commit b82db0e393aa8b4934405cb4f4b6c3a4b584ae5a Author: Rick Dullaart Date: Fri Nov 18 21:38:41 2022 +0100 Initial commit diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md new file mode 100644 index 0000000..dfeec2c --- /dev/null +++ b/CONTRIBUTING.md @@ -0,0 +1,47 @@ +# Contributing to this project + +Please take a moment to review this document in order to make the contribution +process easy and effective for everyone involved. + + +## Using the issue tracker + +The issue tracker is the preferred channel for [bug reports](#bugs) and +[features requests](#features), but please respect the following restrictions: + +* Please **do not** use the issue tracker for personal support requests. + +* Please keep the discussion **on topic** and respect the opinions of others. + + + +## Bug reports + +A bug is a _demonstrable problem_ that is caused by the code in the repository. +Good bug reports are extremely helpful - thank you! + +Guidelines for bug reports: + +1. **Use the GitHub issue search** — check if the issue has already been + reported. + +2. **Check if the issue has been fixed** — try to reproduce it using the + latest branch in the repository. + +3. **Isolate the problem** — create a [reduced test + case](http://css-tricks.com/reduced-test-cases/) and a live example. + +A good bug report shouldn't leave others needing to chase you up for more +information. Please try to be as detailed as possible in your report. What is +your environment? What steps will reproduce the issue? What browser(s) and OS +experience the problem? What would you expect to be the outcome? All these +details will help people to fix any potential bugs. + + + +## Feature requests + +Feature requests are welcome. But take a moment to find out whether your idea +fits with the scope and aims of the project. It's up to *you* to make a strong +case to convince the project's developers of the merits of this feature. Please +provide as much detail and context as possible. \ No newline at end of file diff --git a/LICENSE.txt b/LICENSE.txt new file mode 100644 index 0000000..973ccc8 --- /dev/null +++ b/LICENSE.txt @@ -0,0 +1,2 @@ +This work is licensed under the Creative Commons Attribution-NonCommercial 4.0 International License. +To view a copy of this license, visit http://creativecommons.org/licenses/by-nc/4.0/ or send a letter to Creative Commons, PO Box 1866, Mountain View, CA 94042, USA. \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..c133e15 --- /dev/null +++ b/README.md @@ -0,0 +1,31 @@ +mmenu.js +================ + +The best javascript plugin for app look-alike on- and off-canvas menus with sliding submenus for your website and webapp. It is very customizable through a wide range of options, extensions and add-ons and it will always fit your needs. + +Need help? Have a look at [the documentation](https://mmenujs.com) for demos, tutorials, documentation and support.
+Working on a WordPress site? Check out [the mmenu WordPress plugin](https://mmenujs.com/wordpress-plugin). + +mmenu.js + +### Licence +The mmenu javascript plugin is licensed under the [CC-BY-NC-4.0 license](http://creativecommons.org/licenses/by-nc/4.0/).
+You can [purchase a license](https://mmenujs.com/download.html) if you want to use it in a commercial project. + +### Learn more ++ [Tutorial](https://mmenujs.com/tutorials/off-canvas/) ++ [Options](https://mmenujs.com/documentation/core/options.html) ++ [Extensions](https://mmenujs.com/documentation/extensions/) ++ [Add-ons](https://mmenujs.com/documentation/addons/) ++ [API](https://mmenujs.com/documentation/core/api.html) + +### Browser support +As of version 8, the mmenu.js plugin only supports [ECMAScript 6 compliant browsers](https://kangax.github.io/compat-table/es6/).
+For Internet Explorer 10 and 11, you''ll need [some polyfills](https://polyfill.io/v3/polyfill.min.js?features=default%2CElement.prototype.matches%2CElement.prototype.prepend%2CElement.prototype.closest).
+[Version 7](https://github.com/FrDH/jQuery.mmenu/releases/tag/v7.2.2) should work to some degree in Internet Explorer 9, but you'll need a [matchMedia polyfill](https://polyfill.io/v3/polyfill.min.js?features=default%2CmatchMedia), +[version 6](https://github.com/FrDH/jQuery.mmenu/releases/tag/v6.1.8) should work in Internet Explorer 9 without any shortcomings.

+ +### Development +This project uses [Gulp(4)](http://gulpjs.com/) to compile, minify and concatenate the TS/JS and SCSS/CSS files. +If you are unfamiliar with Gulp, check [this tutorial](https://travismaynard.com/writing/getting-started-with-gulp) on how to get started.
+Run `gulp watch` in the command-line to put a watch on the files and run all scripts immediately after saving your changes. diff --git a/composer.json b/composer.json new file mode 100644 index 0000000..fe762bc --- /dev/null +++ b/composer.json @@ -0,0 +1,27 @@ +{ + "name" : "frdh/mmenu.js", + "version" : "8.5.3", + "authors" : [{ + "name" : "Fred Heusschen", + "email" : "info@frebsite.nl", + "homepage" : "http://www.frebsite.nl", + "role" : "King :)" + }], + "license" : "CC-BY-NC-4.0", + "description" : "The best javascript plugin for app look-alike on- and off-canvas menus with sliding submenus for your website and webapp.", + "keywords" : [ + "app", + "list", + "listview", + "megamenu", + "menu", + "mmenu", + "mobile", + "navigation", + "off-canvas", + "on-canvas", + "curtain", + "panels", + "submenu" + ] +} diff --git a/demo/advanced.html b/demo/advanced.html new file mode 100644 index 0000000..212f6bb --- /dev/null +++ b/demo/advanced.html @@ -0,0 +1,162 @@ + + + + + + + + mmenu.js demo + + + + + + + + +
+
+ + Demo +
+
+

This is an advanced demo.
+ Click the menu icon to open the menu.

+
+ +
+ + + + + + + diff --git a/demo/css/demo.css b/demo/css/demo.css new file mode 100644 index 0000000..7a77e2e --- /dev/null +++ b/demo/css/demo.css @@ -0,0 +1,92 @@ +html, +body { + padding: 0; + margin: 0; +} +body { + background-color: #fff; + font-family: Arial, Helvetica, Verdana; + font-size: 14px; + line-height: 22px; + color: #666; + position: relative; + -webkit-text-size-adjust: none; +} +h1, h2, h3, h4, h5, h6 { + line-height: 1; + font-weight: bold; + margin: 20px 0 10px 0; +} +h1, h2, h3 { + font-size: 18px; +} +h4, h5, h6 { + font-size: 16px; +} +p { + margin: 0 0 10px 0; +} +a, a:link, a:active, a:visited, a:hover { + color: inherit; + text-decoration: underline; +} + +nav:not(.mm-menu) { + display: none; +} + +.header, +.content, +.footer { + text-align: center; +} +.header, +.footer { + background: #4bb5ef; + font-size: 16px; + font-weight: bold; + color: #fff; + line-height: 44px; + + -moz-box-sizing: border-box; + box-sizing: border-box; + width: 100%; + height: 44px; + padding: 0 50px; +} +.header.fixed { + position: fixed; + top: 0; + left: 0; +} +.footer.fixed { + position: fixed; + bottom: 0; + left: 0; +} +.header a { + display: block; + width: 28px; + height: 18px; + padding: 11px; + margin: 2px; + position: absolute; + top: 0; + left: 0; +} +.header a:before, +.header a:after { + content: ''; + display: block; + background: #fff; + height: 2px; +} +.header a span { + background: #fff; + display: block; + height: 2px; + margin: 6px 0; +} +.content { + padding: 150px 50px 50px 50px; +} diff --git a/demo/css/site.css b/demo/css/site.css new file mode 100644 index 0000000..3f34b11 --- /dev/null +++ b/demo/css/site.css @@ -0,0 +1,75 @@ +html, +body { + padding: 0; + margin: 0; + height: 100%; +} +body { + background-color: #3ea7e1; + -webkit-text-size-adjust: none; + font-family: Arial, Helvetica, Verdana; + font-size: 18px; + line-height: 26px; + color: #fff; + position: relative; +} +h1 { + text-shadow: 8px 10px 1px rgba(0,0,0,.1); + text-transform: lowercase; + font-family: 'Pacifico', Arial, sans-serif; + font-weight: normal; + font-size: 150px; + line-height: 150px; + letter-spacing: -10px; + margin: 0 0 20px 0; +} +a, +a:hover +{ + color: #fff; + text-decoration: underline; +} + +.phone { + position: fixed; + top: 50%; + right: 50%; + height: 760px; + width: 430px; + margin-top: -380px; + background: url( ../img/iphonex-example-blue.png ) center top / 395px auto no-repeat transparent; +} + +.phone:before { + content: ''; + border-radius: 30px 30px 0 0; + background: url( ../img/iphonex-example-camera.png ) center top no-repeat #4bb5ef; + display: block; + width: 290px; + height: 25px; + position: absolute; + top: 62px; + left: calc( 50% - 290px / 2); + z-index: 1; +} + +.phone iframe { + position: absolute; + top: 87px; + left: 70px; + z-index: 0; + width: 290px; + height: 600px; + border: none; + border-radius: 0 0 30px 30px; +} + +#page { + width: 350px; + position: fixed; + margin-top: -20px; + margin-left: 0; + top: 50%; + left: 50%; + transform: translateY(-50%); +} diff --git a/demo/default.html b/demo/default.html new file mode 100644 index 0000000..a67796a --- /dev/null +++ b/demo/default.html @@ -0,0 +1,64 @@ + + + + + + + + mmenu.js demo + + + + + + +
+
+ + Demo +
+
+

This is a demo.
+ Click the menu icon to open the menu.

+
+ +
+ + + + + + + diff --git a/demo/img/iphonex-example-blue.png b/demo/img/iphonex-example-blue.png new file mode 100644 index 0000000..0260b7e Binary files /dev/null and b/demo/img/iphonex-example-blue.png differ diff --git a/demo/img/iphonex-example-camera.png b/demo/img/iphonex-example-camera.png new file mode 100644 index 0000000..fa6e40f Binary files /dev/null and b/demo/img/iphonex-example-camera.png differ diff --git a/demo/onepage.html b/demo/onepage.html new file mode 100644 index 0000000..3a07171 --- /dev/null +++ b/demo/onepage.html @@ -0,0 +1,128 @@ + + + + + + + + mmenu.js demo + + + + + + + + + + + +
+
+ + Demo +
+
+
+

This is a demo
+ Click the menu icon to open the menu.

+

Some of the links in the menu link to a section on this page.

+
+
+

Widescreen extension
+ On wider screens, the menu will always be opened.

+

Open the menu.

+
+
+

Drag add-on
+ You can also drag the page to the right to open the menu.

+

Open the menu.

+
+
+

Fixed elements
+ Notice how the fixed header and footer slide out along with the page.

+

Open the menu.

+
+
+ + +
+ + + + + + + + + + + diff --git a/dist/_modules/dom.js b/dist/_modules/dom.js new file mode 100644 index 0000000..6073f28 --- /dev/null +++ b/dist/_modules/dom.js @@ -0,0 +1,132 @@ +/** + * Create an element with classname. + * + * @param {string} selector The nodeName and classnames for the element to create. + * @return {HTMLElement} The created element. + */ +export function create(selector) { + var args = selector.split('.'); + var elem = document.createElement(args.shift()); + // IE11: + args.forEach(function (classname) { + elem.classList.add(classname); + }); + // Better browsers: + // elem.classList.add(...args); + return elem; +} +/** + * Find all elements matching the selector. + * Basically the same as element.querySelectorAll() but it returns an actuall array. + * + * @param {HTMLElement} element Element to search in. + * @param {string} filter The filter to match. + * @return {array} Array of elements that match the filter. + */ +export function find(element, filter) { + return Array.prototype.slice.call(element.querySelectorAll(filter)); +} +/** + * Find all child elements matching the (optional) selector. + * + * @param {HTMLElement} element Element to search in. + * @param {string} filter The filter to match. + * @return {array} Array of child elements that match the filter. + */ +export function children(element, filter) { + var children = Array.prototype.slice.call(element.children); + return filter ? children.filter(function (child) { return child.matches(filter); }) : children; +} +/** + * Find text excluding text from within child elements. + * @param {HTMLElement} element Element to search in. + * @return {string} The text. + */ +export function text(element) { + return Array.prototype.slice + .call(element.childNodes) + .filter(function (child) { return child.nodeType == 3; }) + .map(function (child) { return child.textContent; }) + .join(' '); +} +/** + * Find all preceding elements matching the selector. + * + * @param {HTMLElement} element Element to start searching from. + * @param {string} filter The filter to match. + * @return {array} Array of preceding elements that match the selector. + */ +export function parents(element, filter) { + /** Array of preceding elements that match the selector. */ + var parents = []; + /** Array of preceding elements that match the selector. */ + var parent = element.parentElement; + while (parent) { + parents.push(parent); + parent = parent.parentElement; + } + return filter ? parents.filter(function (parent) { return parent.matches(filter); }) : parents; +} +/** + * Find all previous siblings matching the selecotr. + * + * @param {HTMLElement} element Element to start searching from. + * @param {string} filter The filter to match. + * @return {array} Array of previous siblings that match the selector. + */ +export function prevAll(element, filter) { + /** Array of previous siblings that match the selector. */ + var previous = []; + /** Current element in the loop */ + var current = element.previousElementSibling; + while (current) { + if (!filter || current.matches(filter)) { + previous.push(current); + } + current = current.previousElementSibling; + } + return previous; +} +/** + * Get an element offset relative to the document. + * + * @param {HTMLElement} element Element to start measuring from. + * @param {string} [direction=top] Offset top or left. + * @return {number} The element offset relative to the document. + */ +export function offset(element, direction) { + return (element.getBoundingClientRect()[direction] + + document.body[direction === 'left' ? 'scrollLeft' : 'scrollTop']); +} +/** + * Filter out non-listitem listitems. + * @param {array} listitems Elements to filter. + * @return {array} The filtered set of listitems. + */ +export function filterLI(listitems) { + return listitems.filter(function (listitem) { return !listitem.matches('.mm-hidden'); }); +} +/** + * Find anchors in listitems (excluding anchor that open a sub-panel). + * @param {array} listitems Elements to filter. + * @return {array} The found set of anchors. + */ +export function filterLIA(listitems) { + var anchors = []; + filterLI(listitems).forEach(function (listitem) { + anchors.push.apply(anchors, children(listitem, 'a.mm-listitem__text')); + }); + return anchors.filter(function (anchor) { return !anchor.matches('.mm-btn_next'); }); +} +/** + * Refactor a classname on multiple elements. + * @param {HTMLElement} element Element to refactor. + * @param {string} oldClass Classname to remove. + * @param {string} newClass Classname to add. + */ +export function reClass(element, oldClass, newClass) { + if (element.matches('.' + oldClass)) { + element.classList.remove(oldClass); + element.classList.add(newClass); + } +} diff --git a/dist/_modules/dragevents/_defaults.js b/dist/_modules/dragevents/_defaults.js new file mode 100644 index 0000000..2a6a8f1 --- /dev/null +++ b/dist/_modules/dragevents/_defaults.js @@ -0,0 +1,12 @@ +/** How far from the sides the gesture can start. */ +export var area = { + top: 0, + right: 0, + bottom: 0, + left: 0 +}; +/** Tresholds for gestures. */ +export var treshold = { + start: 15, + swipe: 15 +}; diff --git a/dist/_modules/dragevents/_helpers.js b/dist/_modules/dragevents/_helpers.js new file mode 100644 index 0000000..7405cf5 --- /dev/null +++ b/dist/_modules/dragevents/_helpers.js @@ -0,0 +1,15 @@ +/** + * Calculate a distance from a percentage. + * @param {string|number} position The percentage (e.g. "75%"). + * @param {number} size The available width or height in pixels. + * @return {number} The calculated distance. + */ +export var percentage2number = function (position, size) { + if (typeof position == 'string') { + if (position.slice(-1) == '%') { + position = parseInt(position.slice(0, -1), 10); + position = size * (position / 100); + } + } + return position; +}; diff --git a/dist/_modules/dragevents/_settings.js b/dist/_modules/dragevents/_settings.js new file mode 100644 index 0000000..6468c9a --- /dev/null +++ b/dist/_modules/dragevents/_settings.js @@ -0,0 +1,11 @@ +/** Names of the possible directions. */ +export var directionNames = { + x: ['Right', 'Left'], + y: ['Down', 'Up'] +}; +/** States for the gesture. */ +export var state = { + inactive: 0, + watching: 1, + dragging: 2 +}; diff --git a/dist/_modules/dragevents/_support.js b/dist/_modules/dragevents/_support.js new file mode 100644 index 0000000..5aaa886 --- /dev/null +++ b/dist/_modules/dragevents/_support.js @@ -0,0 +1,4 @@ +/** Whether or not touch gestures are supported by the browser. */ +export var touch = 'ontouchstart' in window || + (navigator.msMaxTouchPoints ? true : false) || + false; diff --git a/dist/_modules/dragevents/index.js b/dist/_modules/dragevents/index.js new file mode 100644 index 0000000..1f1146e --- /dev/null +++ b/dist/_modules/dragevents/index.js @@ -0,0 +1,208 @@ +import * as support from './_support'; +import * as options from './_defaults'; +import * as settings from './_settings'; +import { percentage2number } from './_helpers'; +import { extend } from '../helpers'; +var DragEvents = /** @class */ (function () { + /** + * Create the gestures. + * @param {HTMLElement} surface The surface for the gesture. + * @param {object} area Restriction where on the surface the gesture can be started. + * @param {object} treshold Treshold for the gestures. + */ + function DragEvents(surface, area, treshold) { + this.surface = surface; + this.area = extend(area, options.area); + this.treshold = extend(treshold, options.treshold); + // Set the mouse/touch events. + if (!this.surface['mmHasDragEvents']) { + this.surface.addEventListener(support.touch ? 'touchstart' : 'mousedown', this.start.bind(this)); + this.surface.addEventListener(support.touch ? 'touchend' : 'mouseup', this.stop.bind(this)); + this.surface.addEventListener(support.touch ? 'touchleave' : 'mouseleave', this.stop.bind(this)); + this.surface.addEventListener(support.touch ? 'touchmove' : 'mousemove', this.move.bind(this)); + } + this.surface['mmHasDragEvents'] = true; + } + /** + * Starting the touch gesture. + * @param {Event} event The touch event. + */ + DragEvents.prototype.start = function (event) { + this.currentPosition = { + x: event.touches ? event.touches[0].pageX : event.pageX || 0, + y: event.touches ? event.touches[0].pageY : event.pageY || 0 + }; + /** The widht of the surface. */ + var width = this.surface.clientWidth; + /** The height of the surface. */ + var height = this.surface.clientHeight; + // Check if the gesture started below the area.top. + var top = percentage2number(this.area.top, height); + if (typeof top == 'number') { + if (this.currentPosition.y < top) { + return; + } + } + // Check if the gesture started before the area.right. + var right = percentage2number(this.area.right, width); + if (typeof right == 'number') { + right = width - right; + if (this.currentPosition.x > right) { + return; + } + } + // Check if the gesture started above the area.bottom. + var bottom = percentage2number(this.area.bottom, height); + if (typeof bottom == 'number') { + bottom = height - bottom; + if (this.currentPosition.y > bottom) { + return; + } + } + // Check if the gesture started after the area.left. + var left = percentage2number(this.area.left, width); + if (typeof left == 'number') { + if (this.currentPosition.x < left) { + return; + } + } + // Store the start x- and y-position. + this.startPosition = { + x: this.currentPosition.x, + y: this.currentPosition.y + }; + // Set the state of the gesture to "watching". + this.state = settings.state.watching; + }; + /** + * Stopping the touch gesture. + * @param {Event} event The touch event. + */ + DragEvents.prototype.stop = function (event) { + // Dispatch the "dragEnd" events. + if (this.state == settings.state.dragging) { + /** The direction. */ + var dragDirection = this._dragDirection(); + /** The event information. */ + var detail = this._eventDetail(dragDirection); + this._dispatchEvents('drag*End', detail); + // Dispatch the "swipe" events. + if (Math.abs(this.movement[this.axis]) > this.treshold.swipe) { + /** The direction. */ + var swipeDirection = this._swipeDirection(); + detail.direction = swipeDirection; + this._dispatchEvents('swipe*', detail); + } + } + // Set the state of the gesture to "inactive". + this.state = settings.state.inactive; + }; + /** + * Doing the touch gesture. + * @param {Event} event The touch event. + */ + DragEvents.prototype.move = function (event) { + switch (this.state) { + case settings.state.watching: + case settings.state.dragging: + var position = { + x: event.changedTouches + ? event.touches[0].pageX + : event.pageX || 0, + y: event.changedTouches + ? event.touches[0].pageY + : event.pageY || 0 + }; + this.movement = { + x: position.x - this.currentPosition.x, + y: position.y - this.currentPosition.y + }; + this.distance = { + x: position.x - this.startPosition.x, + y: position.y - this.startPosition.y + }; + this.currentPosition = { + x: position.x, + y: position.y + }; + this.axis = + Math.abs(this.distance.x) > Math.abs(this.distance.y) + ? 'x' + : 'y'; + /** The direction. */ + var dragDirection = this._dragDirection(); + /** The event information. */ + var detail = this._eventDetail(dragDirection); + // Watching for the gesture to go past the treshold. + if (this.state == settings.state.watching) { + if (Math.abs(this.distance[this.axis]) > this.treshold.start) { + this._dispatchEvents('drag*Start', detail); + // Set the state of the gesture to "inactive". + this.state = settings.state.dragging; + } + } + // Dispatch the "drag" events. + if (this.state == settings.state.dragging) { + this._dispatchEvents('drag*Move', detail); + } + break; + } + }; + /** + * Get the event details. + * @param {string} direction Direction for the event (up, right, down, left). + * @return {object} The event details. + */ + DragEvents.prototype._eventDetail = function (direction) { + var distX = this.distance.x; + var distY = this.distance.y; + if (this.axis == 'x') { + distX -= distX > 0 ? this.treshold.start : 0 - this.treshold.start; + } + if (this.axis == 'y') { + distY -= distY > 0 ? this.treshold.start : 0 - this.treshold.start; + } + return { + axis: this.axis, + direction: direction, + movementX: this.movement.x, + movementY: this.movement.y, + distanceX: distX, + distanceY: distY + }; + }; + /** + * Dispatch the events + * @param {string} eventName The name for the events to dispatch. + * @param {object} detail The event details. + */ + DragEvents.prototype._dispatchEvents = function (eventName, detail) { + /** General event, e.g. "drag" */ + var event = new CustomEvent(eventName.replace('*', ''), { detail: detail }); + this.surface.dispatchEvent(event); + /** Axis event, e.g. "dragX" */ + var axis = new CustomEvent(eventName.replace('*', this.axis.toUpperCase()), { detail: detail }); + this.surface.dispatchEvent(axis); + /** Direction event, e.g. "dragLeft" */ + var direction = new CustomEvent(eventName.replace('*', detail.direction), { + detail: detail + }); + this.surface.dispatchEvent(direction); + }; + /** + * Get the dragging direction. + * @return {string} The direction in which the user is dragging. + */ + DragEvents.prototype._dragDirection = function () { + return settings.directionNames[this.axis][this.distance[this.axis] > 0 ? 0 : 1]; + }; + /** + * Get the dragging direction. + * @return {string} The direction in which the user is dragging. + */ + DragEvents.prototype._swipeDirection = function () { + return settings.directionNames[this.axis][this.movement[this.axis] > 0 ? 0 : 1]; + }; + return DragEvents; +}()); +export default DragEvents; diff --git a/dist/_modules/eventlisteners.js b/dist/_modules/eventlisteners.js new file mode 100644 index 0000000..7a0d786 --- /dev/null +++ b/dist/_modules/eventlisteners.js @@ -0,0 +1,50 @@ +/** + * Make the first letter in a word uppercase. + * @param {string} word The word. + */ +function ucFirst(word) { + if (!word) { + return ''; + } + return word.charAt(0).toUpperCase() + word.slice(1); +} +/** + * Bind an event listener to an element. + * @param {HTMLElement} element The element to bind the event listener to. + * @param {string} evnt The event to listen to. + * @param {funcion} handler The function to invoke. + */ +export function on(element, evnt, handler) { + // Extract the event name and space from the event (the event can include a namespace (click.foo)). + var evntParts = evnt.split('.'); + evnt = 'mmEvent' + ucFirst(evntParts[0]) + ucFirst(evntParts[1]); + element[evnt] = element[evnt] || []; + element[evnt].push(handler); + element.addEventListener(evntParts[0], handler); +} +/** + * Remove an event listener from an element. + * @param {HTMLElement} element The element to remove the event listeners from. + * @param {string} evnt The event to remove. + */ +export function off(element, evnt) { + // Extract the event name and space from the event (the event can include a namespace (click.foo)). + var evntParts = evnt.split('.'); + evnt = 'mmEvent' + ucFirst(evntParts[0]) + ucFirst(evntParts[1]); + (element[evnt] || []).forEach(function (handler) { + element.removeEventListener(evntParts[0], handler); + }); +} +/** + * Trigger the bound event listeners on an element. + * @param {HTMLElement} element The element of which to trigger the event listeners from. + * @param {string} evnt The event to trigger. + * @param {object} [options] Options to pass to the handler. + */ +export function trigger(element, evnt, options) { + var evntParts = evnt.split('.'); + evnt = 'mmEvent' + ucFirst(evntParts[0]) + ucFirst(evntParts[1]); + (element[evnt] || []).forEach(function (handler) { + handler(options || {}); + }); +} diff --git a/dist/_modules/helpers.js b/dist/_modules/helpers.js new file mode 100644 index 0000000..4729981 --- /dev/null +++ b/dist/_modules/helpers.js @@ -0,0 +1,125 @@ +/** + * Deep extend an object with the given defaults. + * Note that the extended object is not a clone, meaning the original object will also be updated. + * + * @param {object} orignl The object to extend to. + * @param {object} dfault The object to extend from. + * @return {object} The extended "orignl" object. + */ +export function extend(orignl, dfault) { + if (type(orignl) != 'object') { + orignl = {}; + } + if (type(dfault) != 'object') { + dfault = {}; + } + for (var k in dfault) { + if (!dfault.hasOwnProperty(k)) { + continue; + } + if (typeof orignl[k] == 'undefined') { + orignl[k] = dfault[k]; + } + else if (type(orignl[k]) == 'object') { + extend(orignl[k], dfault[k]); + } + } + return orignl; +} +/** + * Detect the touch / dragging direction on a touch device. + * + * @param {HTMLElement} surface The element to monitor for touch events. + * @return {object} Object with "get" function. + */ +export function touchDirection(surface) { + var direction = ''; + surface.addEventListener('touchmove', function (evnt) { + direction = ''; + if (evnt.movementY > 0) { + direction = 'down'; + } + else if (evnt.movementY < 0) { + direction = 'up'; + } + }); + return { + get: function () { return direction; } + }; +} +/** + * Get the type of any given variable. Improvement of "typeof". + * + * @param {any} variable The variable. + * @return {string} The type of the variable in lowercase. + */ +export function type(variable) { + return {}.toString + .call(variable) + .match(/\s([a-zA-Z]+)/)[1] + .toLowerCase(); +} +/** + * Find the value from an option or function. + * @param {HTMLElement} element Scope for the function. + * @param {any} [option] Value or function. + * @param {any} [dfault] Default fallback value. + * @return {any} The given evaluation of the given option, or the default fallback value. + */ +export function valueOrFn(element, option, dfault) { + if (typeof option == 'function') { + var value = option.call(element); + if (typeof value != 'undefined') { + return value; + } + } + if ((option === null || + typeof option == 'function' || + typeof option == 'undefined') && + typeof dfault != 'undefined') { + return dfault; + } + return option; +} +/** + * Set and invoke a (single) transition-end function with fallback. + * + * @param {HTMLElement} element Scope for the function. + * @param {function} func Function to invoke. + * @param {number} duration The duration of the animation (for the fallback). + */ +export function transitionend(element, func, duration) { + var _ended = false, _fn = function (evnt) { + if (typeof evnt !== 'undefined') { + if (evnt.target !== element) { + return; + } + } + if (!_ended) { + element.removeEventListener('transitionend', _fn); + element.removeEventListener('webkitTransitionEnd', _fn); + func.call(element); + } + _ended = true; + }; + element.addEventListener('transitionend', _fn); + element.addEventListener('webkitTransitionEnd', _fn); + setTimeout(_fn, duration * 1.1); +} +/** + * Get a (page wide) unique ID. + */ +export function uniqueId() { + return 'mm-' + __id++; +} +var __id = 0; +/** + * Get the original ID from a possibly prefixed ID. + * @param id The possibly prefixed ID. + */ +export function originalId(id) { + if (id.slice(0, 3) == 'mm-') { + return id.slice(3); + } + return id; +} diff --git a/dist/_modules/i18n.js b/dist/_modules/i18n.js new file mode 100644 index 0000000..0890d69 --- /dev/null +++ b/dist/_modules/i18n.js @@ -0,0 +1,34 @@ +import { extend } from './helpers'; +var translations = {}; +/** + * Add translations to a language. + * @param {object} text Object of key/value translations. + * @param {string} language The translated language. + */ +export function add(text, language) { + if (typeof translations[language] == 'undefined') { + translations[language] = {}; + } + extend(translations[language], text); +} +/** + * Find a translated text in a language. + * @param {string} text The text to find the translation for. + * @param {string} language The language to search in. + * @return {string} The translated text. + */ +export function get(text, language) { + if (typeof language == 'string' && + typeof translations[language] != 'undefined') { + return translations[language][text] || text; + } + return text; +} +/** + * Get all translated text in a language. + * @param {string} language The language to search for. + * @return {object} The translations. + */ +export function all(language) { + return translations; +} diff --git a/dist/_modules/matchmedia.js b/dist/_modules/matchmedia.js new file mode 100644 index 0000000..8cf6255 --- /dev/null +++ b/dist/_modules/matchmedia.js @@ -0,0 +1,43 @@ +/** Collection of callback functions for media querys. */ +var listeners = {}; +/** + * Bind functions to a matchMedia listener (subscriber). + * + * @param {string|number} query Media query to match or number for min-width. + * @param {function} yes Function to invoke when the media query matches. + * @param {function} no Function to invoke when the media query doesn't match. + */ +export function add(query, yes, no) { + if (typeof query == 'number') { + query = '(min-width: ' + query + 'px)'; + } + listeners[query] = listeners[query] || []; + listeners[query].push({ yes: yes, no: no }); +} +/** + * Initialize the matchMedia listener. + */ +export function watch() { + var _loop_1 = function (query) { + var mqlist = window.matchMedia(query); + fire(query, mqlist); + mqlist.onchange = function (evnt) { + fire(query, mqlist); + }; + }; + for (var query in listeners) { + _loop_1(query); + } +} +/** + * Invoke the "yes" or "no" function for a matchMedia listener (publisher). + * + * @param {string} query Media query to check for. + * @param {MediaQueryList} mqlist Media query list to check with. + */ +export function fire(query, mqlist) { + var fn = mqlist.matches ? 'yes' : 'no'; + for (var m = 0; m < listeners[query].length; m++) { + listeners[query][m][fn](); + } +} diff --git a/dist/_modules/support.js b/dist/_modules/support.js new file mode 100644 index 0000000..5aaa886 --- /dev/null +++ b/dist/_modules/support.js @@ -0,0 +1,4 @@ +/** Whether or not touch gestures are supported by the browser. */ +export var touch = 'ontouchstart' in window || + (navigator.msMaxTouchPoints ? true : false) || + false; diff --git a/dist/_version.js b/dist/_version.js new file mode 100644 index 0000000..8f294ea --- /dev/null +++ b/dist/_version.js @@ -0,0 +1 @@ +export default '8.5.3'; diff --git a/dist/addons/autoheight/_options.js b/dist/addons/autoheight/_options.js new file mode 100644 index 0000000..49bb96b --- /dev/null +++ b/dist/addons/autoheight/_options.js @@ -0,0 +1,27 @@ +var opts = { + height: 'default' +}; +export default opts; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean' && options) { + options = { + height: 'auto' + }; + } + if (typeof options == 'string') { + options = { + height: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/addons/autoheight/mmenu.autoheight.css b/dist/addons/autoheight/mmenu.autoheight.css new file mode 100644 index 0000000..cead9c5 --- /dev/null +++ b/dist/addons/autoheight/mmenu.autoheight.css @@ -0,0 +1 @@ +.mm-menu_autoheight:not(.mm-menu_offcanvas){position:relative}.mm-menu_autoheight.mm-menu_position-bottom,.mm-menu_autoheight.mm-menu_position-top{max-height:80%}.mm-menu_autoheight-measuring .mm-panel{display:block!important}.mm-menu_autoheight-measuring .mm-panels>.mm-panel{bottom:auto!important;height:auto!important}.mm-menu_autoheight-measuring .mm-listitem_vertical:not(.mm-listitem_opened) .mm-panel{display:none!important} \ No newline at end of file diff --git a/dist/addons/autoheight/mmenu.autoheight.js b/dist/addons/autoheight/mmenu.autoheight.js new file mode 100644 index 0000000..09b2a9d --- /dev/null +++ b/dist/addons/autoheight/mmenu.autoheight.js @@ -0,0 +1,84 @@ +import Mmenu from './../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.autoHeight = options; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.autoHeight); + this.opts.autoHeight = extend(options, Mmenu.options.autoHeight); + if (options.height != 'auto' && options.height != 'highest') { + return; + } + var setHeight = (function () { + var getCurrent = function () { + var panel = DOM.children(_this.node.pnls, '.mm-panel_opened')[0]; + if (panel) { + panel = measurablePanel(panel); + } + // Fallback, just to be sure we have a panel. + if (!panel) { + panel = DOM.children(_this.node.pnls, '.mm-panel')[0]; + } + return panel.scrollHeight; + }; + var getHighest = function () { + var highest = 0; + DOM.children(_this.node.pnls, '.mm-panel').forEach(function (panel) { + panel = measurablePanel(panel); + highest = Math.max(highest, panel.scrollHeight); + }); + return highest; + }; + var measurablePanel = function (panel) { + // If it's a vertically expanding panel... + if (panel.parentElement.matches('.mm-listitem_vertical')) { + // ...find the first parent panel that isn't. + panel = DOM.parents(panel, '.mm-panel').filter(function (panel) { + return !panel.parentElement.matches('.mm-listitem_vertical'); + })[0]; + } + return panel; + }; + return function () { + if (_this.opts.offCanvas && !_this.vars.opened) { + return; + } + var _hgh = 0; + var _dif = _this.node.menu.offsetHeight - _this.node.pnls.offsetHeight; + // The "measuring" classname undoes some CSS to be able to measure the height. + _this.node.menu.classList.add('mm-menu_autoheight-measuring'); + // Measure the height. + if (options.height == 'auto') { + _hgh = getCurrent(); + } + else if (options.height == 'highest') { + _hgh = getHighest(); + } + // Set the height. + _this.node.menu.style.height = _hgh + _dif + 'px'; + // Remove the "measuring" classname. + _this.node.menu.classList.remove('mm-menu_autoheight-measuring'); + }; + })(); + // Add the autoheight class to the menu. + this.bind('initMenu:after', function () { + _this.node.menu.classList.add('mm-menu_autoheight'); + }); + if (this.opts.offCanvas) { + // Measure the height when opening the off-canvas menu. + this.bind('open:start', setHeight); + } + if (options.height == 'highest') { + // Measure the height when initiating panels. + this.bind('initPanels:after', setHeight); + } + if (options.height == 'auto') { + // Measure the height when updating listviews. + this.bind('updateListview', setHeight); + // Measure the height when opening a panel. + this.bind('openPanel:start', setHeight); + } +} diff --git a/dist/addons/backbutton/_options.js b/dist/addons/backbutton/_options.js new file mode 100644 index 0000000..d8e286a --- /dev/null +++ b/dist/addons/backbutton/_options.js @@ -0,0 +1,23 @@ +var options = { + close: false, + open: false +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + close: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/addons/backbutton/mmenu.backbutton.js b/dist/addons/backbutton/mmenu.backbutton.js new file mode 100644 index 0000000..fe98dc2 --- /dev/null +++ b/dist/addons/backbutton/mmenu.backbutton.js @@ -0,0 +1,58 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.backButton = options; +export default function () { + var _this = this; + if (!this.opts.offCanvas) { + return; + } + var options = extendShorthandOptions(this.opts.backButton); + this.opts.backButton = extend(options, Mmenu.options.backButton); + var _menu = '#' + this.node.menu.id; + // Close menu + if (options.close) { + var states = []; + var setStates = function () { + states = [_menu]; + DOM.children(_this.node.pnls, '.mm-panel_opened, .mm-panel_opened-parent').forEach(function (panel) { + states.push('#' + panel.id); + }); + }; + this.bind('open:finish', function () { + history.pushState(null, document.title, _menu); + }); + this.bind('open:finish', setStates); + this.bind('openPanel:finish', setStates); + this.bind('close:finish', function () { + states = []; + history.back(); + history.pushState(null, document.title, location.pathname + location.search); + }); + window.addEventListener('popstate', function (evnt) { + if (_this.vars.opened) { + if (states.length) { + states = states.slice(0, -1); + var hash = states[states.length - 1]; + if (hash == _menu) { + _this.close(); + } + else { + _this.openPanel(_this.node.menu.querySelector(hash)); + history.pushState(null, document.title, _menu); + } + } + } + }); + } + if (options.open) { + window.addEventListener('popstate', function (evnt) { + if (!_this.vars.opened && location.hash == _menu) { + _this.open(); + } + }); + } +} diff --git a/dist/addons/columns/_options.js b/dist/addons/columns/_options.js new file mode 100644 index 0000000..747ea2e --- /dev/null +++ b/dist/addons/columns/_options.js @@ -0,0 +1,38 @@ +var options = { + add: false, + visible: { + min: 1, + max: 3 + } +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + add: options + }; + } + if (typeof options == 'number') { + options = { + add: true, + visible: options + }; + } + if (typeof options != 'object') { + options = {}; + } + if (typeof options.visible == 'number') { + options.visible = { + min: options.visible, + max: options.visible + }; + } + return options; +} +; diff --git a/dist/addons/columns/mmenu.columns.css b/dist/addons/columns/mmenu.columns.css new file mode 100644 index 0000000..1eb1184 --- /dev/null +++ b/dist/addons/columns/mmenu.columns.css @@ -0,0 +1 @@ +[class*=mm-menu_columns-]{-webkit-transition-property:width;-o-transition-property:width;transition-property:width}[class*=mm-menu_columns-] .mm-panels>.mm-panel{right:auto;-webkit-transition-property:width,-webkit-transform;transition-property:width,-webkit-transform;-o-transition-property:width,transform;transition-property:width,transform;transition-property:width,transform,-webkit-transform}[class*=mm-menu_columns-] .mm-panels>.mm-panel_opened,[class*=mm-menu_columns-] .mm-panels>.mm-panel_opened-parent{display:block!important}[class*=mm-panel_columns-]{border-right:1px solid;border-color:inherit}.mm-menu_columns-1 .mm-panel_columns-0,.mm-menu_columns-2 .mm-panel_columns-1,.mm-menu_columns-3 .mm-panel_columns-2,.mm-menu_columns-4 .mm-panel_columns-3{border-right:none}[class*=mm-menu_columns-] .mm-panels>.mm-panel_columns-0{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-menu_columns-0 .mm-panels>.mm-panel{z-index:0}.mm-menu_columns-0 .mm-panels>.mm-panel else{width:100%}.mm-menu_columns-0 .mm-panels>.mm-panel:not(.mm-panel_opened):not(.mm-panel_opened-parent){-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.mm-menu_columns-0{width:80%;min-width:240px;max-width:0}.mm-wrapper_opening .mm-menu_columns-0~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-0~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:0px){.mm-wrapper_opening .mm-menu_columns-0~.mm-slideout{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.mm-wrapper_opening .mm-menu_columns-0.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-0.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:0px){.mm-wrapper_opening .mm-menu_columns-0.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}[class*=mm-menu_columns-] .mm-panels>.mm-panel_columns-1{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.mm-menu_columns-1 .mm-panels>.mm-panel{z-index:1;width:100%}.mm-menu_columns-1 .mm-panels>.mm-panel else{width:100%}.mm-menu_columns-1 .mm-panels>.mm-panel:not(.mm-panel_opened):not(.mm-panel_opened-parent){-webkit-transform:translate3d(200%,0,0);transform:translate3d(200%,0,0)}.mm-menu_columns-1{width:80%;min-width:240px;max-width:440px}.mm-wrapper_opening .mm-menu_columns-1~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-1~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:550px){.mm-wrapper_opening .mm-menu_columns-1~.mm-slideout{-webkit-transform:translate3d(440px,0,0);transform:translate3d(440px,0,0)}}.mm-wrapper_opening .mm-menu_columns-1.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-1.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:550px){.mm-wrapper_opening .mm-menu_columns-1.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-440px,0,0);transform:translate3d(-440px,0,0)}}[class*=mm-menu_columns-] .mm-panels>.mm-panel_columns-2{-webkit-transform:translate3d(200%,0,0);transform:translate3d(200%,0,0)}.mm-menu_columns-2 .mm-panels>.mm-panel{z-index:2;width:50%}.mm-menu_columns-2 .mm-panels>.mm-panel else{width:100%}.mm-menu_columns-2 .mm-panels>.mm-panel:not(.mm-panel_opened):not(.mm-panel_opened-parent){-webkit-transform:translate3d(300%,0,0);transform:translate3d(300%,0,0)}.mm-menu_columns-2{width:80%;min-width:240px;max-width:880px}.mm-wrapper_opening .mm-menu_columns-2~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-2~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:1100px){.mm-wrapper_opening .mm-menu_columns-2~.mm-slideout{-webkit-transform:translate3d(880px,0,0);transform:translate3d(880px,0,0)}}.mm-wrapper_opening .mm-menu_columns-2.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-2.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:1100px){.mm-wrapper_opening .mm-menu_columns-2.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-880px,0,0);transform:translate3d(-880px,0,0)}}[class*=mm-menu_columns-] .mm-panels>.mm-panel_columns-3{-webkit-transform:translate3d(300%,0,0);transform:translate3d(300%,0,0)}.mm-menu_columns-3 .mm-panels>.mm-panel{z-index:3;width:33.34%}.mm-menu_columns-3 .mm-panels>.mm-panel else{width:100%}.mm-menu_columns-3 .mm-panels>.mm-panel:not(.mm-panel_opened):not(.mm-panel_opened-parent){-webkit-transform:translate3d(400%,0,0);transform:translate3d(400%,0,0)}.mm-menu_columns-3{width:80%;min-width:240px;max-width:1320px}.mm-wrapper_opening .mm-menu_columns-3~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-3~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:1650px){.mm-wrapper_opening .mm-menu_columns-3~.mm-slideout{-webkit-transform:translate3d(1320px,0,0);transform:translate3d(1320px,0,0)}}.mm-wrapper_opening .mm-menu_columns-3.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-3.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:1650px){.mm-wrapper_opening .mm-menu_columns-3.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-1320px,0,0);transform:translate3d(-1320px,0,0)}}[class*=mm-menu_columns-] .mm-panels>.mm-panel_columns-4{-webkit-transform:translate3d(400%,0,0);transform:translate3d(400%,0,0)}.mm-menu_columns-4 .mm-panels>.mm-panel{z-index:4;width:25%}.mm-menu_columns-4 .mm-panels>.mm-panel else{width:100%}.mm-menu_columns-4 .mm-panels>.mm-panel:not(.mm-panel_opened):not(.mm-panel_opened-parent){-webkit-transform:translate3d(500%,0,0);transform:translate3d(500%,0,0)}.mm-menu_columns-4{width:80%;min-width:240px;max-width:1760px}.mm-wrapper_opening .mm-menu_columns-4~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-4~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:2200px){.mm-wrapper_opening .mm-menu_columns-4~.mm-slideout{-webkit-transform:translate3d(1760px,0,0);transform:translate3d(1760px,0,0)}}.mm-wrapper_opening .mm-menu_columns-4.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-4.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:2200px){.mm-wrapper_opening .mm-menu_columns-4.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-1760px,0,0);transform:translate3d(-1760px,0,0)}}[class*=mm-menu_columns-].mm-menu_position-bottom,[class*=mm-menu_columns-].mm-menu_position-top{width:100%;max-width:100%;min-width:100%}.mm-wrapper_opening [class*=mm-menu_columns-].mm-menu_position-front{-webkit-transition-property:width,min-width,max-width,-webkit-transform;transition-property:width,min-width,max-width,-webkit-transform;-o-transition-property:width,min-width,max-width,transform;transition-property:width,min-width,max-width,transform;transition-property:width,min-width,max-width,transform,-webkit-transform} \ No newline at end of file diff --git a/dist/addons/columns/mmenu.columns.js b/dist/addons/columns/mmenu.columns.js new file mode 100644 index 0000000..7cdb3d6 --- /dev/null +++ b/dist/addons/columns/mmenu.columns.js @@ -0,0 +1,103 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.columns = options; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.columns); + this.opts.columns = extend(options, Mmenu.options.columns); + // Add the columns + if (options.add) { + options.visible.min = Math.max(1, Math.min(6, options.visible.min)); + options.visible.max = Math.max(options.visible.min, Math.min(6, options.visible.max)); + /** Columns related clasnames for the menu. */ + var colm = []; + /** Columns related clasnames for the panels. */ + var colp = []; + /** Classnames to remove from panels in favor of showing columns. */ + var rmvc = [ + 'mm-panel_opened', + 'mm-panel_opened-parent', + 'mm-panel_highest' + ]; + for (var i = 0; i <= options.visible.max; i++) { + colm.push('mm-menu_columns-' + i); + colp.push('mm-panel_columns-' + i); + } + rmvc.push.apply(rmvc, colp); + // Close all later opened panels + this.bind('openPanel:before', function (panel) { + /** The parent panel. */ + var parent; + if (panel) { + parent = panel['mmParent']; + } + if (!parent) { + return; + } + parent = parent.closest('.mm-panel'); + if (!parent) { + return; + } + var classname = parent.className; + if (!classname.length) { + return; + } + classname = classname.split('mm-panel_columns-')[1]; + if (!classname) { + return; + } + var colnr = parseInt(classname.split(' ')[0], 10) + 1; + while (colnr > 0) { + panel = DOM.children(_this.node.pnls, '.mm-panel_columns-' + colnr)[0]; + if (panel) { + colnr++; + panel.classList.add('mm-hidden'); + // IE11: + rmvc.forEach(function (classname) { + panel.classList.remove(classname); + }); + // Better browsers: + // panel.classList.remove(...rmvc); + } + else { + colnr = -1; + break; + } + } + }); + this.bind('openPanel:start', function (panel) { + var columns = DOM.children(_this.node.pnls, '.mm-panel_opened-parent').length; + if (!panel.matches('.mm-panel_opened-parent')) { + columns++; + } + columns = Math.min(options.visible.max, Math.max(options.visible.min, columns)); + // IE11: + colm.forEach(function (classname) { + _this.node.menu.classList.remove(classname); + }); + // Better browsers: + // this.node.menu.classList.remove(...colm); + _this.node.menu.classList.add('mm-menu_columns-' + columns); + var panels = []; + DOM.children(_this.node.pnls, '.mm-panel').forEach(function (panel) { + // IE11: + colp.forEach(function (classname) { + panel.classList.remove(classname); + }); + // Better browsers: + // panel.classList.remove(...colp); + if (panel.matches('.mm-panel_opened-parent')) { + panels.push(panel); + } + }); + panels.push(panel); + panels.slice(-options.visible.max).forEach(function (panel, p) { + panel.classList.add('mm-panel_columns-' + p); + }); + }); + } +} diff --git a/dist/addons/counters/_options.js b/dist/addons/counters/_options.js new file mode 100644 index 0000000..74e5f92 --- /dev/null +++ b/dist/addons/counters/_options.js @@ -0,0 +1,28 @@ +var options = { + add: false, + addTo: 'panels', + count: false +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + add: options, + addTo: 'panels', + count: options + }; + } + if (typeof options != 'object') { + options = {}; + } + if (options.addTo == 'panels') { + options.addTo = '.mm-listview'; + } + return options; +} diff --git a/dist/addons/counters/mmenu.counters.css b/dist/addons/counters/mmenu.counters.css new file mode 100644 index 0000000..7c18734 --- /dev/null +++ b/dist/addons/counters/mmenu.counters.css @@ -0,0 +1 @@ +.mm-counter{color:rgba(0,0,0,.3);display:block;padding-left:20px;float:right;text-align:right;color:var(--mm-color-text-dimmed)}.mm-listitem_nosubitems>.mm-counter{display:none}[dir=rtl] .mm-counter{text-align:left;float:left;padding-left:0;padding-right:20px} \ No newline at end of file diff --git a/dist/addons/counters/mmenu.counters.js b/dist/addons/counters/mmenu.counters.js new file mode 100644 index 0000000..b91a1f6 --- /dev/null +++ b/dist/addons/counters/mmenu.counters.js @@ -0,0 +1,65 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.counters = options; +// Add the classnames. +Mmenu.configs.classNames.counters = { + counter: 'Counter' +}; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.counters); + this.opts.counters = extend(options, Mmenu.options.counters); + // Refactor counter class + this.bind('initListview:after', function (listview) { + var cntrclss = _this.conf.classNames.counters.counter, counters = DOM.find(listview, '.' + cntrclss); + counters.forEach(function (counter) { + DOM.reClass(counter, cntrclss, 'mm-counter'); + }); + }); + // Add the counters after a listview is initiated. + if (options.add) { + this.bind('initListview:after', function (listview) { + if (!listview.matches(options.addTo)) { + return; + } + var parent = listview.closest('.mm-panel')['mmParent']; + if (parent) { + // Check if no counter already excists. + if (!DOM.find(parent, '.mm-counter').length) { + var btn = DOM.children(parent, '.mm-btn')[0]; + if (btn) { + btn.prepend(DOM.create('span.mm-counter')); + } + } + } + }); + } + if (options.count) { + var count = function (listview) { + var panels = listview + ? [listview.closest('.mm-panel')] + : DOM.children(_this.node.pnls, '.mm-panel'); + panels.forEach(function (panel) { + var parent = panel['mmParent']; + if (!parent) { + return; + } + var counter = DOM.find(parent, '.mm-counter')[0]; + if (!counter) { + return; + } + var listitems = []; + DOM.children(panel, '.mm-listview').forEach(function (listview) { + listitems.push.apply(listitems, DOM.children(listview)); + }); + counter.innerHTML = DOM.filterLI(listitems).length.toString(); + }); + }; + this.bind('initListview:after', count); + this.bind('updateListview', count); + } +} diff --git a/dist/addons/dividers/_options.js b/dist/addons/dividers/_options.js new file mode 100644 index 0000000..bf3f013 --- /dev/null +++ b/dist/addons/dividers/_options.js @@ -0,0 +1,25 @@ +var options = { + add: false, + addTo: 'panels' +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + add: options + }; + } + if (typeof options != 'object') { + options = {}; + } + if (options.addTo == 'panels') { + options.addTo = '.mm-listview'; + } + return options; +} diff --git a/dist/addons/dividers/mmenu.dividers.css b/dist/addons/dividers/mmenu.dividers.css new file mode 100644 index 0000000..e95bc1d --- /dev/null +++ b/dist/addons/dividers/mmenu.dividers.css @@ -0,0 +1 @@ +.mm-divider{position:relative;min-height:20px;padding:4.3px;background:#f3f3f3;-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;min-height:var(--mm-line-height);padding:calc(((var(--mm-listitem-size) * .65) - var(--mm-line-height)) * .5);padding-right:10px;padding-left:20px;font-size:75%;text-transform:uppercase;background:var(--mm-color-background);opacity:1;-webkit-transition:opacity .4s ease;-o-transition:opacity .4s ease;transition:opacity .4s ease}.mm-divider:before{background:rgba(0,0,0,.05)}@supports ((position:-webkit-sticky) or (position:sticky)){.mm-divider{position:-webkit-sticky;position:sticky;z-index:2;top:0}.mm-navbar_sticky:not(.mm-hidden)~.mm-listview .mm-divider{top:var(--mm-navbar-size)}}.mm-divider:before{content:'';position:absolute;top:0;right:0;bottom:0;left:0;z-index:-1;background:var(--mm-color-background-highlight)} \ No newline at end of file diff --git a/dist/addons/dividers/mmenu.dividers.js b/dist/addons/dividers/mmenu.dividers.js new file mode 100644 index 0000000..220a0ac --- /dev/null +++ b/dist/addons/dividers/mmenu.dividers.js @@ -0,0 +1,46 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.dividers = options; +// Add the classnames. +Mmenu.configs.classNames.divider = 'Divider'; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.dividers); + this.opts.dividers = extend(options, Mmenu.options.dividers); + // Refactor divider classname + this.bind('initListview:after', function (listview) { + DOM.children(listview).forEach(function (listitem) { + DOM.reClass(listitem, _this.conf.classNames.divider, 'mm-divider'); + if (listitem.matches('.mm-divider')) { + listitem.classList.remove('mm-listitem'); + } + }); + }); + // Add dividers + if (options.add) { + this.bind('initListview:after', function (listview) { + if (!listview.matches(options.addTo)) { + return; + } + DOM.find(listview, '.mm-divider').forEach(function (divider) { + divider.remove(); + }); + var lastletter = '', listitems = DOM.children(listview); + DOM.filterLI(listitems).forEach(function (listitem) { + var letter = DOM.children(listitem, '.mm-listitem__text')[0] + .textContent.trim() + .toLowerCase()[0]; + if (letter.length && letter != lastletter) { + lastletter = letter; + var divider = DOM.create('li.mm-divider'); + divider.textContent = letter; + listview.insertBefore(divider, listitem); + } + }); + }); + } +} diff --git a/dist/addons/drag/_drag.open.js b/dist/addons/drag/_drag.open.js new file mode 100644 index 0000000..8b97e0d --- /dev/null +++ b/dist/addons/drag/_drag.open.js @@ -0,0 +1,202 @@ +import DragEvents from '../../_modules/dragevents/index'; +import * as DOM from '../../_modules/dom'; +import * as events from '../../_modules/eventlisteners'; +import * as media from '../../_modules/matchmedia'; +/** Instance of the DragEvents class. */ +var dragInstance = null; +/** THe node that can be dragged. */ +var dragNode = null; +/** How far the page (or menu) can be dragged. */ +var maxDistance = 0; +export default function (page) { + var _this = this; + /** Variables that vary for each menu position (top, right, bottom, left. front, back). */ + var vars = {}; + /** Whether or not the page or menu is actually being moved. */ + var moving = false; + /** + * Add the dragging events. + */ + var addEvents = function () { + if (dragNode) { + // Prepare the page or menu to be moved. + events.on(dragNode, 'dragStart', function (evnt) { + if (evnt['detail'].direction == vars.direction) { + moving = true; + // Class prevents interaction with the page. + _this.node.wrpr.classList.add('mm-wrapper_dragging'); + // Prepare the menu to be opened. + _this._openSetup(); + _this.trigger('open:start'); + // Get the maximum distance to move out the page or menu. + maxDistance = _this.node.menu[vars.axis == 'x' ? 'clientWidth' : 'clientHeight']; + } + }); + // Move the page or menu when dragging. + events.on(dragNode, 'dragMove', function (evnt) { + if (evnt['detail'].axis == vars.axis) { + if (moving) { + var distance = evnt['detail']['distance' + vars.axis.toUpperCase()]; + switch (vars.position) { + case 'right': + case 'bottom': + distance = Math.min(Math.max(distance, -maxDistance), 0); + break; + default: + distance = Math.max(Math.min(distance, maxDistance), 0); + } + // Deviate for position front (the menu starts out of view). + if (vars.zposition == 'front') { + switch (vars.position) { + case 'right': + case 'bottom': + distance += maxDistance; + break; + default: + distance -= maxDistance; + break; + } + } + vars.slideOutNodes.forEach(function (node) { + node.style['transform'] = + 'translate' + + vars.axis.toUpperCase() + + '(' + + distance + + 'px)'; + }); + } + } + }); + // Stop the page or menu from being moved. + events.on(dragNode, 'dragEnd', function (evnt) { + if (evnt['detail'].axis == vars.axis) { + if (moving) { + moving = false; + _this.node.wrpr.classList.remove('mm-wrapper_dragging'); + vars.slideOutNodes.forEach(function (node) { + node.style['transform'] = ''; + }); + // Determine if the menu should open or close. + var open_1 = Math.abs(evnt['detail']['distance' + vars.axis.toUpperCase()]) >= + maxDistance * 0.75; + if (!open_1) { + var movement = evnt['detail']['movement' + vars.axis.toUpperCase()]; + switch (vars.position) { + case 'right': + case 'bottom': + open_1 = movement <= 0; + break; + default: + open_1 = movement >= 0; + break; + } + } + if (open_1) { + _this._openStart(); + } + else { + _this.close(); + } + } + } + }); + } + }; + /** + * Remove the dragging events. + */ + var removeEvents = function () { + if (dragNode) { + events.off(dragNode, 'dragStart'); + events.off(dragNode, 'dragMove'); + events.off(dragNode, 'dragEnd'); + } + }; + var addMatchMedia = function () { + var queries = Object.keys(_this.opts.extensions); + if (queries.length) { + // A media query that'll match if any of the other media query matches: + // set the defaults if it doesn't match. + media.add(queries.join(', '), function () { }, function () { + vars = getPositionVars(vars, [], _this.node.menu); + }); + // The other media queries. + queries.forEach(function (query) { + media.add(query, function () { + vars = getPositionVars(vars, _this.opts.extensions[query], _this.node.menu); + }, function () { }); + }); + // No extensions, just use the defaults. + } + else { + vars = getPositionVars(vars, [], _this.node.menu); + } + }; + // Remove events from previous "page" + removeEvents(); + // Store new "page" + dragNode = page; + // Initialize the drag events. + dragInstance = new DragEvents(dragNode); + addMatchMedia(); + addMatchMedia = function () { }; + addEvents(); +} +var getPositionVars = function (vars, extensions, menu) { + // Default position and z-position. + vars.position = 'left'; + vars.zposition = 'back'; + // Find position. + ['right', 'top', 'bottom'].forEach(function (pos) { + if (extensions.indexOf('position-' + pos) > -1) { + vars.position = pos; + } + }); + // Find z-position. + ['front', 'top', 'bottom'].forEach(function (pos) { + if (extensions.indexOf('position-' + pos) > -1) { + vars.zposition = 'front'; + } + }); + // Set the area where the dragging can start. + dragInstance.area = { + top: vars.position == 'bottom' ? '75%' : 0, + right: vars.position == 'left' ? '75%' : 0, + bottom: vars.position == 'top' ? '75%' : 0, + left: vars.position == 'right' ? '75%' : 0 + }; + // What side of the menu to measure (width or height). + // What axis to drag the menu along (x or y). + switch (vars.position) { + case 'top': + case 'bottom': + vars.axis = 'y'; + break; + default: + vars.axis = 'x'; + } + // What direction to drag in. + switch (vars.position) { + case 'top': + vars.direction = 'Down'; + break; + case 'right': + vars.direction = 'Left'; + break; + case 'bottom': + vars.direction = 'Up'; + break; + default: + vars.direction = 'Right'; + } + // What nodes to slide out while dragging. + switch (vars.zposition) { + case 'front': + vars.slideOutNodes = [menu]; + break; + default: + vars.slideOutNodes = DOM.find(document.body, '.mm-slideout'); + } + return vars; +}; diff --git a/dist/addons/drag/_options.js b/dist/addons/drag/_options.js new file mode 100644 index 0000000..f7bae38 --- /dev/null +++ b/dist/addons/drag/_options.js @@ -0,0 +1,22 @@ +var options = { + open: false, + node: null +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + open: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} diff --git a/dist/addons/drag/mmenu.drag.css b/dist/addons/drag/mmenu.drag.css new file mode 100644 index 0000000..d19e5c5 --- /dev/null +++ b/dist/addons/drag/mmenu.drag.css @@ -0,0 +1 @@ +.mm-wrapper_dragging .mm-menu,.mm-wrapper_dragging .mm-slideout{-webkit-transition-duration:0s!important;-o-transition-duration:0s!important;transition-duration:0s!important;-webkit-user-select:none!important;-moz-user-select:none!important;-ms-user-select:none!important;user-select:none!important}.mm-wrapper_dragging .mm-menu{pointer-events:none!important}.mm-wrapper_dragging .mm-wrapper__blocker{display:none!important} \ No newline at end of file diff --git a/dist/addons/drag/mmenu.drag.js b/dist/addons/drag/mmenu.drag.js new file mode 100644 index 0000000..36bb85c --- /dev/null +++ b/dist/addons/drag/mmenu.drag.js @@ -0,0 +1,21 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import dragOpen from './_drag.open'; +import { extend } from '../../_modules/helpers'; +// Add the options and configs. +Mmenu.options.drag = options; +export default function () { + var _this = this; + if (!this.opts.offCanvas) { + return; + } + var options = extendShorthandOptions(this.opts.drag); + this.opts.drag = extend(options, Mmenu.options.drag); + // Drag open the menu + if (options.open) { + this.bind('setPage:after', function (page) { + dragOpen.call(_this, options.node || page); + }); + } +} diff --git a/dist/addons/dropdown/_configs.js b/dist/addons/dropdown/_configs.js new file mode 100644 index 0000000..fae440b --- /dev/null +++ b/dist/addons/dropdown/_configs.js @@ -0,0 +1,19 @@ +var configs = { + offset: { + button: { + x: -5, + y: 5 + }, + viewport: { + x: 20, + y: 20 + } + }, + height: { + max: 880 + }, + width: { + max: 440 + } +}; +export default configs; diff --git a/dist/addons/dropdown/_options.js b/dist/addons/dropdown/_options.js new file mode 100644 index 0000000..8b30c85 --- /dev/null +++ b/dist/addons/dropdown/_options.js @@ -0,0 +1,31 @@ +var options = { + drop: false, + fitViewport: true, + event: 'click', + position: {}, + tip: true +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean' && options) { + options = { + drop: options + }; + } + if (typeof options != 'object') { + options = {}; + } + if (typeof options.position == 'string') { + options.position = { + of: options.position + }; + } + return options; +} +; diff --git a/dist/addons/dropdown/mmenu.dropdown.css b/dist/addons/dropdown/mmenu.dropdown.css new file mode 100644 index 0000000..c8e404d --- /dev/null +++ b/dist/addons/dropdown/mmenu.dropdown.css @@ -0,0 +1 @@ +.mm-menu_dropdown{-webkit-box-shadow:0 2px 10px rgba(0,0,0,.3);box-shadow:0 2px 10px rgba(0,0,0,.3);height:80%}.mm-wrapper_dropdown .mm-slideout{-webkit-transform:none!important;-ms-transform:none!important;transform:none!important;z-index:0}.mm-wrapper_dropdown .mm-wrapper__blocker{-webkit-transition-delay:0s!important;-o-transition-delay:0s!important;transition-delay:0s!important;z-index:1}.mm-wrapper_dropdown .mm-menu_dropdown{z-index:2}.mm-wrapper_dropdown.mm-wrapper_opened:not(.mm-wrapper_opening) .mm-menu_dropdown{display:none}.mm-menu_tip-bottom:before,.mm-menu_tip-left:before,.mm-menu_tip-right:before,.mm-menu_tip-top:before{content:'';background:inherit;-webkit-box-shadow:0 2px 10px rgba(0,0,0,.3);box-shadow:0 2px 10px rgba(0,0,0,.3);display:block;width:15px;height:15px;position:absolute;z-index:-1;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.mm-menu_tip-left:before{left:22px}.mm-menu_tip-right:before{right:22px}.mm-menu_tip-top:before{top:-8px}.mm-menu_tip-bottom:before{bottom:-8px} \ No newline at end of file diff --git a/dist/addons/dropdown/mmenu.dropdown.js b/dist/addons/dropdown/mmenu.dropdown.js new file mode 100644 index 0000000..238875c --- /dev/null +++ b/dist/addons/dropdown/mmenu.dropdown.js @@ -0,0 +1,159 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend, originalId } from '../../_modules/helpers'; +// Add the options and configs. +Mmenu.options.dropdown = options; +Mmenu.configs.dropdown = configs; +export default function () { + var _this = this; + if (!this.opts.offCanvas) { + return; + } + var options = extendShorthandOptions(this.opts.dropdown); + this.opts.dropdown = extend(options, Mmenu.options.dropdown); + var configs = this.conf.dropdown; + if (!options.drop) { + return; + } + var button; + this.bind('initMenu:after', function () { + _this.node.menu.classList.add('mm-menu_dropdown'); + if (typeof options.position.of != 'string') { + var id = originalId(_this.node.menu.id); + if (id) { + options.position.of = '[href="#' + id + '"]'; + } + } + if (typeof options.position.of != 'string') { + return; + } + // Get the button to put the menu next to + button = DOM.find(document.body, options.position.of)[0]; + // Emulate hover effect + var events = options.event.split(' '); + if (events.length == 1) { + events[1] = events[0]; + } + if (events[0] == 'hover') { + button.addEventListener('mouseenter', function () { + _this.open(); + }, { passive: true }); + } + if (events[1] == 'hover') { + _this.node.menu.addEventListener('mouseleave', function () { + _this.close(); + }, { passive: true }); + } + }); + // Add/remove classname and style when opening/closing the menu + this.bind('open:start', function () { + _this.node.menu['mmStyle'] = _this.node.menu.getAttribute('style'); + _this.node.wrpr.classList.add('mm-wrapper_dropdown'); + }); + this.bind('close:finish', function () { + _this.node.menu.setAttribute('style', _this.node.menu['mmStyle']); + _this.node.wrpr.classList.remove('mm-wrapper_dropdown'); + }); + /** + * Find the position (x, y) and sizes (width, height) for the menu. + * + * @param {string} dir The direction to measure ("x" for horizontal, "y" for vertical) + * @param {object} obj The object where (previously) measured values are stored. + * @return {object} The object where measered values are stored. + */ + var getPosition = function (dir, obj) { + var css = obj[0], cls = obj[1]; + var _outerSize = dir == 'x' ? 'offsetWidth' : 'offsetHeight', _startPos = dir == 'x' ? 'left' : 'top', _stopPos = dir == 'x' ? 'right' : 'bottom', _size = dir == 'x' ? 'width' : 'height', _winSize = dir == 'x' ? 'innerWidth' : 'innerHeight', _maxSize = dir == 'x' ? 'maxWidth' : 'maxHeight', _position = null; + var startPos = DOM.offset(button, _startPos), stopPos = startPos + button[_outerSize], windowSize = window[_winSize]; + /** Offset for the menu relative to the button. */ + var offs = configs.offset.button[dir] + configs.offset.viewport[dir]; + // Position set in option + if (options.position[dir]) { + switch (options.position[dir]) { + case 'left': + case 'bottom': + _position = 'after'; + break; + case 'right': + case 'top': + _position = 'before'; + break; + } + } + // Position not set in option, find most space + if (_position === null) { + _position = + startPos + (stopPos - startPos) / 2 < windowSize / 2 + ? 'after' + : 'before'; + } + // Set position and max + var val, max; + if (_position == 'after') { + val = dir == 'x' ? startPos : stopPos; + max = windowSize - (val + offs); + css[_startPos] = val + configs.offset.button[dir] + 'px'; + css[_stopPos] = 'auto'; + if (options.tip) { + cls.push('mm-menu_tip-' + (dir == 'x' ? 'left' : 'top')); + } + } + else { + val = dir == 'x' ? stopPos : startPos; + max = val - offs; + css[_stopPos] = + 'calc( 100% - ' + (val - configs.offset.button[dir]) + 'px )'; + css[_startPos] = 'auto'; + if (options.tip) { + cls.push('mm-menu_tip-' + (dir == 'x' ? 'right' : 'bottom')); + } + } + if (options.fitViewport) { + css[_maxSize] = Math.min(configs[_size].max, max) + 'px'; + } + return [css, cls]; + }; + function position() { + var _this = this; + if (!this.vars.opened) { + return; + } + this.node.menu.setAttribute('style', this.node.menu['mmStyle']); + var obj = [{}, []]; + obj = getPosition.call(this, 'y', obj); + obj = getPosition.call(this, 'x', obj); + for (var s in obj[0]) { + this.node.menu.style[s] = obj[0][s]; + } + if (options.tip) { + var classnames = [ + 'mm-menu_tip-left', + 'mm-menu_tip-right', + 'mm-menu_tip-top', + 'mm-menu_tip-bottom' + ]; + // IE11: + classnames.forEach(function (classname) { + _this.node.menu.classList.remove(classname); + }); + obj[1].forEach(function (classname) { + _this.node.menu.classList.add(classname); + }); + // Better browsers: + // this.node.menu.classList.remove(...classnames); + // this.node.menu.classList.add(...obj[1]); + } + } + this.bind('open:start', position); + window.addEventListener('resize', function (evnt) { + position.call(_this); + }, { passive: true }); + if (!this.opts.offCanvas.blockUI) { + window.addEventListener('scroll', function (evnt) { + position.call(_this); + }, { passive: true }); + } +} diff --git a/dist/addons/fixedelements/_configs.js b/dist/addons/fixedelements/_configs.js new file mode 100644 index 0000000..277750a --- /dev/null +++ b/dist/addons/fixedelements/_configs.js @@ -0,0 +1,5 @@ +var configs = { + insertMethod: 'append', + insertSelector: 'body' +}; +export default configs; diff --git a/dist/addons/fixedelements/mmenu.fixedelements.js b/dist/addons/fixedelements/mmenu.fixedelements.js new file mode 100644 index 0000000..5394eac --- /dev/null +++ b/dist/addons/fixedelements/mmenu.fixedelements.js @@ -0,0 +1,26 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import configs from './_configs'; +import * as DOM from '../../_modules/dom'; +// Add the configs. +Mmenu.configs.fixedElements = configs; +// Add the classnames. +Mmenu.configs.classNames.fixedElements = { + fixed: 'Fixed' +}; +export default function () { + var _this = this; + if (!this.opts.offCanvas) { + return; + } + var configs = this.conf.fixedElements; + var _fixd, fixed, wrppr; + this.bind('setPage:after', function (page) { + _fixd = _this.conf.classNames.fixedElements.fixed; + wrppr = DOM.find(document, configs.insertSelector)[0]; + fixed = DOM.find(page, '.' + _fixd); + fixed.forEach(function (fxd) { + DOM.reClass(fxd, _fixd, 'mm-slideout'); + wrppr[configs.insertMethod](fxd); + }); + }); +} diff --git a/dist/addons/iconbar/_options.js b/dist/addons/iconbar/_options.js new file mode 100644 index 0000000..821e7b8 --- /dev/null +++ b/dist/addons/iconbar/_options.js @@ -0,0 +1,33 @@ +import { type } from '../../_modules/helpers'; +var options = { + use: false, + top: [], + bottom: [], + position: 'left', + type: 'default' +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (type(options) == 'array') { + options = { + use: true, + top: options + }; + } + if (type(options) != 'object') { + options = {}; + } + if (typeof options.use == 'undefined') { + options.use = true; + } + if (typeof options.use == 'boolean' && options.use) { + options.use = true; + } + return options; +} diff --git a/dist/addons/iconbar/mmenu.iconbar.css b/dist/addons/iconbar/mmenu.iconbar.css new file mode 100644 index 0000000..947ab91 --- /dev/null +++ b/dist/addons/iconbar/mmenu.iconbar.css @@ -0,0 +1 @@ +:root{--mm-iconbar-size:50px}.mm-menu_iconbar-left .mm-navbars_bottom,.mm-menu_iconbar-left .mm-navbars_top,.mm-menu_iconbar-left .mm-panels{margin-left:50px;margin-left:var(--mm-iconbar-size)}.mm-menu_iconbar-left .mm-iconbar{border-right-width:1px;display:block;left:0}.mm-menu_iconbar-right .mm-navbars_bottom,.mm-menu_iconbar-right .mm-navbars_top,.mm-menu_iconbar-right .mm-panels{margin-right:50px;margin-right:var(--mm-iconbar-size)}.mm-menu_iconbar-right .mm-iconbar{border-left-width:1px;display:block;right:0}.mm-iconbar{width:50px;border-color:rgba(0,0,0,.1);background:#f3f3f3;color:rgba(0,0,0,.3);display:none;width:var(--mm-iconbar-size);overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;position:absolute;top:0;bottom:0;z-index:2;border:0 solid;border-color:var(--mm-color-border);background:var(--mm-color-background);color:var(--mm-color-text-dimmed);text-align:center}.mm-iconbar__bottom,.mm-iconbar__top{width:inherit;position:absolute}.mm-iconbar__bottom>*,.mm-iconbar__top>*{-webkit-box-sizing:border-box;box-sizing:border-box;display:block;padding:12.5px 0}.mm-iconbar__bottom a,.mm-iconbar__bottom a:hover,.mm-iconbar__top a,.mm-iconbar__top a:hover{text-decoration:none}.mm-iconbar__top{top:0}.mm-iconbar__bottom{bottom:0}.mm-iconbar__tab_selected{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)} \ No newline at end of file diff --git a/dist/addons/iconbar/mmenu.iconbar.js b/dist/addons/iconbar/mmenu.iconbar.js new file mode 100644 index 0000000..8e3c49c --- /dev/null +++ b/dist/addons/iconbar/mmenu.iconbar.js @@ -0,0 +1,103 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as media from '../../_modules/matchmedia'; +import { type, extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.iconbar = options; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.iconbar); + this.opts.iconbar = extend(options, Mmenu.options.iconbar); + if (!options.use) { + return; + } + var iconbar; + ['top', 'bottom'].forEach(function (position, n) { + var ctnt = options[position]; + // Extend shorthand options + if (type(ctnt) != 'array') { + ctnt = [ctnt]; + } + // Create node + var part = DOM.create('div.mm-iconbar__' + position); + // Add content + for (var c = 0, l = ctnt.length; c < l; c++) { + if (typeof ctnt[c] == 'string') { + part.innerHTML += ctnt[c]; + } + else { + part.append(ctnt[c]); + } + } + if (part.children.length) { + if (!iconbar) { + iconbar = DOM.create('div.mm-iconbar'); + } + iconbar.append(part); + } + }); + // Add to menu + if (iconbar) { + // Add the iconbar. + this.bind('initMenu:after', function () { + _this.node.menu.prepend(iconbar); + }); + // En-/disable the iconbar. + var classname_1 = 'mm-menu_iconbar-' + options.position; + var enable = function () { + _this.node.menu.classList.add(classname_1); + Mmenu.sr_aria(iconbar, 'hidden', false); + }; + var disable = function () { + _this.node.menu.classList.remove(classname_1); + Mmenu.sr_aria(iconbar, 'hidden', true); + }; + if (typeof options.use == 'boolean') { + this.bind('initMenu:after', enable); + } + else { + media.add(options.use, enable, disable); + } + // Tabs + if (options.type == 'tabs') { + iconbar.classList.add('mm-iconbar_tabs'); + iconbar.addEventListener('click', function (evnt) { + var anchor = evnt.target; + if (!anchor.matches('a')) { + return; + } + if (anchor.matches('.mm-iconbar__tab_selected')) { + evnt.stopImmediatePropagation(); + return; + } + try { + var panel = _this.node.menu.querySelector(anchor.getAttribute('href'))[0]; + if (panel && panel.matches('.mm-panel')) { + evnt.preventDefault(); + evnt.stopImmediatePropagation(); + _this.openPanel(panel, false); + } + } + catch (err) { } + }); + var selectTab_1 = function (panel) { + DOM.find(iconbar, 'a').forEach(function (anchor) { + anchor.classList.remove('mm-iconbar__tab_selected'); + }); + var anchor = DOM.find(iconbar, '[href="#' + panel.id + '"]')[0]; + if (anchor) { + anchor.classList.add('mm-iconbar__tab_selected'); + } + else { + var parent_1 = panel['mmParent']; + if (parent_1) { + selectTab_1(parent_1.closest('.mm-panel')); + } + } + }; + this.bind('openPanel:start', selectTab_1); + } + } +} diff --git a/dist/addons/iconpanels/_options.js b/dist/addons/iconpanels/_options.js new file mode 100644 index 0000000..321759e --- /dev/null +++ b/dist/addons/iconpanels/_options.js @@ -0,0 +1,33 @@ +var options = { + add: false, + blockPanel: true, + hideDivider: false, + hideNavbar: true, + visible: 3 +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + add: options + }; + } + if (typeof options == 'number' || + typeof options == 'string') { + options = { + add: true, + visible: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/addons/iconpanels/mmenu.iconpanels.css b/dist/addons/iconpanels/mmenu.iconpanels.css new file mode 100644 index 0000000..1a14373 --- /dev/null +++ b/dist/addons/iconpanels/mmenu.iconpanels.css @@ -0,0 +1 @@ +:root{--mm-iconpanel-size:50px}.mm-panel_iconpanel-1{width:calc(100% - 50px);width:calc(100% - (var(--mm-iconpanel-size) * 1))}.mm-panel_iconpanel-2{width:calc(100% - 100px);width:calc(100% - (var(--mm-iconpanel-size) * 2))}.mm-panel_iconpanel-3{width:calc(100% - 150px);width:calc(100% - (var(--mm-iconpanel-size) * 3))}.mm-panel_iconpanel-first~.mm-panel{width:calc(100% - 50px);width:calc(100% - var(--mm-iconpanel-size))}.mm-menu_iconpanel .mm-panels>.mm-panel{left:auto;-webkit-transition-property:width,-webkit-transform;transition-property:width,-webkit-transform;-o-transition-property:transform,width;transition-property:transform,width;transition-property:transform,width,-webkit-transform}.mm-menu_iconpanel .mm-panels>.mm-panel_opened,.mm-menu_iconpanel .mm-panels>.mm-panel_opened-parent{display:block!important}.mm-menu_iconpanel .mm-panels>.mm-panel_opened-parent{overflow-y:hidden;-webkit-transform:unset;-ms-transform:unset;transform:unset}.mm-menu_iconpanel .mm-panels>.mm-panel:not(.mm-panel_iconpanel-first):not(.mm-panel_iconpanel-0){border-left-width:1px;border-left-style:solid}.mm-menu_hidedivider .mm-panel_opened-parent .mm-divider,.mm-menu_hidenavbar .mm-panel_opened-parent .mm-navbar{opacity:0}.mm-panel__blocker{background:inherit;opacity:0;display:block;position:absolute;top:0;right:0;left:0;z-index:3;-webkit-transition:opacity .4s ease;-o-transition:opacity .4s ease;transition:opacity .4s ease}.mm-panel_opened-parent .mm-panel__blocker{opacity:.6;bottom:-100000px}[dir=rtl] .mm-menu_iconpanel .mm-panels>.mm-panel{left:0;right:auto;-webkit-transition-property:width,-webkit-transform;transition-property:width,-webkit-transform;-o-transition-property:transform,width;transition-property:transform,width;transition-property:transform,width,-webkit-transform}[dir=rtl] .mm-menu_iconpanel .mm-panels>.mm-panel:not(.mm-panel_iconpanel-first):not(.mm-panel_iconpanel-0){border-left:none;border-right:1px solid;border-color:inherit} \ No newline at end of file diff --git a/dist/addons/iconpanels/mmenu.iconpanels.js b/dist/addons/iconpanels/mmenu.iconpanels.js new file mode 100644 index 0000000..fe58b4c --- /dev/null +++ b/dist/addons/iconpanels/mmenu.iconpanels.js @@ -0,0 +1,99 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.iconPanels = options; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.iconPanels); + this.opts.iconPanels = extend(options, Mmenu.options.iconPanels); + var keepFirst = false; + if (options.visible == 'first') { + keepFirst = true; + options.visible = 1; + } + options.visible = Math.min(3, Math.max(1, options.visible)); + options.visible++; + // Add the iconpanels + if (options.add) { + this.bind('initMenu:after', function () { + var classnames = ['mm-menu_iconpanel']; + if (options.hideNavbar) { + classnames.push('mm-menu_hidenavbar'); + } + if (options.hideDivider) { + classnames.push('mm-menu_hidedivider'); + } + // IE11: + classnames.forEach(function (classname) { + _this.node.menu.classList.add(classname); + }); + // Better browsers: + // this.node.menu.classList.add(...classnames); + }); + var classnames_1 = []; + if (!keepFirst) { + for (var i = 0; i <= options.visible; i++) { + classnames_1.push('mm-panel_iconpanel-' + i); + } + } + this.bind('openPanel:start', function (panel) { + var panels = DOM.children(_this.node.pnls, '.mm-panel'); + panel = panel || panels[0]; + if (panel.parentElement.matches('.mm-listitem_vertical')) { + return; + } + if (keepFirst) { + panels.forEach(function (panel, p) { + panel.classList[p == 0 ? 'add' : 'remove']('mm-panel_iconpanel-first'); + }); + } + else { + // Remove the "iconpanel" classnames from all panels. + panels.forEach(function (panel) { + // IE11: + classnames_1.forEach(function (classname) { + panel.classList.remove(classname); + }); + // Better browsers: + // panel.classList.remove(...classnames); + }); + // Filter out panels that are not opened. + panels = panels.filter(function (panel) { + return panel.matches('.mm-panel_opened-parent'); + }); + // Add the current panel to the list. + var panelAdded_1 = false; + panels.forEach(function (elem) { + if (panel === elem) { + panelAdded_1 = true; + } + }); + if (!panelAdded_1) { + panels.push(panel); + } + // Remove the "hidden" classname from all opened panels. + panels.forEach(function (panel) { + panel.classList.remove('mm-hidden'); + }); + // Slice the opened panels to the max visible amount. + panels = panels.slice(-options.visible); + // Add the "iconpanel" classnames. + panels.forEach(function (panel, p) { + panel.classList.add('mm-panel_iconpanel-' + p); + }); + } + }); + this.bind('initPanel:after', function (panel) { + if (options.blockPanel && + !panel.parentElement.matches('.mm-listitem_vertical') && + !DOM.children(panel, '.mm-panel__blocker')[0]) { + var blocker = DOM.create('a.mm-panel__blocker'); + blocker.setAttribute('href', '#' + panel.closest('.mm-panel').id); + panel.prepend(blocker); + } + }); + } +} diff --git a/dist/addons/keyboardnavigation/_options.js b/dist/addons/keyboardnavigation/_options.js new file mode 100644 index 0000000..d0590b7 --- /dev/null +++ b/dist/addons/keyboardnavigation/_options.js @@ -0,0 +1,23 @@ +var options = { + enable: false, + enhance: false +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean' || typeof options == 'string') { + options = { + enable: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/addons/keyboardnavigation/mmenu.keyboardnavigation.css b/dist/addons/keyboardnavigation/mmenu.keyboardnavigation.css new file mode 100644 index 0000000..de70aa4 --- /dev/null +++ b/dist/addons/keyboardnavigation/mmenu.keyboardnavigation.css @@ -0,0 +1 @@ +.mm-menu_keyboardfocus a:focus,.mm-menu_keyboardfocus.mm-menu_opened~.mm-wrapper__blocker a:focus{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis);outline:0}.mm-wrapper__blocker .mm-tabstart{cursor:default;display:block;width:100%;height:100%}.mm-wrapper__blocker .mm-tabend{opacity:0;position:absolute;bottom:0} \ No newline at end of file diff --git a/dist/addons/keyboardnavigation/mmenu.keyboardnavigation.js b/dist/addons/keyboardnavigation/mmenu.keyboardnavigation.js new file mode 100644 index 0000000..e11d45a --- /dev/null +++ b/dist/addons/keyboardnavigation/mmenu.keyboardnavigation.js @@ -0,0 +1,183 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as events from '../../_modules/eventlisteners'; +import * as support from '../../_modules/support'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.keyboardNavigation = options; +export default function () { + var _this = this; + // Keyboard navigation on touchscreens opens the virtual keyboard :/ + // Lets prevent that. + if (support.touch) { + return; + } + var options = extendShorthandOptions(this.opts.keyboardNavigation); + this.opts.keyboardNavigation = extend(options, Mmenu.options.keyboardNavigation); + // Enable keyboard navigation + if (options.enable) { + var menuStart_1 = DOM.create('button.mm-tabstart.mm-sronly'), menuEnd_1 = DOM.create('button.mm-tabend.mm-sronly'), blockerEnd_1 = DOM.create('button.mm-tabend.mm-sronly'); + this.bind('initMenu:after', function () { + if (options.enhance) { + _this.node.menu.classList.add('mm-menu_keyboardfocus'); + } + initWindow.call(_this, options.enhance); + }); + this.bind('initOpened:before', function () { + _this.node.menu.prepend(menuStart_1); + _this.node.menu.append(menuEnd_1); + DOM.children(_this.node.menu, '.mm-navbars-top, .mm-navbars-bottom').forEach(function (navbars) { + navbars.querySelectorAll('.mm-navbar__title').forEach(function (title) { + title.setAttribute('tabindex', '-1'); + }); + }); + }); + this.bind('initBlocker:after', function () { + Mmenu.node.blck.append(blockerEnd_1); + DOM.children(Mmenu.node.blck, 'a')[0].classList.add('mm-tabstart'); + }); + var focusable_1 = 'input, select, textarea, button, label, a[href]'; + var setFocus = function (panel) { + panel = + panel || DOM.children(_this.node.pnls, '.mm-panel_opened')[0]; + var focus = null; + // Focus already is on an element in a navbar in this menu. + var navbar = document.activeElement.closest('.mm-navbar'); + if (navbar) { + if (navbar.closest('.mm-menu') == _this.node.menu) { + return; + } + } + // Set the focus to the first focusable element by default. + if (options.enable == 'default') { + // First visible anchor in a listview in the current panel. + focus = DOM.find(panel, '.mm-listview a[href]:not(.mm-hidden)')[0]; + // First focusable and visible element in the current panel. + if (!focus) { + focus = DOM.find(panel, focusable_1 + ':not(.mm-hidden)')[0]; + } + // First focusable and visible element in a navbar. + if (!focus) { + var elements_1 = []; + DOM.children(_this.node.menu, '.mm-navbars_top, .mm-navbars_bottom').forEach(function (navbar) { + elements_1.push.apply(elements_1, DOM.find(navbar, focusable_1 + ':not(.mm-hidden)')); + }); + focus = elements_1[0]; + } + } + // Default. + if (!focus) { + focus = DOM.children(_this.node.menu, '.mm-tabstart')[0]; + } + if (focus) { + focus.focus(); + } + }; + this.bind('open:finish', setFocus); + this.bind('openPanel:finish', setFocus); + // Add screenreader / aria support. + this.bind('initOpened:after:sr-aria', function () { + [_this.node.menu, Mmenu.node.blck].forEach(function (element) { + DOM.children(element, '.mm-tabstart, .mm-tabend').forEach(function (tabber) { + Mmenu.sr_aria(tabber, 'hidden', true); + Mmenu.sr_role(tabber, 'presentation'); + }); + }); + }); + } +} +/** + * Initialize the window for keyboard navigation. + * @param {boolean} enhance - Whether or not to also rich enhance the keyboard behavior. + **/ +var initWindow = function (enhance) { + var _this = this; + // Re-enable tabbing in general + events.off(document.body, 'keydown.tabguard'); + // Intersept the target when tabbing. + events.off(document.body, 'focusin.tabguard'); + events.on(document.body, 'focusin.tabguard', function (evnt) { + if (_this.node.wrpr.matches('.mm-wrapper_opened')) { + var target = evnt.target; + if (target.matches('.mm-tabend')) { + var next = void 0; + // Jump from menu to blocker. + if (target.parentElement.matches('.mm-menu')) { + if (Mmenu.node.blck) { + next = Mmenu.node.blck; + } + } + // Jump to opened menu. + if (target.parentElement.matches('.mm-wrapper__blocker')) { + next = DOM.find(document.body, '.mm-menu_offcanvas.mm-menu_opened')[0]; + } + // If no available element found, stay in current element. + if (!next) { + next = target.parentElement; + } + if (next) { + DOM.children(next, '.mm-tabstart')[0].focus(); + } + } + } + }); + // Add Additional keyboard behavior. + events.off(document.body, 'keydown.navigate'); + events.on(document.body, 'keydown.navigate', function (evnt) { + var target = evnt.target; + var menu = target.closest('.mm-menu'); + if (menu) { + var api = menu['mmApi']; + if (!target.matches('input, textarea')) { + switch (evnt.keyCode) { + // press enter to toggle and check + case 13: + if (target.matches('.mm-toggle') || + target.matches('.mm-check')) { + target.dispatchEvent(new Event('click')); + } + break; + // prevent spacebar or arrows from scrolling the page + case 32: // space + case 37: // left + case 38: // top + case 39: // right + case 40: // bottom + evnt.preventDefault(); + break; + } + } + if (enhance) { + // special case for input + if (target.matches('input')) { + switch (evnt.keyCode) { + // empty searchfield with esc + case 27: + target.value = ''; + break; + } + } + else { + var api_1 = menu['mmApi']; + switch (evnt.keyCode) { + // close submenu with backspace + case 8: + var parent_1 = DOM.find(menu, '.mm-panel_opened')[0]['mmParent']; + if (parent_1) { + api_1.openPanel(parent_1.closest('.mm-panel')); + } + break; + // close menu with esc + case 27: + if (menu.matches('.mm-menu_offcanvas')) { + api_1.close(); + } + break; + } + } + } + } + }); +}; diff --git a/dist/addons/lazysubmenus/_options.js b/dist/addons/lazysubmenus/_options.js new file mode 100644 index 0000000..7162392 --- /dev/null +++ b/dist/addons/lazysubmenus/_options.js @@ -0,0 +1,22 @@ +var options = { + load: false +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + load: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/addons/lazysubmenus/mmenu.lazysubmenus.js b/dist/addons/lazysubmenus/mmenu.lazysubmenus.js new file mode 100644 index 0000000..f2ee908 --- /dev/null +++ b/dist/addons/lazysubmenus/mmenu.lazysubmenus.js @@ -0,0 +1,103 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.lazySubmenus = options; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.lazySubmenus); + this.opts.lazySubmenus = extend(options, Mmenu.options.lazySubmenus); + if (options.load) { + // Prevent all sub panels from being initialized. + this.bind('initMenu:after', function () { + var panels = []; + // Find all potential subpanels. + DOM.find(_this.node.pnls, 'li').forEach(function (listitem) { + panels.push.apply(panels, DOM.children(listitem, _this.conf.panelNodetype.join(', '))); + }); + // Filter out all non-panels and add the lazyload classes + panels + .filter(function (panel) { return !panel.matches('.mm-listview_inset'); }) + .filter(function (panel) { return !panel.matches('.mm-nolistview'); }) + .filter(function (panel) { return !panel.matches('.mm-nopanel'); }) + .forEach(function (panel) { + var classnames = [ + 'mm-panel_lazysubmenu', + 'mm-nolistview', + 'mm-nopanel' + ]; + // IE11: + classnames.forEach(function (classname) { + panel.classList.add(classname); + }); + // Better browsers: + // panel.classList.add(...classnames); + }); + }); + // Prepare current and one level sub panels for initPanels + this.bind('initPanels:before', function () { + var panels = DOM.children(_this.node.pnls, _this.conf.panelNodetype.join(', ')); + panels.forEach(function (panel) { + var filter = '.mm-panel_lazysubmenu', children = DOM.find(panel, filter); + if (panel.matches(filter)) { + children.unshift(panel); + } + children + .filter(function (child) { + return !child.matches('.mm-panel_lazysubmenu .mm-panel_lazysubmenu'); + }) + .forEach(function (child) { + var classnames = [ + 'mm-panel_lazysubmenu', + 'mm-nolistview', + 'mm-nopanel' + ]; + // IE11: + classnames.forEach(function (classname) { + child.classList.remove(classname); + }); + // Better browsers: + // child.classList.remove(...classnames); + }); + }); + }); + // initPanels for the default opened panel + this.bind('initOpened:before', function () { + var panels = []; + DOM.find(_this.node.pnls, '.' + _this.conf.classNames.selected).forEach(function (listitem) { + panels.push.apply(panels, DOM.parents(listitem, '.mm-panel_lazysubmenu')); + }); + if (panels.length) { + panels.forEach(function (panel) { + var classnames = [ + 'mm-panel_lazysubmenu', + 'mm-nolistview', + 'mm-nopanel' + ]; + // IE11: + classnames.forEach(function (classname) { + panel.classList.remove(classname); + }); + // Better browsers: + // panel.classList.remove(...classnames); + }); + _this.initPanel(panels[panels.length - 1]); + } + }); + // initPanels for current- and sub panels before openPanel + this.bind('openPanel:before', function (panel) { + var filter = '.mm-panel_lazysubmenu', panels = DOM.find(panel, filter); + if (panel.matches(filter)) { + panels.unshift(panel); + } + panels = panels.filter(function (panel) { + return !panel.matches('.mm-panel_lazysubmenu .mm-panel_lazysubmenu'); + }); + panels.forEach(function (panel) { + _this.initPanel(panel); + }); + }); + } +} diff --git a/dist/addons/navbars/_configs.js b/dist/addons/navbars/_configs.js new file mode 100644 index 0000000..24ecd61 --- /dev/null +++ b/dist/addons/navbars/_configs.js @@ -0,0 +1,7 @@ +var configs = { + breadcrumbs: { + separator: '/', + removeFirst: false + } +}; +export default configs; diff --git a/dist/addons/navbars/_navbar.breadcrumbs.js b/dist/addons/navbars/_navbar.breadcrumbs.js new file mode 100644 index 0000000..22136e4 --- /dev/null +++ b/dist/addons/navbars/_navbar.breadcrumbs.js @@ -0,0 +1,53 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; +export default function (navbar) { + var _this = this; + // Add content + var breadcrumbs = DOM.create('div.mm-navbar__breadcrumbs'); + navbar.append(breadcrumbs); + this.bind('initNavbar:after', function (panel) { + if (panel.querySelector('.mm-navbar__breadcrumbs')) { + return; + } + DOM.children(panel, '.mm-navbar')[0].classList.add('mm-hidden'); + var crumbs = [], breadcrumbs = DOM.create('span.mm-navbar__breadcrumbs'), current = panel, first = true; + while (current) { + current = current.closest('.mm-panel'); + if (!current.parentElement.matches('.mm-listitem_vertical')) { + var title = DOM.find(current, '.mm-navbar__title span')[0]; + if (title) { + var text = title.textContent; + if (text.length) { + crumbs.unshift(first + ? '' + text + '' + : '' + + text + + ''); + } + } + first = false; + } + current = current['mmParent']; + } + if (_this.conf.navbars.breadcrumbs.removeFirst) { + crumbs.shift(); + } + breadcrumbs.innerHTML = crumbs.join('' + + _this.conf.navbars.breadcrumbs.separator + + ''); + DOM.children(panel, '.mm-navbar')[0].append(breadcrumbs); + }); + // Update for to opened panel + this.bind('openPanel:start', function (panel) { + var crumbs = panel.querySelector('.mm-navbar__breadcrumbs'); + breadcrumbs.innerHTML = crumbs ? crumbs.innerHTML : ''; + }); + // Add screenreader / aria support + this.bind('initNavbar:after:sr-aria', function (panel) { + DOM.find(panel, '.mm-breadcrumbs a').forEach(function (anchor) { + Mmenu.sr_aria(anchor, 'owns', anchor.getAttribute('href').slice(1)); + }); + }); +} diff --git a/dist/addons/navbars/_navbar.close.js b/dist/addons/navbars/_navbar.close.js new file mode 100644 index 0000000..b038bcf --- /dev/null +++ b/dist/addons/navbars/_navbar.close.js @@ -0,0 +1,17 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; +export default function (navbar) { + var _this = this; + // Add content + var close = DOM.create('a.mm-btn.mm-btn_close.mm-navbar__btn'); + navbar.append(close); + // Update to page node + this.bind('setPage:after', function (page) { + close.setAttribute('href', '#' + page.id); + }); + // Add screenreader / text support + this.bind('setPage:after:sr-text', function () { + close.innerHTML = Mmenu.sr_text(_this.i18n(_this.conf.screenReader.text.closeMenu)); + Mmenu.sr_aria(close, 'owns', close.getAttribute('href').slice(1)); + }); +} diff --git a/dist/addons/navbars/_navbar.next.js b/dist/addons/navbars/_navbar.next.js new file mode 100644 index 0000000..73bd9d3 --- /dev/null +++ b/dist/addons/navbars/_navbar.next.js @@ -0,0 +1,31 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; +// DEPRECATED +// Will be removed in version 8.2 +export default function (navbar) { + var _this = this; + // Add content + var next = DOM.create('a.mm-btn.mm-btn_next.mm-navbar__btn'); + navbar.append(next); + // Update to opened panel + var org; + var _url, _txt; + this.bind('openPanel:start', function (panel) { + org = panel.querySelector('.' + _this.conf.classNames.navbars.panelNext); + _url = org ? org.getAttribute('href') : ''; + _txt = org ? org.innerHTML : ''; + if (_url) { + next.setAttribute('href', _url); + } + else { + next.removeAttribute('href'); + } + next.classList[_url || _txt ? 'remove' : 'add']('mm-hidden'); + next.innerHTML = _txt; + }); + // Add screenreader / aria support + this.bind('openPanel:start:sr-aria', function (panel) { + Mmenu.sr_aria(next, 'hidden', next.matches('mm-hidden')); + Mmenu.sr_aria(next, 'owns', (next.getAttribute('href') || '').slice(1)); + }); +} diff --git a/dist/addons/navbars/_navbar.prev.js b/dist/addons/navbars/_navbar.prev.js new file mode 100644 index 0000000..c8bf5f3 --- /dev/null +++ b/dist/addons/navbars/_navbar.prev.js @@ -0,0 +1,41 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; +export default function (navbar) { + var _this = this; + // Add content. + var prev = DOM.create('a.mm-btn.mm-btn_prev.mm-navbar__btn'); + navbar.append(prev); + this.bind('initNavbar:after', function (panel) { + DOM.children(panel, '.mm-navbar')[0].classList.add('mm-hidden'); + }); + // Update to opened panel. + var org; + var _url, _txt; + this.bind('openPanel:start', function (panel) { + if (panel.parentElement.matches('.mm-listitem_vertical')) { + return; + } + org = panel.querySelector('.' + _this.conf.classNames.navbars.panelPrev); + if (!org) { + org = panel.querySelector('.mm-navbar__btn.mm-btn_prev'); + } + _url = org ? org.getAttribute('href') : ''; + _txt = org ? org.innerHTML : ''; + if (_url) { + prev.setAttribute('href', _url); + } + else { + prev.removeAttribute('href'); + } + prev.classList[_url || _txt ? 'remove' : 'add']('mm-hidden'); + prev.innerHTML = _txt; + }); + // Add screenreader / aria support + this.bind('initNavbar:after:sr-aria', function (panel) { + Mmenu.sr_aria(panel.querySelector('.mm-navbar'), 'hidden', true); + }); + this.bind('openPanel:start:sr-aria', function (panel) { + Mmenu.sr_aria(prev, 'hidden', prev.matches('.mm-hidden')); + Mmenu.sr_aria(prev, 'owns', (prev.getAttribute('href') || '').slice(1)); + }); +} diff --git a/dist/addons/navbars/_navbar.searchfield.js b/dist/addons/navbars/_navbar.searchfield.js new file mode 100644 index 0000000..b9e3d0c --- /dev/null +++ b/dist/addons/navbars/_navbar.searchfield.js @@ -0,0 +1,11 @@ +import * as DOM from '../../_modules/dom'; +import { type } from '../../_modules/helpers'; +export default function (navbar) { + if (type(this.opts.searchfield) != 'object') { + this.opts.searchfield = {}; + } + var searchfield = DOM.create('div.mm-navbar__searchfield'); + navbar.append(searchfield); + this.opts.searchfield.add = true; + this.opts.searchfield.addTo = [searchfield]; +} diff --git a/dist/addons/navbars/_navbar.tabs.js b/dist/addons/navbars/_navbar.tabs.js new file mode 100644 index 0000000..a8880d8 --- /dev/null +++ b/dist/addons/navbars/_navbar.tabs.js @@ -0,0 +1,40 @@ +import * as DOM from '../../_modules/dom'; +export default function (navbar) { + var _this = this; + navbar.classList.add('mm-navbar_tabs'); + navbar.parentElement.classList.add('mm-navbars_has-tabs'); + var anchors = DOM.children(navbar, 'a'); + navbar.addEventListener('click', function (evnt) { + var anchor = evnt.target; + if (!anchor.matches('a')) { + return; + } + if (anchor.matches('.mm-navbar__tab_selected')) { + evnt.stopImmediatePropagation(); + return; + } + try { + _this.openPanel(_this.node.menu.querySelector(anchor.getAttribute('href')), false); + evnt.stopImmediatePropagation(); + } + catch (err) { } + }); + function selectTab(panel) { + anchors.forEach(function (anchor) { + anchor.classList.remove('mm-navbar__tab_selected'); + }); + var anchor = anchors.filter(function (anchor) { + return anchor.matches('[href="#' + panel.id + '"]'); + })[0]; + if (anchor) { + anchor.classList.add('mm-navbar__tab_selected'); + } + else { + var parent = panel['mmParent']; + if (parent) { + selectTab.call(this, parent.closest('.mm-panel')); + } + } + } + this.bind('openPanel:start', selectTab); +} diff --git a/dist/addons/navbars/_navbar.title.js b/dist/addons/navbars/_navbar.title.js new file mode 100644 index 0000000..f125478 --- /dev/null +++ b/dist/addons/navbars/_navbar.title.js @@ -0,0 +1,60 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; +export default function (navbar) { + var _this = this; + // Add content to the navbar. + var title = DOM.create('a.mm-navbar__title'); + var titleText = DOM.create('span'); + title.append(titleText); + navbar.append(title); + // Update the title to the opened panel. + var _url, _txt; + var original; + this.bind('openPanel:start', function (panel) { + // Do nothing in a vertically expanding panel. + if (panel.parentElement.matches('.mm-listitem_vertical')) { + return; + } + // Find the original title in the opened panel. + original = panel.querySelector('.' + _this.conf.classNames.navbars.panelTitle); + if (!original) { + original = panel.querySelector('.mm-navbar__title span'); + } + // Get the URL for the title. + _url = + original && original.closest('a') + ? original.closest('a').getAttribute('href') + : ''; + if (_url) { + title.setAttribute('href', _url); + } + else { + title.removeAttribute('href'); + } + // Get the text for the title. + _txt = original ? original.innerHTML : ''; + titleText.innerHTML = _txt; + }); + // Add screenreader / aria support + var prev; + this.bind('openPanel:start:sr-aria', function (panel) { + if (_this.opts.screenReader.text) { + if (!prev) { + var navbars = DOM.children(_this.node.menu, '.mm-navbars_top, .mm-navbars_bottom'); + navbars.forEach(function (navbar) { + var btn = navbar.querySelector('.mm-btn_prev'); + if (btn) { + prev = btn; + } + }); + } + if (prev) { + var hidden = true; + if (_this.opts.navbar.titleLink == 'parent') { + hidden = !prev.matches('.mm-hidden'); + } + Mmenu.sr_aria(title, 'hidden', hidden); + } + } + }); +} diff --git a/dist/addons/navbars/_options.js b/dist/addons/navbars/_options.js new file mode 100644 index 0000000..a9e6e45 --- /dev/null +++ b/dist/addons/navbars/_options.js @@ -0,0 +1,30 @@ +var options = []; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean' && options) { + options = {}; + } + if (typeof options != 'object') { + options = {}; + } + if (typeof options.content == 'undefined') { + options.content = ['prev', 'title']; + } + if (!(options.content instanceof Array)) { + options.content = [options.content]; + } + if (typeof options.use == 'undefined') { + options.use = true; + } + if (typeof options.use == 'boolean' && options.use) { + options.use = true; + } + return options; +} +; diff --git a/dist/addons/navbars/mmenu.navbars.css b/dist/addons/navbars/mmenu.navbars.css new file mode 100644 index 0000000..665c2f8 --- /dev/null +++ b/dist/addons/navbars/mmenu.navbars.css @@ -0,0 +1 @@ +.mm-navbars_top{-ms-flex-negative:0;flex-shrink:0}.mm-navbars_top .mm-navbar:not(:last-child){border-bottom:none}.mm-navbars_bottom{-ms-flex-negative:0;flex-shrink:0}.mm-navbars_bottom .mm-navbar{border-bottom:none}.mm-navbars_bottom .mm-navbar:first-child{border-top:1px solid rgba(0,0,0,.1);border-top:1px solid var(--mm-color-border)}.mm-btn:not(.mm-hidden)+.mm-navbar__searchfield .mm-searchfield__input{padding-left:0}.mm-navbar__searchfield:not(:last-child) .mm-searchfield__input{padding-right:0}.mm-navbar__breadcrumbs{-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;-webkit-box-flex:1;-ms-flex:1 1 50%;flex:1 1 50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;padding:0 20px;overflow-x:auto;-webkit-overflow-scrolling:touch}.mm-navbar__breadcrumbs>*{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding-right:6px}.mm-navbar__breadcrumbs>a{text-decoration:underline}.mm-navbar__breadcrumbs:not(:last-child){padding-right:0}.mm-btn:not(.mm-hidden)+.mm-navbar__breadcrumbs{padding-left:0}.mm-navbar_tabs>*{padding:0 10px;border:1px solid transparent}.mm-navbar__tab_selected{background:#f3f3f3;color:rgba(0,0,0,.75);background:var(--mm-color-background);color:var(--mm-color-text)}.mm-navbar__tab_selected:not(:first-child){border-left-color:rgba(0,0,0,.1)}.mm-navbar__tab_selected:not(:last-child){border-right-color:rgba(0,0,0,.1)}.mm-navbar__tab_selected:not(:first-child){border-left-color:var(--mm-color-border)}.mm-navbar__tab_selected:not(:last-child){border-right-color:var(--mm-color-border)}.mm-navbars_top .mm-navbar_tabs{border-bottom:none}.mm-navbars_top .mm-navbar_tabs>*{border-bottom-color:rgba(0,0,0,.1);border-bottom-color:var(--mm-color-border)}.mm-navbars_top .mm-navbar__tab_selected{border-top-color:rgba(0,0,0,.1);border-top-color:var(--mm-color-border);border-bottom-color:transparent}.mm-navbars_top.mm-navbars_has-tabs .mm-navbar{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)}.mm-navbars_top.mm-navbars_has-tabs .mm-navbar_tabs~.mm-navbar{background:#f3f3f3;background:var(--mm-color-background)}.mm-navbars_bottom .mm-navbar_tabs:first-child{border-top:none}.mm-navbars_bottom .mm-navbar_tabs>*{border-top-color:rgba(0,0,0,.1);border-top-color:var(--mm-color-border)}.mm-navbars_bottom .mm-navbar__tab_selected{border-bottom-color:rgba(0,0,0,.1);border-bottom-color:var(--mm-color-border);border-top-color:transparent}.mm-navbars_bottom.mm-navbars_has-tabs .mm-navbar{background:#f3f3f3;background:var(--mm-color-background)}.mm-navbars_bottom.mm-navbars_has-tabs .mm-navbar_tabs,.mm-navbars_bottom.mm-navbars_has-tabs .mm-navbar_tabs~.mm-navbar{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)} \ No newline at end of file diff --git a/dist/addons/navbars/mmenu.navbars.js b/dist/addons/navbars/mmenu.navbars.js new file mode 100644 index 0000000..59fc210 --- /dev/null +++ b/dist/addons/navbars/mmenu.navbars.js @@ -0,0 +1,120 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as media from '../../_modules/matchmedia'; +// Add the options and configs. +Mmenu.options.navbars = options; +Mmenu.configs.navbars = configs; +// Add the classnames. +Mmenu.configs.classNames.navbars = { + panelPrev: 'Prev', + panelTitle: 'Title' +}; +import breadcrumbs from './_navbar.breadcrumbs'; +import close from './_navbar.close'; +import prev from './_navbar.prev'; +import searchfield from './_navbar.searchfield'; +import title from './_navbar.title'; +Navbars.navbarContents = { + breadcrumbs: breadcrumbs, + close: close, + prev: prev, + searchfield: searchfield, + title: title +}; +import tabs from './_navbar.tabs'; +Navbars.navbarTypes = { + tabs: tabs +}; +export default function Navbars() { + var _this = this; + var navs = this.opts.navbars; + if (typeof navs == 'undefined') { + return; + } + if (!(navs instanceof Array)) { + navs = [navs]; + } + var navbars = {}; + if (!navs.length) { + return; + } + navs.forEach(function (options) { + options = extendShorthandOptions(options); + if (!options.use) { + return false; + } + // Create the navbar element. + var navbar = DOM.create('div.mm-navbar'); + // Get the position for the navbar. + var position = options.position; + // Restrict the position to either "bottom" or "top" (default). + if (position !== 'bottom') { + position = 'top'; + } + // Create the wrapper for the navbar position. + if (!navbars[position]) { + navbars[position] = DOM.create('div.mm-navbars_' + position); + } + navbars[position].append(navbar); + // Add content to the navbar. + for (var c = 0, l = options.content.length; c < l; c++) { + var ctnt = options.content[c]; + // The content is a string. + if (typeof ctnt == 'string') { + var func = Navbars.navbarContents[ctnt]; + // The content refers to one of the navbar-presets ("prev", "title", etc). + if (typeof func == 'function') { + // Call the preset function. + func.call(_this, navbar); + // The content is just HTML. + } + else { + // Add the HTML. + // Wrap the HTML in a single node + var node = DOM.create('span'); + node.innerHTML = ctnt; + // If there was only a single node, use that. + var children = DOM.children(node); + if (children.length == 1) { + node = children[0]; + } + navbar.append(node); + } + // The content is not a string, it must be an element. + } + else { + navbar.append(ctnt); + } + } + // The type option is set. + if (typeof options.type == 'string') { + // The function refers to one of the navbar-presets ("tabs"). + var func = Navbars.navbarTypes[options.type]; + if (typeof func == 'function') { + // Call the preset function. + func.call(_this, navbar); + } + } + // En-/disable the navbar. + var enable = function () { + navbar.classList.remove('mm-hidden'); + Mmenu.sr_aria(navbar, 'hidden', false); + }; + var disable = function () { + navbar.classList.add('mm-hidden'); + Mmenu.sr_aria(navbar, 'hidden', true); + }; + if (typeof options.use != 'boolean') { + media.add(options.use, enable, disable); + } + }); + // Add to menu. + this.bind('initMenu:after', function () { + for (var position in navbars) { + _this.node.menu[position == 'bottom' ? 'append' : 'prepend'](navbars[position]); + } + }); +} diff --git a/dist/addons/pagescroll/_configs.js b/dist/addons/pagescroll/_configs.js new file mode 100644 index 0000000..3662db1 --- /dev/null +++ b/dist/addons/pagescroll/_configs.js @@ -0,0 +1,5 @@ +var configs = { + scrollOffset: 0, + updateOffset: 50 +}; +export default configs; diff --git a/dist/addons/pagescroll/_options.js b/dist/addons/pagescroll/_options.js new file mode 100644 index 0000000..de3cacb --- /dev/null +++ b/dist/addons/pagescroll/_options.js @@ -0,0 +1,23 @@ +var options = { + scroll: false, + update: false +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + scroll: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/addons/pagescroll/mmenu.pagescroll.js b/dist/addons/pagescroll/mmenu.pagescroll.js new file mode 100644 index 0000000..ed60ddd --- /dev/null +++ b/dist/addons/pagescroll/mmenu.pagescroll.js @@ -0,0 +1,111 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; +// Add the options and configs. +Mmenu.options.pageScroll = options; +Mmenu.configs.pageScroll = configs; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.pageScroll); + this.opts.pageScroll = extend(options, Mmenu.options.pageScroll); + var configs = this.conf.pageScroll; + /** The currently "active" section */ + var section; + function scrollTo() { + if (section) { + // section.scrollIntoView({ behavior: 'smooth' }); + window.scrollTo({ + top: section.getBoundingClientRect().top + + document.scrollingElement.scrollTop - + configs.scrollOffset, + behavior: 'smooth' + }); + } + section = null; + } + function anchorInPage(href) { + try { + if (href != '#' && href.slice(0, 1) == '#') { + return Mmenu.node.page.querySelector(href); + } + return null; + } + catch (err) { + return null; + } + } + // Scroll to section after clicking menu item. + if (options.scroll) { + this.bind('close:finish', function () { + scrollTo(); + }); + } + // Add click behavior. + // Prevents default behavior when clicking an anchor. + if (this.opts.offCanvas && options.scroll) { + this.clck.push(function (anchor, args) { + section = null; + // Don't continue if the clicked anchor is not in the menu. + if (!args.inMenu) { + return; + } + // Don't continue if the targeted section is not on the page. + var href = anchor.getAttribute('href'); + section = anchorInPage(href); + if (!section) { + return; + } + // If the sidebar add-on is "expanded"... + if (_this.node.menu.matches('.mm-menu_sidebar-expanded') && + _this.node.wrpr.matches('.mm-wrapper_sidebar-expanded')) { + // ... scroll the page to the section. + scrollTo(); + // ... otherwise... + } + else { + // ... close the menu. + return { + close: true + }; + } + }); + } + // Update selected menu item after scrolling. + if (options.update) { + var scts_1 = []; + this.bind('initListview:after', function (listview) { + var listitems = DOM.children(listview, '.mm-listitem'); + DOM.filterLIA(listitems).forEach(function (anchor) { + var href = anchor.getAttribute('href'); + var section = anchorInPage(href); + if (section) { + scts_1.unshift(section); + } + }); + }); + var _selected_1 = -1; + window.addEventListener('scroll', function (evnt) { + var scrollTop = window.scrollY; + for (var s = 0; s < scts_1.length; s++) { + if (scts_1[s].offsetTop < scrollTop + configs.updateOffset) { + if (_selected_1 !== s) { + _selected_1 = s; + var panel = DOM.children(_this.node.pnls, '.mm-panel_opened')[0]; + var listitems = DOM.find(panel, '.mm-listitem'); + var anchors = DOM.filterLIA(listitems); + anchors = anchors.filter(function (anchor) { + return anchor.matches('[href="#' + scts_1[s].id + '"]'); + }); + if (anchors.length) { + _this.setSelected(anchors[0].parentElement); + } + } + break; + } + } + }); + } +} diff --git a/dist/addons/searchfield/_configs.js b/dist/addons/searchfield/_configs.js new file mode 100644 index 0000000..3bc4deb --- /dev/null +++ b/dist/addons/searchfield/_configs.js @@ -0,0 +1,7 @@ +var configs = { + clear: false, + form: false, + input: false, + submit: false +}; +export default configs; diff --git a/dist/addons/searchfield/_options.js b/dist/addons/searchfield/_options.js new file mode 100644 index 0000000..21e424a --- /dev/null +++ b/dist/addons/searchfield/_options.js @@ -0,0 +1,55 @@ +var options = { + add: false, + addTo: 'panels', + cancel: false, + noResults: 'No results found.', + placeholder: 'Search', + panel: { + add: false, + dividers: true, + fx: 'none', + id: null, + splash: null, + title: 'Search' + }, + search: true, + showTextItems: false, + showSubPanels: true +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + add: options + }; + } + if (typeof options != 'object') { + options = {}; + } + if (typeof options.panel == 'boolean') { + options.panel = { + add: options.panel + }; + } + if (typeof options.panel != 'object') { + options.panel = {}; + } + // Extend logical options. + if (options.addTo == 'panel') { + options.panel.add = true; + } + if (options.panel.add) { + options.showSubPanels = false; + if (options.panel.splash) { + options.cancel = true; + } + } + return options; +} +; diff --git a/dist/addons/searchfield/mmenu.searchfield.css b/dist/addons/searchfield/mmenu.searchfield.css new file mode 100644 index 0000000..f1ae636 --- /dev/null +++ b/dist/addons/searchfield/mmenu.searchfield.css @@ -0,0 +1 @@ +.mm-searchfield{height:44px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;height:var(--mm-navbar-size);padding:0;overflow:hidden}.mm-searchfield input{height:30.8px;line-height:30.8px}.mm-searchfield input,.mm-searchfield input:focus,.mm-searchfield input:hover{background:rgba(0,0,0,.05);color:rgba(0,0,0,.75)}.mm-searchfield input{display:block;width:100%;max-width:100%;height:calc(var(--mm-navbar-size) * .7);min-height:unset;max-height:unset;margin:0;padding:0 10px;-webkit-box-sizing:border-box;box-sizing:border-box;border:none!important;border-radius:4px;line-height:calc(var(--mm-navbar-size) * .7);-webkit-box-shadow:none!important;box-shadow:none!important;outline:0!important;font:inherit;font-size:inherit}.mm-searchfield input,.mm-searchfield input:focus,.mm-searchfield input:hover{background:var(--mm-color-background-highlight);color:var(--mm-color-text)}.mm-searchfield input::-ms-clear{display:none}.mm-searchfield__input{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;width:100%;max-width:100%;padding:0 10px;-webkit-box-sizing:border-box;box-sizing:border-box}.mm-panel__noresultsmsg{color:rgba(0,0,0,.3);padding:50px 0;color:var(--mm-color-text-dimmed);text-align:center;font-size:150%}.mm-searchfield__btn{position:absolute;right:0;top:0;bottom:0}.mm-panel_search{left:0!important;right:0!important;width:100%!important;border-left:none!important}.mm-searchfield__cancel{line-height:44px;display:block;padding-right:10px;margin-right:-100px;line-height:var(--mm-navbar-size);text-decoration:none;-webkit-transition:margin .4s ease;-o-transition:margin .4s ease;transition:margin .4s ease}.mm-searchfield__cancel-active{margin-right:0}.mm-listitem_nosubitems>.mm-listitem__btn{display:none}.mm-listitem_nosubitems>.mm-listitem__text{padding-right:10px}.mm-listitem_onlysubitems>.mm-listitem__text:not(.mm-listitem__btn){z-index:-1;pointer-events:none} \ No newline at end of file diff --git a/dist/addons/searchfield/mmenu.searchfield.js b/dist/addons/searchfield/mmenu.searchfield.js new file mode 100644 index 0000000..7d8b951 --- /dev/null +++ b/dist/addons/searchfield/mmenu.searchfield.js @@ -0,0 +1,507 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import translate from './translations/translate'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as events from '../../_modules/eventlisteners'; +import { type, extend } from '../../_modules/helpers'; +// Add the translations. +translate(); +// Add the options and configs. +Mmenu.options.searchfield = options; +Mmenu.configs.searchfield = configs; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.searchfield); + this.opts.searchfield = extend(options, Mmenu.options.searchfield); + var configs = this.conf.searchfield; + if (!options.add) { + return; + } + // Blur searchfield + this.bind('close:start', function () { + DOM.find(_this.node.menu, '.mm-searchfield').forEach(function (input) { + input.blur(); + }); + }); + this.bind('initPanel:after', function (panel) { + var searchpanel = null; + // Add the search panel + if (options.panel.add) { + searchpanel = initSearchPanel.call(_this); + } + // Add the searchfield + var addTo = null; + switch (options.addTo) { + case 'panels': + addTo = [panel]; + break; + case 'panel': + addTo = [searchpanel]; + break; + default: + if (typeof options.addTo == 'string') { + addTo = DOM.find(_this.node.menu, options.addTo); + } + else if (type(options.addTo) == 'array') { + addTo = options.addTo; + } + break; + } + addTo.forEach(function (form) { + form = initSearchfield.call(_this, form); + if (options.search && form) { + initSearching.call(_this, form); + } + }); + // Add the no-results message + if (options.noResults) { + initNoResultsMsg.call(_this, options.panel.add ? searchpanel : panel); + } + }); + // Add click behavior. + // Prevents default behavior when clicking an anchor + this.clck.push(function (anchor, args) { + if (args.inMenu) { + if (anchor.matches('.mm-searchfield__btn')) { + // Clicking the clear button + if (anchor.matches('.mm-btn_close')) { + var form = anchor.closest('.mm-searchfield'), input = DOM.find(form, 'input')[0]; + input.value = ''; + _this.search(input); + return true; + } + // Clicking the submit button + if (anchor.matches('.mm-btn_next')) { + var form = anchor.closest('form'); + if (form) { + form.submit(); + } + return true; + } + } + } + }); +} +var initSearchPanel = function () { + var options = this.opts.searchfield, configs = this.conf.searchfield; + var searchpanel = DOM.children(this.node.pnls, '.mm-panel_search')[0]; + // Only once + if (searchpanel) { + return searchpanel; + } + searchpanel = DOM.create('div.mm-panel.mm-panel_search.mm-hidden'); + if (options.panel.id) { + searchpanel.id = options.panel.id; + } + if (options.panel.title) { + searchpanel.setAttribute('data-mm-title', options.panel.title); + // searchpanel.dataset.mmTitle = options.panel.title; // IE10 has no dataset :( + } + var listview = DOM.create('ul'); + searchpanel.append(listview); + this.node.pnls.append(searchpanel); + this.initListview(listview); + this._initNavbar(searchpanel); + switch (options.panel.fx) { + case false: + break; + case 'none': + searchpanel.classList.add('mm-panel_noanimation'); + break; + default: + searchpanel.classList.add('mm-panel_fx-' + options.panel.fx); + break; + } + // Add splash content + if (options.panel.splash) { + var splash = DOM.create('div.mm-panel__content'); + splash.innerHTML = options.panel.splash; + searchpanel.append(splash); + } + searchpanel.classList.add('mm-panel'); + searchpanel.classList.add('mm-hidden'); + this.node.pnls.append(searchpanel); + return searchpanel; +}; +var initSearchfield = function (wrapper) { + var options = this.opts.searchfield, configs = this.conf.searchfield; + // No searchfield in vertical submenus + if (wrapper.parentElement.matches('.mm-listitem_vertical')) { + return null; + } + // Only one searchfield per panel + var form = DOM.find(wrapper, '.mm-searchfield')[0]; + if (form) { + return form; + } + function addAttributes(element, attr) { + if (attr) { + for (var a in attr) { + element.setAttribute(a, attr[a]); + } + } + } + var form = DOM.create((configs.form ? 'form' : 'div') + '.mm-searchfield'), field = DOM.create('div.mm-searchfield__input'), input = DOM.create('input'); + input.type = 'text'; + input.autocomplete = 'off'; + input.placeholder = this.i18n(options.placeholder); + field.append(input); + form.append(field); + wrapper.prepend(form); + // Add attributes to the input + addAttributes(input, configs.input); + // Add the clear button + if (configs.clear) { + var anchor = DOM.create('a.mm-btn.mm-btn_close.mm-searchfield__btn'); + anchor.setAttribute('href', '#'); + field.append(anchor); + } + // Add attributes and submit to the form + addAttributes(form, configs.form); + if (configs.form && configs.submit && !configs.clear) { + var anchor = DOM.create('a.mm-btn.mm-btn_next.mm-searchfield__btn'); + anchor.setAttribute('href', '#'); + field.append(anchor); + } + if (options.cancel) { + var anchor = DOM.create('a.mm-searchfield__cancel'); + anchor.setAttribute('href', '#'); + anchor.textContent = this.i18n('cancel'); + form.append(anchor); + } + return form; +}; +var initSearching = function (form) { + var _this = this; + var options = this.opts.searchfield, configs = this.conf.searchfield; + var data = {}; + // In the searchpanel. + if (form.closest('.mm-panel_search')) { + data.panels = DOM.find(this.node.pnls, '.mm-panel'); + data.noresults = [form.closest('.mm-panel')]; + // In a panel + } + else if (form.closest('.mm-panel')) { + data.panels = [form.closest('.mm-panel')]; + data.noresults = data.panels; + // Not in a panel, global + } + else { + data.panels = DOM.find(this.node.pnls, '.mm-panel'); + data.noresults = [this.node.menu]; + } + // Filter out search panel + data.panels = data.panels.filter(function (panel) { return !panel.matches('.mm-panel_search'); }); + // Filter out vertical submenus + data.panels = data.panels.filter(function (panel) { return !panel.parentElement.matches('.mm-listitem_vertical'); }); + // Find listitems and dividers. + data.listitems = []; + data.dividers = []; + data.panels.forEach(function (panel) { + var _a, _b; + (_a = data.listitems).push.apply(_a, DOM.find(panel, '.mm-listitem')); + (_b = data.dividers).push.apply(_b, DOM.find(panel, '.mm-divider')); + }); + var searchpanel = DOM.children(this.node.pnls, '.mm-panel_search')[0], input = DOM.find(form, 'input')[0], cancel = DOM.find(form, '.mm-searchfield__cancel')[0]; + input['mmSearchfield'] = data; + // Open the splash panel when focussing the input. + if (options.panel.add && options.panel.splash) { + events.off(input, 'focus.splash'); + events.on(input, 'focus.splash', function (evnt) { + _this.openPanel(searchpanel); + }); + } + if (options.cancel) { + // Show the cancel button when focussing the input. + events.off(input, 'focus.cancel'); + events.on(input, 'focus.cancel', function (evnt) { + cancel.classList.add('mm-searchfield__cancel-active'); + }); + // Close the splash panel when clicking the cancel button. + events.off(cancel, 'click.splash'); + events.on(cancel, 'click.splash', function (evnt) { + evnt.preventDefault(); + cancel.classList.remove('mm-searchfield__cancel-active'); + if (searchpanel.matches('.mm-panel_opened')) { + var parents = DOM.children(_this.node.pnls, '.mm-panel_opened-parent'); + if (parents.length) { + _this.openPanel(parents[parents.length - 1]); + } + } + }); + } + // Focus the input in the searchpanel when opening the searchpanel. + if (options.panel.add && options.addTo == 'panel') { + this.bind('openPanel:finish', function (panel) { + if (panel === searchpanel) { + input.focus(); + } + }); + } + // Search while typing. + events.off(input, 'input.search'); + events.on(input, 'input.search', function (evnt) { + switch (evnt.keyCode) { + case 9: // tab + case 16: // shift + case 17: // control + case 18: // alt + case 37: // left + case 38: // top + case 39: // right + case 40: // bottom + break; + default: + _this.search(input); + break; + } + }); + // Search initially. + this.search(input); +}; +var initNoResultsMsg = function (wrapper) { + if (!wrapper) { + return; + } + var options = this.opts.searchfield, configs = this.conf.searchfield; + // Not in a panel + if (!wrapper.closest('.mm-panel')) { + wrapper = DOM.children(this.node.pnls, '.mm-panel')[0]; + } + // Only once + if (DOM.children(wrapper, '.mm-panel__noresultsmsg').length) { + return; + } + // Add no-results message + var message = DOM.create('div.mm-panel__noresultsmsg.mm-hidden'); + message.innerHTML = this.i18n(options.noResults); + wrapper.append(message); +}; +Mmenu.prototype.search = function (input, query) { + var _this = this; + var _a; + var options = this.opts.searchfield, configs = this.conf.searchfield; + query = query || '' + input.value; + query = query.toLowerCase().trim(); + var data = input['mmSearchfield']; + var form = input.closest('.mm-searchfield'), buttons = DOM.find(form, '.mm-btn'), searchpanel = DOM.children(this.node.pnls, '.mm-panel_search')[0]; + /** The panels. */ + var panels = data.panels; + /** The "no results" messages in a cloned array. */ + var noresults = data.noresults; + /** The listitems in a cloned array. */ + var listitems = data.listitems; + /** Tje dividers in a cloned array. */ + var dividers = data.dividers; + // Reset previous results + listitems.forEach(function (listitem) { + listitem.classList.remove('mm-listitem_nosubitems'); + listitem.classList.remove('mm-listitem_onlysubitems'); + listitem.classList.remove('mm-hidden'); + }); + if (searchpanel) { + DOM.children(searchpanel, '.mm-listview')[0].innerHTML = ''; + } + panels.forEach(function (panel) { + panel.scrollTop = 0; + }); + // Search + if (query.length) { + // Initially hide all dividers. + dividers.forEach(function (divider) { + divider.classList.add('mm-hidden'); + }); + // Hide listitems that do not match. + listitems.forEach(function (listitem) { + var text = DOM.children(listitem, '.mm-listitem__text')[0]; + var add = false; + // The listitem should be shown if: + // 1) The text matches the query and + // 2a) The text is a open-button and + // 2b) the option showSubPanels is set to true. + // or 3a) The text is not an anchor and + // 3b) the option showTextItems is set to true. + // or 4) The text is an anchor. + // 1 + if (text && + DOM.text(text) + .toLowerCase() + .indexOf(query) > -1) { + // 2a + if (text.matches('.mm-listitem__btn')) { + // 2b + if (options.showSubPanels) { + add = true; + } + } + // 3a + else if (!text.matches('a')) { + // 3b + if (options.showTextItems) { + add = true; + } + } + // 4 + else { + add = true; + } + } + if (!add) { + listitem.classList.add('mm-hidden'); + } + }); + /** Whether or not the query yielded results. */ + var hasResults = listitems.filter(function (listitem) { return !listitem.matches('.mm-hidden'); }).length; + // Show all mached listitems in the search panel + if (options.panel.add) { + // Clone all matched listitems into the search panel + var allitems_1 = []; + panels.forEach(function (panel) { + var listitems = DOM.filterLI(DOM.find(panel, '.mm-listitem')); + listitems = listitems.filter(function (listitem) { return !listitem.matches('.mm-hidden'); }); + if (listitems.length) { + // Add a divider to indicate in what panel the listitems were. + if (options.panel.dividers) { + var divider = DOM.create('li.mm-divider'); + var title = DOM.find(panel, '.mm-navbar__title')[0]; + if (title) { + divider.innerHTML = title.innerHTML; + allitems_1.push(divider); + } + } + listitems.forEach(function (listitem) { + allitems_1.push(listitem.cloneNode(true)); + }); + } + }); + // Remove toggles and checks. + allitems_1.forEach(function (listitem) { + listitem + .querySelectorAll('.mm-toggle, .mm-check') + .forEach(function (element) { + element.remove(); + }); + }); + // Add to the search panel. + (_a = DOM.children(searchpanel, '.mm-listview')[0]).append.apply(_a, allitems_1); + // Open the search panel. + this.openPanel(searchpanel); + } + else { + // Also show listitems in sub-panels for matched listitems + if (options.showSubPanels) { + panels.forEach(function (panel) { + var listitems = DOM.find(panel, '.mm-listitem'); + DOM.filterLI(listitems).forEach(function (listitem) { + var child = listitem['mmChild']; + if (child) { + DOM.find(child, '.mm-listitem').forEach(function (listitem) { + listitem.classList.remove('mm-hidden'); + }); + } + }); + }); + } + // Update parent for sub-panel + // .reverse() mutates the original array, therefor we "clone" it first using [...panels]. + panels.slice().reverse().forEach(function (panel, p) { + var parent = panel['mmParent']; + if (parent) { + // The current panel has mached listitems + var listitems_1 = DOM.find(panel, '.mm-listitem'); + if (DOM.filterLI(listitems_1).length) { + // Show parent + if (parent.matches('.mm-hidden')) { + parent.classList.remove('mm-hidden'); + } + parent.classList.add('mm-listitem_onlysubitems'); + } + else if (!input.closest('.mm-panel')) { + if (panel.matches('.mm-panel_opened') || + panel.matches('.mm-panel_opened-parent')) { + // Compensate the timeout for the opening animation + setTimeout(function () { + _this.openPanel(parent.closest('.mm-panel')); + }, (p + 1) * (_this.conf.openingInterval * 1.5)); + } + parent.classList.add('mm-listitem_nosubitems'); + } + } + }); + // Show parent panels of vertical submenus + panels.forEach(function (panel) { + var listitems = DOM.find(panel, '.mm-listitem'); + DOM.filterLI(listitems).forEach(function (listitem) { + DOM.parents(listitem, '.mm-listitem_vertical').forEach(function (parent) { + if (parent.matches('.mm-hidden')) { + parent.classList.remove('mm-hidden'); + parent.classList.add('mm-listitem_onlysubitems'); + } + }); + }); + }); + // Show first preceeding divider of parent + panels.forEach(function (panel) { + var listitems = DOM.find(panel, '.mm-listitem'); + DOM.filterLI(listitems).forEach(function (listitem) { + var divider = DOM.prevAll(listitem, '.mm-divider')[0]; + if (divider) { + divider.classList.remove('mm-hidden'); + } + }); + }); + } + // Show submit / clear button + buttons.forEach(function (button) { return button.classList.remove('mm-hidden'); }); + // Show/hide no results message + noresults.forEach(function (wrapper) { + DOM.find(wrapper, '.mm-panel__noresultsmsg').forEach(function (message) { + return message.classList[hasResults ? 'add' : 'remove']('mm-hidden'); + }); + }); + if (options.panel.add) { + // Hide splash + if (options.panel.splash) { + DOM.find(searchpanel, '.mm-panel__content').forEach(function (splash) { + return splash.classList.add('mm-hidden'); + }); + } + // Re-show original listitems when in search panel + listitems.forEach(function (listitem) { + return listitem.classList.remove('mm-hidden'); + }); + dividers.forEach(function (divider) { return divider.classList.remove('mm-hidden'); }); + } + // Don't search + } + else { + // Show all items + listitems.forEach(function (listitem) { return listitem.classList.remove('mm-hidden'); }); + dividers.forEach(function (divider) { return divider.classList.remove('mm-hidden'); }); + // Hide submit / clear button + buttons.forEach(function (button) { return button.classList.add('mm-hidden'); }); + // Hide no results message + noresults.forEach(function (wrapper) { + DOM.find(wrapper, '.mm-panel__noresultsmsg').forEach(function (message) { + return message.classList.add('mm-hidden'); + }); + }); + if (options.panel.add) { + // Show splash + if (options.panel.splash) { + DOM.find(searchpanel, '.mm-panel__content').forEach(function (splash) { + return splash.classList.remove('mm-hidden'); + }); + // Close panel + } + else if (!input.closest('.mm-panel_search')) { + var opened = DOM.children(this.node.pnls, '.mm-panel_opened-parent'); + this.openPanel(opened.slice(-1)[0]); + } + } + } + // Update for other addons + this.trigger('updateListview'); +}; diff --git a/dist/addons/searchfield/translations/de.js b/dist/addons/searchfield/translations/de.js new file mode 100644 index 0000000..64bb721 --- /dev/null +++ b/dist/addons/searchfield/translations/de.js @@ -0,0 +1,5 @@ +export default { + Search: 'Suche', + 'No results found.': 'Keine Ergebnisse gefunden.', + cancel: 'beenden' +}; diff --git a/dist/addons/searchfield/translations/fa.js b/dist/addons/searchfield/translations/fa.js new file mode 100644 index 0000000..c13a6e0 --- /dev/null +++ b/dist/addons/searchfield/translations/fa.js @@ -0,0 +1,5 @@ +export default { + Search: 'جستجو', + 'No results found.': 'نتیجه‌ای یافت نشد.', + cancel: 'انصراف' +}; diff --git a/dist/addons/searchfield/translations/nl.js b/dist/addons/searchfield/translations/nl.js new file mode 100644 index 0000000..440ec0e --- /dev/null +++ b/dist/addons/searchfield/translations/nl.js @@ -0,0 +1,5 @@ +export default { + Search: 'Zoeken', + 'No results found.': 'Geen resultaten gevonden.', + cancel: 'annuleren' +}; diff --git a/dist/addons/searchfield/translations/ru.js b/dist/addons/searchfield/translations/ru.js new file mode 100644 index 0000000..47438bd --- /dev/null +++ b/dist/addons/searchfield/translations/ru.js @@ -0,0 +1,5 @@ +export default { + Search: 'Найти', + 'No results found.': 'Ничего не найдено.', + cancel: 'отменить' +}; diff --git a/dist/addons/searchfield/translations/translate.js b/dist/addons/searchfield/translations/translate.js new file mode 100644 index 0000000..42e19b8 --- /dev/null +++ b/dist/addons/searchfield/translations/translate.js @@ -0,0 +1,11 @@ +import { add } from '../../../_modules/i18n'; +import nl from './nl'; +import fa from './fa'; +import de from './de'; +import ru from './ru'; +export default function () { + add(nl, 'nl'); + add(fa, 'fa'); + add(de, 'de'); + add(ru, 'ru'); +} diff --git a/dist/addons/sectionindexer/_options.js b/dist/addons/sectionindexer/_options.js new file mode 100644 index 0000000..2cd82c0 --- /dev/null +++ b/dist/addons/sectionindexer/_options.js @@ -0,0 +1,23 @@ +var options = { + add: false, + addTo: 'panels' +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + add: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/addons/sectionindexer/mmenu.sectionindexer.css b/dist/addons/sectionindexer/mmenu.sectionindexer.css new file mode 100644 index 0000000..c4a7a92 --- /dev/null +++ b/dist/addons/sectionindexer/mmenu.sectionindexer.css @@ -0,0 +1 @@ +.mm-sectionindexer{background:inherit;text-align:center;font-size:12px;-webkit-box-sizing:border-box;box-sizing:border-box;width:20px;position:absolute;top:0;bottom:0;right:-20px;z-index:5;-webkit-transition:right .4s ease;-o-transition:right .4s ease;transition:right .4s ease;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;justify-content:space-evenly}.mm-sectionindexer a{color:rgba(0,0,0,.3);color:var(--mm-color-text-dimmed);line-height:1;text-decoration:none;display:block}.mm-sectionindexer~.mm-panel{padding-right:0}.mm-sectionindexer_active{right:0}.mm-sectionindexer_active~.mm-panel{padding-right:20px} \ No newline at end of file diff --git a/dist/addons/sectionindexer/mmenu.sectionindexer.js b/dist/addons/sectionindexer/mmenu.sectionindexer.js new file mode 100644 index 0000000..71f1937 --- /dev/null +++ b/dist/addons/sectionindexer/mmenu.sectionindexer.js @@ -0,0 +1,70 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as support from '../../_modules/support'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.sectionIndexer = options; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.sectionIndexer); + this.opts.sectionIndexer = extend(options, Mmenu.options.sectionIndexer); + if (!options.add) { + return; + } + this.bind('initPanels:after', function () { + // Add the indexer, only if it does not allready excists + if (!_this.node.indx) { + var buttons_1 = ''; + 'abcdefghijklmnopqrstuvwxyz'.split('').forEach(function (letter) { + buttons_1 += '' + letter + ''; + }); + var indexer = DOM.create('div.mm-sectionindexer'); + indexer.innerHTML = buttons_1; + _this.node.pnls.prepend(indexer); + _this.node.indx = indexer; + // Prevent default behavior when clicking an anchor + _this.node.indx.addEventListener('click', function (evnt) { + var anchor = evnt.target; + if (anchor.matches('a')) { + evnt.preventDefault(); + } + }); + // Scroll onMouseOver / onTouchStart + var mouseOverEvent = function (evnt) { + if (!evnt.target.matches('a')) { + return; + } + var letter = evnt.target.textContent, panel = DOM.children(_this.node.pnls, '.mm-panel_opened')[0]; + var newTop = -1, oldTop = panel.scrollTop; + panel.scrollTop = 0; + DOM.find(panel, '.mm-divider') + .filter(function (divider) { return !divider.matches('.mm-hidden'); }) + .forEach(function (divider) { + if (newTop < 0 && + letter == + divider.textContent + .trim() + .slice(0, 1) + .toLowerCase()) { + newTop = divider.offsetTop; + } + }); + panel.scrollTop = newTop > -1 ? newTop : oldTop; + }; + if (support.touch) { + _this.node.indx.addEventListener('touchstart', mouseOverEvent); + _this.node.indx.addEventListener('touchmove', mouseOverEvent); + } + else { + _this.node.indx.addEventListener('mouseover', mouseOverEvent); + } + } + // Show or hide the indexer + _this.bind('openPanel:start', function (panel) { + var active = DOM.find(panel, '.mm-divider').filter(function (divider) { return !divider.matches('.mm-hidden'); }).length; + _this.node.indx.classList[active ? 'add' : 'remove']('mm-sectionindexer_active'); + }); + }); +} diff --git a/dist/addons/setselected/_options.js b/dist/addons/setselected/_options.js new file mode 100644 index 0000000..2fe3937 --- /dev/null +++ b/dist/addons/setselected/_options.js @@ -0,0 +1,25 @@ +var options = { + current: true, + hover: false, + parent: false +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + hover: options, + parent: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/addons/setselected/mmenu.setselected.css b/dist/addons/setselected/mmenu.setselected.css new file mode 100644 index 0000000..ba0c57f --- /dev/null +++ b/dist/addons/setselected/mmenu.setselected.css @@ -0,0 +1 @@ +.mm-menu_selected-hover .mm-listitem__btn,.mm-menu_selected-hover .mm-listitem__text,.mm-menu_selected-parent .mm-listitem__btn,.mm-menu_selected-parent .mm-listitem__text{-webkit-transition:background-color .4s ease;-o-transition:background-color .4s ease;transition:background-color .4s ease}.mm-menu_selected-hover .mm-listview:hover>.mm-listitem_selected>.mm-listitem__text{background:0 0}.mm-menu_selected-hover .mm-listitem__btn:hover,.mm-menu_selected-hover .mm-listitem__text:hover{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)}.mm-menu_selected-parent .mm-panel_opened-parent .mm-listitem:not(.mm-listitem_selected-parent)>.mm-listitem__text{background:0 0}.mm-menu_selected-parent .mm-listitem_selected-parent>.mm-listitem__btn,.mm-menu_selected-parent .mm-listitem_selected-parent>.mm-listitem__text{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)} \ No newline at end of file diff --git a/dist/addons/setselected/mmenu.setselected.js b/dist/addons/setselected/mmenu.setselected.js new file mode 100644 index 0000000..eb82c90 --- /dev/null +++ b/dist/addons/setselected/mmenu.setselected.js @@ -0,0 +1,66 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.setSelected = options; +export default function () { + var _this = this; + var options = extendShorthandOptions(this.opts.setSelected); + this.opts.setSelected = extend(options, Mmenu.options.setSelected); + // Find current by URL + if (options.current == 'detect') { + var findCurrent_1 = function (url) { + url = url.split('?')[0].split('#')[0]; + var anchor = _this.node.menu.querySelector('a[href="' + url + '"], a[href="' + url + '/"]'); + if (anchor) { + _this.setSelected(anchor.parentElement); + } + else { + var arr = url.split('/').slice(0, -1); + if (arr.length) { + findCurrent_1(arr.join('/')); + } + } + }; + this.bind('initMenu:after', function () { + findCurrent_1.call(_this, window.location.href); + }); + // Remove current selected item + } + else if (!options.current) { + this.bind('initListview:after', function (listview) { + DOM.children(listview, '.mm-listitem_selected').forEach(function (listitem) { + listitem.classList.remove('mm-listitem_selected'); + }); + }); + } + // Add :hover effect on items + if (options.hover) { + this.bind('initMenu:after', function () { + _this.node.menu.classList.add('mm-menu_selected-hover'); + }); + } + // Set parent item selected for submenus + if (options.parent) { + this.bind('openPanel:finish', function (panel) { + // Remove all + DOM.find(_this.node.pnls, '.mm-listitem_selected-parent').forEach(function (listitem) { + listitem.classList.remove('mm-listitem_selected-parent'); + }); + // Move up the DOM tree + var parent = panel['mmParent']; + while (parent) { + if (!parent.matches('.mm-listitem_vertical')) { + parent.classList.add('mm-listitem_selected-parent'); + } + parent = parent.closest('.mm-panel'); + parent = parent['mmParent']; + } + }); + this.bind('initMenu:after', function () { + _this.node.menu.classList.add('mm-menu_selected-parent'); + }); + } +} diff --git a/dist/addons/sidebar/_options.js b/dist/addons/sidebar/_options.js new file mode 100644 index 0000000..f45f9d7 --- /dev/null +++ b/dist/addons/sidebar/_options.js @@ -0,0 +1,62 @@ +var options = { + collapsed: { + use: false, + blockMenu: true, + hideDivider: false, + hideNavbar: true + }, + expanded: { + use: false, + initial: 'open' + } +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'string' || + (typeof options == 'boolean' && options) || + typeof options == 'number') { + options = { + expanded: options + }; + } + if (typeof options != 'object') { + options = {}; + } + // Extend collapsed shorthand options. + if (typeof options.collapsed == 'boolean' && options.collapsed) { + options.collapsed = { + use: true + }; + } + if (typeof options.collapsed == 'string' || + typeof options.collapsed == 'number') { + options.collapsed = { + use: options.collapsed + }; + } + if (typeof options.collapsed != 'object') { + options.collapsed = {}; + } + // Extend expanded shorthand options. + if (typeof options.expanded == 'boolean' && options.expanded) { + options.expanded = { + use: true + }; + } + if (typeof options.expanded == 'string' || + typeof options.expanded == 'number') { + options.expanded = { + use: options.expanded + }; + } + if (typeof options.expanded != 'object') { + options.expanded = {}; + } + return options; +} diff --git a/dist/addons/sidebar/mmenu.sidebar.css b/dist/addons/sidebar/mmenu.sidebar.css new file mode 100644 index 0000000..550ae42 --- /dev/null +++ b/dist/addons/sidebar/mmenu.sidebar.css @@ -0,0 +1 @@ +:root{--mm-sidebar-collapsed-size:50px;--mm-sidebar-expanded-size:440px}.mm-wrapper_sidebar-collapsed body,.mm-wrapper_sidebar-expanded body{position:relative}.mm-wrapper_sidebar-collapsed .mm-slideout,.mm-wrapper_sidebar-expanded .mm-slideout{-webkit-transition-property:width,-webkit-transform;transition-property:width,-webkit-transform;-o-transition-property:width,transform;transition-property:width,transform;transition-property:width,transform,-webkit-transform}.mm-wrapper_sidebar-collapsed .mm-page,.mm-wrapper_sidebar-expanded .mm-page{background:inherit;-webkit-box-sizing:border-box;box-sizing:border-box;min-height:100vh}.mm-wrapper_sidebar-collapsed .mm-menu_sidebar-collapsed,.mm-wrapper_sidebar-expanded .mm-menu_sidebar-expanded{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;top:0!important;right:auto!important;bottom:0!important;left:0!important}.mm-wrapper_sidebar-collapsed .mm-slideout{width:calc(100% - 50px);-webkit-transform:translate3d(50px,0,0);transform:translate3d(50px,0,0);width:calc(100% - var(--mm-sidebar-collapsed-size));-webkit-transform:translate3d(var(--mm-sidebar-collapsed-size),0,0);transform:translate3d(var(--mm-sidebar-collapsed-size),0,0)}.mm-wrapper_sidebar-collapsed:not(.mm-wrapper_opening) .mm-menu_hidedivider .mm-divider,.mm-wrapper_sidebar-collapsed:not(.mm-wrapper_opening) .mm-menu_hidenavbar .mm-navbar{opacity:0}.mm-wrapper_sidebar-expanded .mm-menu_sidebar-expanded{width:440px;width:var(--mm-sidebar-expanded-size);min-width:0!important;max-width:100000px!important;border-right-width:1px;border-right-style:solid}.mm-wrapper_sidebar-expanded .mm-menu_sidebar-expanded.mm-menu_pageshadow:after{content:none;display:none}.mm-wrapper_sidebar-expanded.mm-wrapper_blocking,.mm-wrapper_sidebar-expanded.mm-wrapper_blocking body{overflow:visible}.mm-wrapper_sidebar-expanded .mm-wrapper__blocker{display:none!important}.mm-wrapper_sidebar-expanded:not(.mm-wrapper_sidebar-closed) .mm-menu_sidebar-expanded.mm-menu_opened~.mm-slideout{width:calc(100% - 440px);-webkit-transform:translate3d(440px,0,0);transform:translate3d(440px,0,0);width:calc(100% - var(--mm-sidebar-expanded-size));-webkit-transform:translate3d(var(--mm-sidebar-expanded-size),0,0);transform:translate3d(var(--mm-sidebar-expanded-size),0,0)}.mm-menu__blocker{background:rgba(3,2,1,0);display:block;position:absolute;top:0;right:0;bottom:0;left:0;z-index:3}.mm-menu_opened .mm-menu__blocker{display:none}[dir=rtl].mm-wrapper_sidebar-collapsed .mm-slideout{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}[dir=rtl].mm-wrapper_sidebar-expanded .mm-slideout{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}[dir=rtl].mm-wrapper_sidebar-expanded:not(.mm-wrapper_sidebar-closed) .mm-menu_sidebar-expanded.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)} \ No newline at end of file diff --git a/dist/addons/sidebar/mmenu.sidebar.js b/dist/addons/sidebar/mmenu.sidebar.js new file mode 100644 index 0000000..45ad4bc --- /dev/null +++ b/dist/addons/sidebar/mmenu.sidebar.js @@ -0,0 +1,117 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as media from '../../_modules/matchmedia'; +import { extend } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.sidebar = options; +export default function () { + var _this = this; + if (!this.opts.offCanvas) { + return; + } + var options = extendShorthandOptions(this.opts.sidebar); + this.opts.sidebar = extend(options, Mmenu.options.sidebar); + // Collapsed + if (options.collapsed.use) { + // Make the menu collapsable. + this.bind('initMenu:after', function () { + _this.node.menu.classList.add('mm-menu_sidebar-collapsed'); + if (options.collapsed.blockMenu && + _this.opts.offCanvas && + !DOM.children(_this.node.menu, '.mm-menu__blocker')[0]) { + var anchor = DOM.create('a.mm-menu__blocker'); + anchor.setAttribute('href', '#' + _this.node.menu.id); + _this.node.menu.prepend(anchor); + } + if (options.collapsed.hideNavbar) { + _this.node.menu.classList.add('mm-menu_hidenavbar'); + } + if (options.collapsed.hideDivider) { + _this.node.menu.classList.add('mm-menu_hidedivider'); + } + }); + // En-/disable the collapsed sidebar. + var enable = function () { + _this.node.wrpr.classList.add('mm-wrapper_sidebar-collapsed'); + }; + var disable = function () { + _this.node.wrpr.classList.remove('mm-wrapper_sidebar-collapsed'); + }; + if (typeof options.collapsed.use == 'boolean') { + this.bind('initMenu:after', enable); + } + else { + media.add(options.collapsed.use, enable, disable); + } + } + // Expanded + if (options.expanded.use) { + // Make the menu expandable + this.bind('initMenu:after', function () { + _this.node.menu.classList.add('mm-menu_sidebar-expanded'); + }); + // En-/disable the expanded sidebar. + var enable = function () { + _this.node.wrpr.classList.add('mm-wrapper_sidebar-expanded'); + if (!_this.node.wrpr.matches('.mm-wrapper_sidebar-closed')) { + _this.open(); + } + }; + var disable = function () { + _this.node.wrpr.classList.remove('mm-wrapper_sidebar-expanded'); + _this.close(); + }; + if (typeof options.expanded.use == 'boolean') { + this.bind('initMenu:after', enable); + } + else { + media.add(options.expanded.use, enable, disable); + } + // Manually en-/disable the expanded sidebar (open / close the menu) + this.bind('close:start', function () { + if (_this.node.wrpr.matches('.mm-wrapper_sidebar-expanded')) { + _this.node.wrpr.classList.add('mm-wrapper_sidebar-closed'); + if (options.expanded.initial == 'remember') { + window.localStorage.setItem('mmenuExpandedState', 'closed'); + } + } + }); + this.bind('open:start', function () { + if (_this.node.wrpr.matches('.mm-wrapper_sidebar-expanded')) { + _this.node.wrpr.classList.remove('mm-wrapper_sidebar-closed'); + if (options.expanded.initial == 'remember') { + window.localStorage.setItem('mmenuExpandedState', 'open'); + } + } + }); + // Set the initial state + var initialState = options.expanded.initial; + if (options.expanded.initial == 'remember') { + var state = window.localStorage.getItem('mmenuExpandedState'); + switch (state) { + case 'open': + case 'closed': + initialState = state; + break; + } + } + if (initialState == 'closed') { + this.bind('initMenu:after', function () { + _this.node.wrpr.classList.add('mm-wrapper_sidebar-closed'); + }); + } + // Add click behavior. + // Prevents default behavior when clicking an anchor + this.clck.push(function (anchor, args) { + if (args.inMenu && args.inListview) { + if (_this.node.wrpr.matches('.mm-wrapper_sidebar-expanded')) { + return { + close: options.expanded.initial == 'closed' + }; + } + } + }); + } +} diff --git a/dist/addons/toggles/mmenu.toggles.css b/dist/addons/toggles/mmenu.toggles.css new file mode 100644 index 0000000..3d647cf --- /dev/null +++ b/dist/addons/toggles/mmenu.toggles.css @@ -0,0 +1 @@ +input.mm-toggle{margin-top:5px;background:rgba(0,0,0,.1);display:inline-block;min-width:58px;width:58px;height:34px;margin:0 10px;margin-top:calc((var(--mm-listitem-size) - 34px)/ 2);border:none!important;background:var(--mm-color-border);border-radius:34px;-webkit-appearance:none!important;-moz-appearance:none!important;appearance:none!important;cursor:pointer;-webkit-transition:background-color .2s ease;-o-transition:background-color .2s ease;transition:background-color .2s ease}input.mm-toggle:before{background:#f3f3f3}input.mm-toggle:before{content:'';display:block;width:32px;height:32px;margin:1px;border-radius:34px;background:var(--mm-color-background);-webkit-transition:-webkit-transform .2s ease;transition:-webkit-transform .2s ease;-o-transition:transform .2s ease;transition:transform .2s ease;transition:transform .2s ease,-webkit-transform .2s ease}input.mm-toggle:checked{background:#4bd963}input.mm-toggle:checked:before{-webkit-transform:translateX(24px);-ms-transform:translateX(24px);transform:translateX(24px)}input.mm-check{margin-top:2px;-webkit-appearance:none!important;-moz-appearance:none!important;appearance:none!important;border:none!important;background:0 0!important;cursor:pointer;display:inline-block;width:40px;height:40px;margin:0 10px;margin-top:calc((var(--mm-listitem-size) - 40px)/ 2)}input.mm-check:before{content:'';display:block;width:40%;height:20%;margin:25% 0 0 20%;border-left:3px solid;border-bottom:3px solid;border-color:var(--mm-color-text);opacity:.3;-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transition:opacity .2s ease;-o-transition:opacity .2s ease;transition:opacity .2s ease}input.mm-check:checked:before{opacity:1}[dir=rtl] input.mm-toggle:checked~label.mm-toggle:before{float:left} \ No newline at end of file diff --git a/dist/addons/toggles/mmenu.toggles.js b/dist/addons/toggles/mmenu.toggles.js new file mode 100644 index 0000000..03cb52b --- /dev/null +++ b/dist/addons/toggles/mmenu.toggles.js @@ -0,0 +1,17 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; +// Add the classnames. +Mmenu.configs.classNames.toggles = { + toggle: 'Toggle', + check: 'Check' +}; +export default function () { + var _this = this; + this.bind('initPanel:after', function (panel) { + // Refactor toggle classes + DOM.find(panel, 'input').forEach(function (input) { + DOM.reClass(input, _this.conf.classNames.toggles.toggle, 'mm-toggle'); + DOM.reClass(input, _this.conf.classNames.toggles.check, 'mm-check'); + }); + }); +} diff --git a/dist/core/offcanvas/_configs.js b/dist/core/offcanvas/_configs.js new file mode 100644 index 0000000..7e4e965 --- /dev/null +++ b/dist/core/offcanvas/_configs.js @@ -0,0 +1,13 @@ +var configs = { + clone: false, + menu: { + insertMethod: 'prepend', + insertSelector: 'body' + }, + page: { + nodetype: 'div', + selector: null, + noSelector: [] + } +}; +export default configs; diff --git a/dist/core/offcanvas/_options.js b/dist/core/offcanvas/_options.js new file mode 100644 index 0000000..1212cff --- /dev/null +++ b/dist/core/offcanvas/_options.js @@ -0,0 +1,18 @@ +var options = { + blockUI: true, + moveBackground: true +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/core/offcanvas/mmenu.offcanvas.css b/dist/core/offcanvas/mmenu.offcanvas.css new file mode 100644 index 0000000..791bb7f --- /dev/null +++ b/dist/core/offcanvas/mmenu.offcanvas.css @@ -0,0 +1 @@ +.mm-page{-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.mm-slideout{-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;-o-transition:transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease;z-index:1}.mm-wrapper_opened{overflow-x:hidden;position:relative}.mm-wrapper_opened .mm-page{min-height:100vh}.mm-wrapper_background .mm-page{background:inherit}.mm-menu_offcanvas{position:fixed;right:auto;z-index:0}.mm-menu_offcanvas:not(.mm-menu_opened){display:none}.mm-menu_offcanvas{width:80%;min-width:240px;max-width:440px}.mm-wrapper_opening .mm-menu_offcanvas~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_offcanvas~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:550px){.mm-wrapper_opening .mm-menu_offcanvas~.mm-slideout{-webkit-transform:translate3d(440px,0,0);transform:translate3d(440px,0,0)}}.mm-wrapper__blocker{background:rgba(3,2,1,0);overflow:hidden;display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:2}.mm-wrapper_blocking{overflow:hidden}.mm-wrapper_blocking body{overflow:hidden}.mm-wrapper_blocking .mm-wrapper__blocker{display:block} \ No newline at end of file diff --git a/dist/core/offcanvas/mmenu.offcanvas.js b/dist/core/offcanvas/mmenu.offcanvas.js new file mode 100644 index 0000000..4fdc508 --- /dev/null +++ b/dist/core/offcanvas/mmenu.offcanvas.js @@ -0,0 +1,331 @@ +import Mmenu from './../oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as events from '../../_modules/eventlisteners'; +import { extend, transitionend, uniqueId, originalId } from '../../_modules/helpers'; +// Add the options and configs. +Mmenu.options.offCanvas = options; +Mmenu.configs.offCanvas = configs; +export default function () { + var _this = this; + if (!this.opts.offCanvas) { + return; + } + var options = extendShorthandOptions(this.opts.offCanvas); + this.opts.offCanvas = extend(options, Mmenu.options.offCanvas); + var configs = this.conf.offCanvas; + // Add methods to the API. + this._api.push('open', 'close', 'setPage'); + // Setup the menu. + this.vars.opened = false; + // Add off-canvas behavior. + this.bind('initMenu:before', function () { + // Clone if needed. + if (configs.clone) { + // Clone the original menu and store it. + _this.node.menu = _this.node.menu.cloneNode(true); + // Prefix all ID's in the cloned menu. + if (_this.node.menu.id) { + _this.node.menu.id = 'mm-' + _this.node.menu.id; + } + DOM.find(_this.node.menu, '[id]').forEach(function (elem) { + elem.id = 'mm-' + elem.id; + }); + } + _this.node.wrpr = document.body; + // Prepend to the + document + .querySelector(configs.menu.insertSelector)[configs.menu.insertMethod](_this.node.menu); + }); + this.bind('initMenu:after', function () { + // Setup the UI blocker. + initBlocker.call(_this); + // Setup the page. + _this.setPage(Mmenu.node.page); + // Setup window events. + initWindow.call(_this); + // Setup the menu. + _this.node.menu.classList.add('mm-menu_offcanvas'); + // Open if url hash equals menu id (usefull when user clicks the hamburger icon before the menu is created) + var hash = window.location.hash; + if (hash) { + var id = originalId(_this.node.menu.id); + if (id && id == hash.slice(1)) { + setTimeout(function () { + _this.open(); + }, 1000); + } + } + }); + // Sync the blocker to target the page. + this.bind('setPage:after', function (page) { + if (Mmenu.node.blck) { + DOM.children(Mmenu.node.blck, 'a').forEach(function (anchor) { + anchor.setAttribute('href', '#' + page.id); + }); + } + }); + // Add screenreader / aria support + this.bind('open:start:sr-aria', function () { + Mmenu.sr_aria(_this.node.menu, 'hidden', false); + }); + this.bind('close:finish:sr-aria', function () { + Mmenu.sr_aria(_this.node.menu, 'hidden', true); + }); + this.bind('initMenu:after:sr-aria', function () { + Mmenu.sr_aria(_this.node.menu, 'hidden', true); + }); + // Add screenreader / text support + this.bind('initBlocker:after:sr-text', function () { + DOM.children(Mmenu.node.blck, 'a').forEach(function (anchor) { + anchor.innerHTML = Mmenu.sr_text(_this.i18n(_this.conf.screenReader.text.closeMenu)); + }); + }); + // Add click behavior. + // Prevents default behavior when clicking an anchor + this.clck.push(function (anchor, args) { + // Open menu if the clicked anchor links to the menu + var id = originalId(_this.node.menu.id); + if (id) { + if (anchor.matches('[href="#' + id + '"]')) { + // Opening this menu from within this menu + // -> Open menu + if (args.inMenu) { + _this.open(); + return true; + } + // Opening this menu from within a second menu + // -> Close the second menu before opening this menu + var menu = anchor.closest('.mm-menu'); + if (menu) { + var api = menu['mmApi']; + if (api && api.close) { + api.close(); + transitionend(menu, function () { + _this.open(); + }, _this.conf.transitionDuration); + return true; + } + } + // Opening this menu + _this.open(); + return true; + } + } + // Close menu + id = Mmenu.node.page.id; + if (id) { + if (anchor.matches('[href="#' + id + '"]')) { + _this.close(); + return true; + } + } + return; + }); +} +/** + * Open the menu. + */ +Mmenu.prototype.open = function () { + var _this = this; + // Invoke "before" hook. + this.trigger('open:before'); + if (this.vars.opened) { + return; + } + this._openSetup(); + // Without the timeout, the animation won't work because the menu had display: none; + setTimeout(function () { + _this._openStart(); + }, this.conf.openingInterval); + // Invoke "after" hook. + this.trigger('open:after'); +}; +Mmenu.prototype._openSetup = function () { + var _this = this; + var options = this.opts.offCanvas; + // Close other menus + this.closeAllOthers(); + // Store style and position + Mmenu.node.page['mmStyle'] = Mmenu.node.page.getAttribute('style') || ''; + // Trigger window-resize to measure height + events.trigger(window, 'resize.page', { force: true }); + var clsn = ['mm-wrapper_opened']; + // Add options + if (options.blockUI) { + clsn.push('mm-wrapper_blocking'); + } + if (options.blockUI == 'modal') { + clsn.push('mm-wrapper_modal'); + } + if (options.moveBackground) { + clsn.push('mm-wrapper_background'); + } + // IE11: + clsn.forEach(function (classname) { + _this.node.wrpr.classList.add(classname); + }); + // Better browsers: + // this.node.wrpr.classList.add(...clsn); + // Open + // Without the timeout, the animation won't work because the menu had display: none; + setTimeout(function () { + _this.vars.opened = true; + }, this.conf.openingInterval); + this.node.menu.classList.add('mm-menu_opened'); +}; +/** + * Finish opening the menu. + */ +Mmenu.prototype._openStart = function () { + var _this = this; + // Callback when the page finishes opening. + transitionend(Mmenu.node.page, function () { + _this.trigger('open:finish'); + }, this.conf.transitionDuration); + // Opening + this.trigger('open:start'); + this.node.wrpr.classList.add('mm-wrapper_opening'); +}; +Mmenu.prototype.close = function () { + var _this = this; + // Invoke "before" hook. + this.trigger('close:before'); + if (!this.vars.opened) { + return; + } + // Callback when the page finishes closing. + transitionend(Mmenu.node.page, function () { + _this.node.menu.classList.remove('mm-menu_opened'); + var classnames = [ + 'mm-wrapper_opened', + 'mm-wrapper_blocking', + 'mm-wrapper_modal', + 'mm-wrapper_background' + ]; + // IE11: + classnames.forEach(function (classname) { + _this.node.wrpr.classList.remove(classname); + }); + // Better browsers: + // this.node.wrpr.classList.remove(...classnames); + // Restore style and position + Mmenu.node.page.setAttribute('style', Mmenu.node.page['mmStyle']); + _this.vars.opened = false; + _this.trigger('close:finish'); + }, this.conf.transitionDuration); + // Closing + this.trigger('close:start'); + this.node.wrpr.classList.remove('mm-wrapper_opening'); + // Invoke "after" hook. + this.trigger('close:after'); +}; +/** + * Close all other menus. + */ +Mmenu.prototype.closeAllOthers = function () { + var _this = this; + DOM.find(document.body, '.mm-menu_offcanvas').forEach(function (menu) { + if (menu !== _this.node.menu) { + var api = menu['mmApi']; + if (api && api.close) { + api.close(); + } + } + }); +}; +/** + * Set the "page" node. + * + * @param {HTMLElement} page Element to set as the page. + */ +Mmenu.prototype.setPage = function (page) { + // Invoke "before" hook. + this.trigger('setPage:before', [page]); + var configs = this.conf.offCanvas; + // If no page was specified, find it. + if (!page) { + /** Array of elements that are / could be "the page". */ + var pages = typeof configs.page.selector == 'string' + ? DOM.find(document.body, configs.page.selector) + : DOM.children(document.body, configs.page.nodetype); + // Filter out elements that are absolutely not "the page". + pages = pages.filter(function (page) { return !page.matches('.mm-menu, .mm-wrapper__blocker'); }); + // Filter out elements that are configured to not be "the page". + if (configs.page.noSelector.length) { + pages = pages.filter(function (page) { return !page.matches(configs.page.noSelector.join(', ')); }); + } + // Wrap multiple pages in a single element. + if (pages.length > 1) { + var wrapper_1 = DOM.create('div'); + pages[0].before(wrapper_1); + pages.forEach(function (page) { + wrapper_1.append(page); + }); + pages = [wrapper_1]; + } + page = pages[0]; + } + page.classList.add('mm-page'); + page.classList.add('mm-slideout'); + page.id = page.id || uniqueId(); + Mmenu.node.page = page; + // Invoke "after" hook. + this.trigger('setPage:after', [page]); +}; +/** + * Initialize the window. + */ +var initWindow = function () { + var _this = this; + // Prevent tabbing + // Because when tabbing outside the menu, the element that gains focus will be centered on the screen. + // In other words: The menu would move out of view. + events.off(document.body, 'keydown.tabguard'); + events.on(document.body, 'keydown.tabguard', function (evnt) { + if (evnt.keyCode == 9) { + if (_this.node.wrpr.matches('.mm-wrapper_opened')) { + evnt.preventDefault(); + } + } + }); +}; +/** + * Initialize "blocker" node + */ +var initBlocker = function () { + var _this = this; + // Invoke "before" hook. + this.trigger('initBlocker:before'); + var options = this.opts.offCanvas, configs = this.conf.offCanvas; + if (!options.blockUI) { + return; + } + // Create the blocker node. + if (!Mmenu.node.blck) { + var blck = DOM.create('div.mm-wrapper__blocker.mm-slideout'); + blck.innerHTML = ''; + // Append the blocker node to the body. + document.querySelector(configs.menu.insertSelector).append(blck); + // Store the blocker node. + Mmenu.node.blck = blck; + } + // Close the menu when + // 1) clicking, + // 2) touching or + // 3) dragging the blocker node. + var closeMenu = function (evnt) { + evnt.preventDefault(); + evnt.stopPropagation(); + if (!_this.node.wrpr.matches('.mm-wrapper_modal')) { + _this.close(); + } + }; + Mmenu.node.blck.addEventListener('mousedown', closeMenu); // 1 + Mmenu.node.blck.addEventListener('touchstart', closeMenu); // 2 + Mmenu.node.blck.addEventListener('touchmove', closeMenu); // 3 + // Invoke "after" hook. + this.trigger('initBlocker:after'); +}; diff --git a/dist/core/oncanvas/_configs.js b/dist/core/oncanvas/_configs.js new file mode 100644 index 0000000..5c1ff12 --- /dev/null +++ b/dist/core/oncanvas/_configs.js @@ -0,0 +1,15 @@ +var configs = { + classNames: { + inset: 'Inset', + nolistview: 'NoListview', + nopanel: 'NoPanel', + panel: 'Panel', + selected: 'Selected', + vertical: 'Vertical' + }, + language: null, + openingInterval: 25, + panelNodetype: ['ul', 'ol', 'div'], + transitionDuration: 400 +}; +export default configs; diff --git a/dist/core/oncanvas/_options.js b/dist/core/oncanvas/_options.js new file mode 100644 index 0000000..2c671c4 --- /dev/null +++ b/dist/core/oncanvas/_options.js @@ -0,0 +1,18 @@ +var options = { + hooks: {}, + extensions: [], + wrappers: [], + navbar: { + add: true, + sticky: true, + title: 'Menu', + titleLink: 'parent' + }, + onClick: { + close: null, + preventDefault: null, + setSelected: true + }, + slidingSubmenus: true +}; +export default options; diff --git a/dist/core/oncanvas/mmenu.oncanvas.css b/dist/core/oncanvas/mmenu.oncanvas.css new file mode 100644 index 0000000..b0163ff --- /dev/null +++ b/dist/core/oncanvas/mmenu.oncanvas.css @@ -0,0 +1 @@ +:root{--mm-line-height:20px;--mm-listitem-size:44px;--mm-navbar-size:44px;--mm-offset-top:0;--mm-offset-right:0;--mm-offset-bottom:0;--mm-offset-left:0;--mm-color-border:rgba(0, 0, 0, 0.1);--mm-color-button:rgba(0, 0, 0, 0.3);--mm-color-text:rgba(0, 0, 0, 0.75);--mm-color-text-dimmed:rgba(0, 0, 0, 0.3);--mm-color-background:#f3f3f3;--mm-color-background-highlight:rgba(0, 0, 0, 0.05);--mm-color-background-emphasis:rgba(255, 255, 255, 0.4);--mm-shadow:0 0 10px rgba(0, 0, 0, 0.3)}.mm-hidden{display:none!important}.mm-wrapper{overflow-x:hidden;position:relative}.mm-menu{top:0;right:0;bottom:0;left:0;background:#f3f3f3;border-color:rgba(0,0,0,.1);color:rgba(0,0,0,.75);line-height:20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding:0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;position:absolute;top:var(--mm-offset-top);right:var(--mm-offset-right);bottom:var(--mm-offset-bottom);left:var(--mm-offset-left);z-index:0;background:var(--mm-color-background);border-color:var(--mm-color-border);color:var(--mm-color-text);line-height:var(--mm-line-height);-webkit-tap-highlight-color:var(--mm-color-background-emphasis);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.mm-menu a,.mm-menu a:active,.mm-menu a:hover,.mm-menu a:link,.mm-menu a:visited{text-decoration:none;color:inherit}[dir=rtl] .mm-menu{direction:rtl}.mm-panel{background:#f3f3f3;border-color:rgba(0,0,0,.1);color:rgba(0,0,0,.75);z-index:0;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;-webkit-overflow-scrolling:touch;overflow:scroll;overflow-x:hidden;overflow-y:auto;background:var(--mm-color-background);border-color:var(--mm-color-border);color:var(--mm-color-text);-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;-o-transition:transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease}.mm-panel:after{height:44px}.mm-panel:not(.mm-hidden){display:block}.mm-panel:after{content:'';display:block;height:var(--mm-listitem-size)}.mm-panel_opened{z-index:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-panel_opened-parent{-webkit-transform:translate3d(-30%,0,0);transform:translate3d(-30%,0,0)}.mm-panel_highest{z-index:2}.mm-panel_noanimation{-webkit-transition:none!important;-o-transition:none!important;transition:none!important}.mm-panel_noanimation.mm-panel_opened-parent{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-panels>.mm-panel{position:absolute;left:0;right:0;top:0;bottom:0}.mm-panel__content{padding:20px 20px 0}.mm-panels{background:#f3f3f3;border-color:rgba(0,0,0,.1);color:rgba(0,0,0,.75);position:relative;height:100%;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;overflow:hidden;background:var(--mm-color-background);border-color:var(--mm-color-border);color:var(--mm-color-text)}[dir=rtl] .mm-panel:not(.mm-panel_opened){-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}[dir=rtl] .mm-panel.mm-panel_opened-parent{-webkit-transform:translate3d(30%,0,0);transform:translate3d(30%,0,0)}.mm-listitem_vertical>.mm-panel{display:none;width:100%;padding:10px 0 10px 10px;-webkit-transform:none!important;-ms-transform:none!important;transform:none!important}.mm-listitem_vertical>.mm-panel:after,.mm-listitem_vertical>.mm-panel:before{content:none;display:none}.mm-listitem_opened>.mm-panel{display:block}.mm-listitem_vertical>.mm-listitem__btn{height:44px;height:var(--mm-listitem-size);bottom:auto}.mm-listitem_vertical .mm-listitem:last-child:after{border-color:transparent}.mm-listitem_opened>.mm-listitem__btn:after{-webkit-transform:rotate(225deg);-ms-transform:rotate(225deg);transform:rotate(225deg);right:19px}.mm-btn{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:50px;padding:0}.mm-btn:after,.mm-btn:before{border:2px solid rgba(0,0,0,.3);border:2px solid var(--mm-color-button)}.mm-btn_next:after,.mm-btn_prev:before{content:'';border-bottom:none;border-right:none;-webkit-box-sizing:content-box;box-sizing:content-box;display:block;width:8px;height:8px;margin:auto;position:absolute;top:0;bottom:0}.mm-btn_prev:before{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg);left:23px;right:auto}.mm-btn_next:after{-webkit-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg);right:23px;left:auto}.mm-btn_close:after,.mm-btn_close:before{content:'';-webkit-box-sizing:content-box;box-sizing:content-box;display:block;width:5px;height:5px;margin:auto;position:absolute;top:0;bottom:0;-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.mm-btn_close:before{border-right:none;border-bottom:none;right:18px}.mm-btn_close:after{border-left:none;border-top:none;right:25px}[dir=rtl] .mm-btn_next:after{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg);left:23px;right:auto}[dir=rtl] .mm-btn_prev:before{-webkit-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg);right:23px;left:auto}[dir=rtl] .mm-btn_close:after,[dir=rtl] .mm-btn_close:before{right:auto}[dir=rtl] .mm-btn_close:before{left:25px}[dir=rtl] .mm-btn_close:after{left:18px}.mm-navbar{min-height:44px;border-bottom:1px solid rgba(0,0,0,.1);background:#f3f3f3;color:rgba(0,0,0,.3);display:-webkit-box;display:-ms-flexbox;display:flex;min-height:var(--mm-navbar-size);border-bottom:1px solid var(--mm-color-border);background:var(--mm-color-background);color:var(--mm-color-text-dimmed);text-align:center;opacity:1;-webkit-transition:opacity .4s ease;-o-transition:opacity .4s ease;transition:opacity .4s ease}.mm-navbar>*{min-height:44px}@supports ((position:-webkit-sticky) or (position:sticky)){.mm-navbar_sticky{position:-webkit-sticky;position:sticky;top:0;z-index:1}}.mm-navbar>*{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-sizing:border-box;box-sizing:border-box}.mm-navbar__btn{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.mm-navbar__title{-webkit-box-flex:1;-ms-flex:1 1 50%;flex:1 1 50%;display:-webkit-box;display:-ms-flexbox;display:flex;padding-left:20px;padding-right:20px;overflow:hidden}.mm-navbar__title:not(:last-child){padding-right:0}.mm-navbar__title>span{-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mm-navbar__btn:not(.mm-hidden)+.mm-navbar__title{padding-left:0}.mm-navbar__btn:not(.mm-hidden)+.mm-navbar__title:last-child{padding-right:50px}[dir=rtl] .mm-navbar{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.mm-listview{list-style:none;display:block;padding:0;margin:0}.mm-listitem{color:rgba(0,0,0,.75);border-color:rgba(0,0,0,.1);color:var(--mm-color-text);border-color:var(--mm-color-border);list-style:none;display:block;padding:0;margin:0;position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.mm-listitem:after{content:'';border-color:inherit;border-bottom-width:1px;border-bottom-style:solid;display:block;position:absolute;left:20px;right:0;bottom:0}.mm-listitem a,.mm-listitem a:hover{text-decoration:none}.mm-listitem__btn,.mm-listitem__text{padding:12px;display:block;padding:calc((var(--mm-listitem-size) - var(--mm-line-height))/ 2);padding-left:0;padding-right:0;color:inherit}.mm-listitem__text{-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;padding-left:20px;padding-right:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-preferred-size:10%;flex-basis:10%}.mm-listitem__btn{background:rgba(3,2,1,0);border-color:inherit;width:auto;padding-right:50px;position:relative}.mm-listitem__btn:not(.mm-listitem__text){border-left-width:1px;border-left-style:solid}.mm-listitem_selected>.mm-listitem__text{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)}.mm-listitem_opened>.mm-listitem__btn,.mm-listitem_opened>.mm-panel{background:rgba(0,0,0,.05);background:var(--mm-color-background-highlight)}[dir=rtl] .mm-listitem:after{left:0;right:20px}[dir=rtl] .mm-listitem__text{padding-left:10px;padding-right:20px}[dir=rtl] .mm-listitem__btn{padding-left:50px;border-left-width:0;border-left-style:none}[dir=rtl] .mm-listitem__btn:not(.mm-listitem__text){padding-right:0;border-right-width:1px;border-right-style:solid} \ No newline at end of file diff --git a/dist/core/oncanvas/mmenu.oncanvas.js b/dist/core/oncanvas/mmenu.oncanvas.js new file mode 100644 index 0000000..010bec9 --- /dev/null +++ b/dist/core/oncanvas/mmenu.oncanvas.js @@ -0,0 +1,774 @@ +import version from '../../_version'; +import options from './_options'; +import configs from './_configs'; +import translate from './translations/translate'; +import * as DOM from '../../_modules/dom'; +import * as i18n from '../../_modules/i18n'; +import * as media from '../../_modules/matchmedia'; +import { type, extend, transitionend, uniqueId, valueOrFn } from '../../_modules/helpers'; +// Add the translations. +translate(); +/** + * Class for a mobile menu. + */ +var Mmenu = /** @class */ (function () { + /** + * Create a mobile menu. + * @param {HTMLElement|string} menu The menu node. + * @param {object} [options=Mmenu.options] Options for the menu. + * @param {object} [configs=Mmenu.configs] Configuration options for the menu. + */ + function Mmenu(menu, options, configs) { + // Extend options and configuration from defaults. + this.opts = extend(options, Mmenu.options); + this.conf = extend(configs, Mmenu.configs); + // Methods to expose in the API. + this._api = [ + 'bind', + 'initPanel', + 'initListview', + 'openPanel', + 'closePanel', + 'closeAllPanels', + 'setSelected' + ]; + // Storage objects for nodes, variables, hooks and click handlers. + this.node = {}; + this.vars = {}; + this.hook = {}; + this.clck = []; + // Get menu node from string or element. + this.node.menu = + typeof menu == 'string' ? document.querySelector(menu) : menu; + if (typeof this._deprecatedWarnings == 'function') { + this._deprecatedWarnings(); + } + this._initWrappers(); + this._initAddons(); + this._initExtensions(); + this._initHooks(); + this._initAPI(); + this._initMenu(); + this._initPanels(); + this._initOpened(); + this._initAnchors(); + media.watch(); + return this; + } + /** + * Open a panel. + * @param {HTMLElement} panel Panel to open. + * @param {boolean} [animation=true] Whether or not to open the panel with an animation. + */ + Mmenu.prototype.openPanel = function (panel, animation) { + var _this = this; + // Invoke "before" hook. + this.trigger('openPanel:before', [panel]); + // Find panel. + if (!panel) { + return; + } + if (!panel.matches('.mm-panel')) { + panel = panel.closest('.mm-panel'); + } + if (!panel) { + return; + } + // /Find panel. + if (typeof animation != 'boolean') { + animation = true; + } + // Open a "vertical" panel. + if (panel.parentElement.matches('.mm-listitem_vertical')) { + // Open current and all vertical parent panels. + DOM.parents(panel, '.mm-listitem_vertical').forEach(function (listitem) { + listitem.classList.add('mm-listitem_opened'); + DOM.children(listitem, '.mm-panel').forEach(function (panel) { + panel.classList.remove('mm-hidden'); + }); + }); + // Open first non-vertical parent panel. + var parents = DOM.parents(panel, '.mm-panel').filter(function (panel) { return !panel.parentElement.matches('.mm-listitem_vertical'); }); + this.trigger('openPanel:start', [panel]); + if (parents.length) { + this.openPanel(parents[0]); + } + this.trigger('openPanel:finish', [panel]); + // Open a "horizontal" panel. + } + else { + if (panel.matches('.mm-panel_opened')) { + return; + } + var panels = DOM.children(this.node.pnls, '.mm-panel'), current_1 = DOM.children(this.node.pnls, '.mm-panel_opened')[0]; + // Close all child panels. + panels + .filter(function (parent) { return parent !== panel; }) + .forEach(function (parent) { + parent.classList.remove('mm-panel_opened-parent'); + }); + // Open all parent panels. + var parent_1 = panel['mmParent']; + while (parent_1) { + parent_1 = parent_1.closest('.mm-panel'); + if (parent_1) { + if (!parent_1.parentElement.matches('.mm-listitem_vertical')) { + parent_1.classList.add('mm-panel_opened-parent'); + } + parent_1 = parent_1['mmParent']; + } + } + // Add classes for animation. + panels.forEach(function (panel) { + panel.classList.remove('mm-panel_highest'); + }); + panels + .filter(function (hidden) { return hidden !== current_1; }) + .filter(function (hidden) { return hidden !== panel; }) + .forEach(function (hidden) { + hidden.classList.add('mm-hidden'); + }); + panel.classList.remove('mm-hidden'); + /** Start opening the panel. */ + var openPanelStart_1 = function () { + if (current_1) { + current_1.classList.remove('mm-panel_opened'); + } + panel.classList.add('mm-panel_opened'); + if (panel.matches('.mm-panel_opened-parent')) { + if (current_1) { + current_1.classList.add('mm-panel_highest'); + } + panel.classList.remove('mm-panel_opened-parent'); + } + else { + if (current_1) { + current_1.classList.add('mm-panel_opened-parent'); + } + panel.classList.add('mm-panel_highest'); + } + // Invoke "start" hook. + _this.trigger('openPanel:start', [panel]); + }; + /** Finish opening the panel. */ + var openPanelFinish_1 = function () { + if (current_1) { + current_1.classList.remove('mm-panel_highest'); + current_1.classList.add('mm-hidden'); + } + panel.classList.remove('mm-panel_highest'); + // Invoke "finish" hook. + _this.trigger('openPanel:finish', [panel]); + }; + if (animation && !panel.matches('.mm-panel_noanimation')) { + // Without the timeout the animation will not work because the element had display: none; + setTimeout(function () { + // Callback + transitionend(panel, function () { + openPanelFinish_1(); + }, _this.conf.transitionDuration); + openPanelStart_1(); + }, this.conf.openingInterval); + } + else { + openPanelStart_1(); + openPanelFinish_1(); + } + } + // Invoke "after" hook. + this.trigger('openPanel:after', [panel]); + }; + /** + * Close a panel. + * @param {HTMLElement} panel Panel to close. + */ + Mmenu.prototype.closePanel = function (panel) { + // Invoke "before" hook. + this.trigger('closePanel:before', [panel]); + var li = panel.parentElement; + // Only works for "vertical" panels. + if (li.matches('.mm-listitem_vertical')) { + li.classList.remove('mm-listitem_opened'); + panel.classList.add('mm-hidden'); + // Invoke main hook. + this.trigger('closePanel', [panel]); + } + // Invoke "after" hook. + this.trigger('closePanel:after', [panel]); + }; + /** + * Close all opened panels. + * @param {HTMLElement} panel Panel to open after closing all other panels. + */ + Mmenu.prototype.closeAllPanels = function (panel) { + // Invoke "before" hook. + this.trigger('closeAllPanels:before'); + // Close all "vertical" panels. + var listitems = this.node.pnls.querySelectorAll('.mm-listitem'); + listitems.forEach(function (listitem) { + listitem.classList.remove('mm-listitem_selected'); + listitem.classList.remove('mm-listitem_opened'); + }); + // Close all "horizontal" panels. + var panels = DOM.children(this.node.pnls, '.mm-panel'), opened = panel ? panel : panels[0]; + DOM.children(this.node.pnls, '.mm-panel').forEach(function (panel) { + if (panel !== opened) { + panel.classList.remove('mm-panel_opened'); + panel.classList.remove('mm-panel_opened-parent'); + panel.classList.remove('mm-panel_highest'); + panel.classList.add('mm-hidden'); + } + }); + // Open first panel. + this.openPanel(opened, false); + // Invoke "after" hook. + this.trigger('closeAllPanels:after'); + }; + /** + * Toggle a panel opened/closed. + * @param {HTMLElement} panel Panel to open or close. + */ + Mmenu.prototype.togglePanel = function (panel) { + var listitem = panel.parentElement; + // Only works for "vertical" panels. + if (listitem.matches('.mm-listitem_vertical')) { + this[listitem.matches('.mm-listitem_opened') + ? 'closePanel' + : 'openPanel'](panel); + } + }; + /** + * Display a listitem as being "selected". + * @param {HTMLElement} listitem Listitem to mark. + */ + Mmenu.prototype.setSelected = function (listitem) { + // Invoke "before" hook. + this.trigger('setSelected:before', [listitem]); + // First, remove the selected class from all listitems. + DOM.find(this.node.menu, '.mm-listitem_selected').forEach(function (li) { + li.classList.remove('mm-listitem_selected'); + }); + // Next, add the selected class to the provided listitem. + listitem.classList.add('mm-listitem_selected'); + // Invoke "after" hook. + this.trigger('setSelected:after', [listitem]); + }; + /** + * Bind functions to a hook (subscriber). + * @param {string} hook The hook. + * @param {function} func The function. + */ + Mmenu.prototype.bind = function (hook, func) { + // Create an array for the hook if it does not yet excist. + this.hook[hook] = this.hook[hook] || []; + // Push the function to the array. + this.hook[hook].push(func); + }; + /** + * Invoke the functions bound to a hook (publisher). + * @param {string} hook The hook. + * @param {array} [args] Arguments for the function. + */ + Mmenu.prototype.trigger = function (hook, args) { + if (this.hook[hook]) { + for (var h = 0, l = this.hook[hook].length; h < l; h++) { + this.hook[hook][h].apply(this, args); + } + } + }; + /** + * Create the API. + */ + Mmenu.prototype._initAPI = function () { + var _this = this; + // We need this=that because: + // 1) the "arguments" object can not be referenced in an arrow function in ES3 and ES5. + var that = this; + this.API = {}; + this._api.forEach(function (fn) { + _this.API[fn] = function () { + var re = that[fn].apply(that, arguments); // 1) + return typeof re == 'undefined' ? that.API : re; + }; + }); + // Store the API in the HTML node for external usage. + this.node.menu['mmApi'] = this.API; + }; + /** + * Bind the hooks specified in the options (publisher). + */ + Mmenu.prototype._initHooks = function () { + for (var hook in this.opts.hooks) { + this.bind(hook, this.opts.hooks[hook]); + } + }; + /** + * Initialize the wrappers specified in the options. + */ + Mmenu.prototype._initWrappers = function () { + // Invoke "before" hook. + this.trigger('initWrappers:before'); + for (var w = 0; w < this.opts.wrappers.length; w++) { + var wrpr = Mmenu.wrappers[this.opts.wrappers[w]]; + if (typeof wrpr == 'function') { + wrpr.call(this); + } + } + // Invoke "after" hook. + this.trigger('initWrappers:after'); + }; + /** + * Initialize all available add-ons. + */ + Mmenu.prototype._initAddons = function () { + // Invoke "before" hook. + this.trigger('initAddons:before'); + for (var addon in Mmenu.addons) { + Mmenu.addons[addon].call(this); + } + // Invoke "after" hook. + this.trigger('initAddons:after'); + }; + /** + * Initialize the extensions specified in the options. + */ + Mmenu.prototype._initExtensions = function () { + var _this = this; + // Invoke "before" hook. + this.trigger('initExtensions:before'); + // Convert array to object with array. + if (type(this.opts.extensions) == 'array') { + this.opts.extensions = { + all: this.opts.extensions + }; + } + // Loop over object. + Object.keys(this.opts.extensions).forEach(function (query) { + var classnames = _this.opts.extensions[query].map(function (extension) { return 'mm-menu_' + extension; }); + if (classnames.length) { + media.add(query, function () { + // IE11: + classnames.forEach(function (classname) { + _this.node.menu.classList.add(classname); + }); + // Better browsers: + // this.node.menu.classList.add(...classnames); + }, function () { + // IE11: + classnames.forEach(function (classname) { + _this.node.menu.classList.remove(classname); + }); + // Better browsers: + // this.node.menu.classList.remove(...classnames); + }); + } + }); + // Invoke "after" hook. + this.trigger('initExtensions:after'); + }; + /** + * Initialize the menu. + */ + Mmenu.prototype._initMenu = function () { + var _this = this; + // Invoke "before" hook. + this.trigger('initMenu:before'); + // Add class to the wrapper. + this.node.wrpr = this.node.wrpr || this.node.menu.parentElement; + this.node.wrpr.classList.add('mm-wrapper'); + // Add an ID to the menu if it does not yet have one. + this.node.menu.id = this.node.menu.id || uniqueId(); + // Wrap the panels in a node. + var panels = DOM.create('div.mm-panels'); + DOM.children(this.node.menu).forEach(function (panel) { + if (_this.conf.panelNodetype.indexOf(panel.nodeName.toLowerCase()) > + -1) { + panels.append(panel); + } + }); + this.node.menu.append(panels); + this.node.pnls = panels; + // Add class to the menu. + this.node.menu.classList.add('mm-menu'); + // Invoke "after" hook. + this.trigger('initMenu:after'); + }; + /** + * Initialize panels. + */ + Mmenu.prototype._initPanels = function () { + var _this = this; + // Invoke "before" hook. + this.trigger('initPanels:before'); + // Open / close panels. + this.clck.push(function (anchor, args) { + if (args.inMenu) { + var href = anchor.getAttribute('href'); + if (href && href.length > 1 && href.slice(0, 1) == '#') { + try { + var panel = DOM.find(_this.node.menu, href)[0]; + if (panel && panel.matches('.mm-panel')) { + if (anchor.parentElement.matches('.mm-listitem_vertical')) { + _this.togglePanel(panel); + } + else { + _this.openPanel(panel); + } + return true; + } + } + catch (err) { } + } + } + }); + /** The panels to initiate */ + var panels = DOM.children(this.node.pnls); + panels.forEach(function (panel) { + _this.initPanel(panel); + }); + // Invoke "after" hook. + this.trigger('initPanels:after'); + }; + /** + * Initialize a single panel and its children. + * @param {HTMLElement} panel The panel to initialize. + */ + Mmenu.prototype.initPanel = function (panel) { + var _this = this; + /** Query selector for possible node-types for panels. */ + var panelNodetype = this.conf.panelNodetype.join(', '); + if (panel.matches(panelNodetype)) { + // Only once + if (!panel.matches('.mm-panel')) { + panel = this._initPanel(panel); + } + if (panel) { + /** The sub panels. */ + var children_1 = []; + // Find panel > panel + children_1.push.apply(children_1, DOM.children(panel, '.' + this.conf.classNames.panel)); + // Find panel listitem > panel + DOM.children(panel, '.mm-listview').forEach(function (listview) { + DOM.children(listview, '.mm-listitem').forEach(function (listitem) { + children_1.push.apply(children_1, DOM.children(listitem, panelNodetype)); + }); + }); + // Initiate subpanel(s). + children_1.forEach(function (child) { + _this.initPanel(child); + }); + } + } + }; + /** + * Initialize a single panel. + * @param {HTMLElement} panel Panel to initialize. + * @return {HTMLElement|null} Initialized panel. + */ + Mmenu.prototype._initPanel = function (panel) { + var _this = this; + // Invoke "before" hook. + this.trigger('initPanel:before', [panel]); + // Refactor panel classnames + DOM.reClass(panel, this.conf.classNames.panel, 'mm-panel'); + DOM.reClass(panel, this.conf.classNames.nopanel, 'mm-nopanel'); + DOM.reClass(panel, this.conf.classNames.inset, 'mm-listview_inset'); + if (panel.matches('.mm-listview_inset')) { + panel.classList.add('mm-nopanel'); + } + // Stop if not supposed to be a panel. + if (panel.matches('.mm-nopanel')) { + return null; + } + /** The original ID on the node. */ + var id = panel.id || uniqueId(); + // Vertical panel. + var vertical = panel.matches('.' + this.conf.classNames.vertical) || + !this.opts.slidingSubmenus; + panel.classList.remove(this.conf.classNames.vertical); + // Wrap UL/OL in DIV + if (panel.matches('ul, ol')) { + panel.removeAttribute('id'); + /** The panel. */ + var wrapper = DOM.create('div'); + // Wrap the listview in the panel. + panel.before(wrapper); + wrapper.append(panel); + panel = wrapper; + } + panel.id = id; + panel.classList.add('mm-panel'); + panel.classList.add('mm-hidden'); + /** The parent listitem. */ + var parent = [panel.parentElement].filter(function (listitem) { + return listitem.matches('li'); + })[0]; + if (vertical) { + if (parent) { + parent.classList.add('mm-listitem_vertical'); + } + } + else { + this.node.pnls.append(panel); + } + if (parent) { + // Store parent/child relation. + parent['mmChild'] = panel; + panel['mmParent'] = parent; + // Add open link to parent listitem + if (parent && parent.matches('.mm-listitem')) { + if (!DOM.children(parent, '.mm-btn').length) { + /** The text node. */ + var item = DOM.children(parent, '.mm-listitem__text')[0]; + if (item) { + /** The open link. */ + var button = DOM.create('a.mm-btn.mm-btn_next.mm-listitem__btn'); + button.setAttribute('href', '#' + panel.id); + // If the item has no link, + // Replace the item with the open link. + if (item.matches('span')) { + button.classList.add('mm-listitem__text'); + button.innerHTML = item.innerHTML; + parent.insertBefore(button, item.nextElementSibling); + item.remove(); + } + // Otherwise, insert the button after the text. + else { + parent.insertBefore(button, DOM.children(parent, '.mm-panel')[0]); + } + } + } + } + } + this._initNavbar(panel); + DOM.children(panel, 'ul, ol').forEach(function (listview) { + _this.initListview(listview); + }); + // Invoke "after" hook. + this.trigger('initPanel:after', [panel]); + return panel; + }; + /** + * Initialize a navbar. + * @param {HTMLElement} panel Panel for the navbar. + */ + Mmenu.prototype._initNavbar = function (panel) { + // Invoke "before" hook. + this.trigger('initNavbar:before', [panel]); + // Only one navbar per panel. + if (DOM.children(panel, '.mm-navbar').length) { + return; + } + /** The parent listitem. */ + var parentListitem = null; + /** The parent panel. */ + var parentPanel = null; + // The parent panel was specified in the data-mm-parent attribute. + if (panel.getAttribute('data-mm-parent')) { + parentPanel = DOM.find(this.node.pnls, panel.getAttribute('data-mm-parent'))[0]; + } + // if (panel.dataset.mmParent) { // IE10 has no dataset + // parentPanel = DOM.find(this.node.pnls, panel.dataset.mmParent)[0]; + // } + // The parent panel from a listitem. + else { + parentListitem = panel['mmParent']; + if (parentListitem) { + parentPanel = parentListitem.closest('.mm-panel'); + } + } + // No navbar needed for vertical submenus. + if (parentListitem && parentListitem.matches('.mm-listitem_vertical')) { + return; + } + /** The navbar element. */ + var navbar = DOM.create('div.mm-navbar'); + // Hide navbar if specified in options. + if (!this.opts.navbar.add) { + navbar.classList.add('mm-hidden'); + } + // Sticky navbars. + else if (this.opts.navbar.sticky) { + navbar.classList.add('mm-navbar_sticky'); + } + // Add the back button. + if (parentPanel) { + /** The back button. */ + var prev = DOM.create('a.mm-btn.mm-btn_prev.mm-navbar__btn'); + prev.setAttribute('href', '#' + parentPanel.id); + navbar.append(prev); + } + /** The anchor that opens the panel. */ + var opener = null; + // The anchor is in a listitem. + if (parentListitem) { + opener = DOM.children(parentListitem, '.mm-listitem__text')[0]; + } + // The anchor is in a panel. + else if (parentPanel) { + opener = DOM.find(parentPanel, 'a[href="#' + panel.id + '"]')[0]; + } + // Add the title. + var title = DOM.create('a.mm-navbar__title'); + var titleText = DOM.create('span'); + title.append(titleText); + titleText.innerHTML = + // panel.dataset.mmTitle || // IE10 has no dataset :( + panel.getAttribute('data-mm-title') || + (opener ? opener.textContent : '') || + this.i18n(this.opts.navbar.title) || + this.i18n('Menu'); + switch (this.opts.navbar.titleLink) { + case 'anchor': + if (opener) { + title.setAttribute('href', opener.getAttribute('href')); + } + break; + case 'parent': + if (parentPanel) { + title.setAttribute('href', '#' + parentPanel.id); + } + break; + } + navbar.append(title); + panel.prepend(navbar); + // Invoke "after" hook. + this.trigger('initNavbar:after', [panel]); + }; + /** + * Initialize a listview. + * @param {HTMLElement} listview Listview to initialize. + */ + Mmenu.prototype.initListview = function (listview) { + var _this = this; + // Invoke "before" hook. + this.trigger('initListview:before', [listview]); + DOM.reClass(listview, this.conf.classNames.nolistview, 'mm-nolistview'); + if (!listview.matches('.mm-nolistview')) { + listview.classList.add('mm-listview'); + DOM.children(listview).forEach(function (listitem) { + listitem.classList.add('mm-listitem'); + DOM.reClass(listitem, _this.conf.classNames.selected, 'mm-listitem_selected'); + DOM.children(listitem, 'a, span').forEach(function (item) { + if (!item.matches('.mm-btn')) { + item.classList.add('mm-listitem__text'); + } + }); + }); + } + // Invoke "after" hook. + this.trigger('initListview:after', [listview]); + }; + /** + * Find and open the correct panel after creating the menu. + */ + Mmenu.prototype._initOpened = function () { + // Invoke "before" hook. + this.trigger('initOpened:before'); + /** The selected listitem(s). */ + var listitems = this.node.pnls.querySelectorAll('.mm-listitem_selected'); + /** The last selected listitem. */ + var lastitem = null; + // Deselect the listitems. + listitems.forEach(function (listitem) { + lastitem = listitem; + listitem.classList.remove('mm-listitem_selected'); + }); + // Re-select the last listitem. + if (lastitem) { + lastitem.classList.add('mm-listitem_selected'); + } + /** The current opened panel. */ + var current = lastitem + ? lastitem.closest('.mm-panel') + : DOM.children(this.node.pnls, '.mm-panel')[0]; + // Open the current opened panel. + this.openPanel(current, false); + // Invoke "after" hook. + this.trigger('initOpened:after'); + }; + /** + * Initialize anchors in / for the menu. + */ + Mmenu.prototype._initAnchors = function () { + var _this = this; + // Invoke "before" hook. + this.trigger('initAnchors:before'); + document.addEventListener('click', function (evnt) { + /** The clicked element. */ + var target = evnt.target.closest('a[href]'); + if (!target) { + return; + } + /** Arguments passed to the bound methods. */ + var args = { + inMenu: target.closest('.mm-menu') === _this.node.menu, + inListview: target.matches('.mm-listitem > a'), + toExternal: target.matches('[rel="external"]') || + target.matches('[target="_blank"]') + }; + var onClick = { + close: null, + setSelected: null, + preventDefault: target.getAttribute('href').slice(0, 1) == '#' + }; + // Find hooked behavior. + for (var c = 0; c < _this.clck.length; c++) { + var click = _this.clck[c].call(_this, target, args); + if (click) { + if (typeof click == 'boolean') { + evnt.preventDefault(); + return; + } + if (type(click) == 'object') { + onClick = extend(click, onClick); + } + } + } + // Default behavior for anchors in lists. + if (args.inMenu && args.inListview && !args.toExternal) { + // Set selected item, Default: true + if (valueOrFn(target, _this.opts.onClick.setSelected, onClick.setSelected)) { + _this.setSelected(target.parentElement); + } + // Prevent default / don't follow link. Default: false. + if (valueOrFn(target, _this.opts.onClick.preventDefault, onClick.preventDefault)) { + evnt.preventDefault(); + } + // Close menu. Default: false + if (valueOrFn(target, _this.opts.onClick.close, onClick.close)) { + if (_this.opts.offCanvas && + typeof _this.close == 'function') { + _this.close(); + } + } + } + }, true); + // Invoke "after" hook. + this.trigger('initAnchors:after'); + }; + /** + * Get the translation for a text. + * @param {string} text Text to translate. + * @return {string} The translated text. + */ + Mmenu.prototype.i18n = function (text) { + return i18n.get(text, this.conf.language); + }; + /** Plugin version. */ + Mmenu.version = version; + /** Default options for menus. */ + Mmenu.options = options; + /** Default configuration for menus. */ + Mmenu.configs = configs; + /** Available add-ons for the plugin. */ + Mmenu.addons = {}; + /** Available wrappers for the plugin. */ + Mmenu.wrappers = {}; + /** Globally used HTML elements. */ + Mmenu.node = {}; + /** Globally used variables. */ + Mmenu.vars = {}; + return Mmenu; +}()); +export default Mmenu; diff --git a/dist/core/oncanvas/translations/de.js b/dist/core/oncanvas/translations/de.js new file mode 100644 index 0000000..1bf890e --- /dev/null +++ b/dist/core/oncanvas/translations/de.js @@ -0,0 +1,3 @@ +export default { + 'Menu': 'Menü' +}; diff --git a/dist/core/oncanvas/translations/fa.js b/dist/core/oncanvas/translations/fa.js new file mode 100644 index 0000000..9dbb686 --- /dev/null +++ b/dist/core/oncanvas/translations/fa.js @@ -0,0 +1,3 @@ +export default { + 'Menu': 'منو' +}; diff --git a/dist/core/oncanvas/translations/nl.js b/dist/core/oncanvas/translations/nl.js new file mode 100644 index 0000000..8ef4179 --- /dev/null +++ b/dist/core/oncanvas/translations/nl.js @@ -0,0 +1,3 @@ +export default { + 'Menu': 'Menu' +}; diff --git a/dist/core/oncanvas/translations/ru.js b/dist/core/oncanvas/translations/ru.js new file mode 100644 index 0000000..b624e86 --- /dev/null +++ b/dist/core/oncanvas/translations/ru.js @@ -0,0 +1,3 @@ +export default { + 'Menu': 'Меню' +}; diff --git a/dist/core/oncanvas/translations/translate.js b/dist/core/oncanvas/translations/translate.js new file mode 100644 index 0000000..42e19b8 --- /dev/null +++ b/dist/core/oncanvas/translations/translate.js @@ -0,0 +1,11 @@ +import { add } from '../../../_modules/i18n'; +import nl from './nl'; +import fa from './fa'; +import de from './de'; +import ru from './ru'; +export default function () { + add(nl, 'nl'); + add(fa, 'fa'); + add(de, 'de'); + add(ru, 'ru'); +} diff --git a/dist/core/screenreader/_configs.js b/dist/core/screenreader/_configs.js new file mode 100644 index 0000000..7917a2c --- /dev/null +++ b/dist/core/screenreader/_configs.js @@ -0,0 +1,9 @@ +var configs = { + text: { + closeMenu: 'Close menu', + closeSubmenu: 'Close submenu', + openSubmenu: 'Open submenu', + toggleSubmenu: 'Toggle submenu' + } +}; +export default configs; diff --git a/dist/core/screenreader/_options.js b/dist/core/screenreader/_options.js new file mode 100644 index 0000000..567df79 --- /dev/null +++ b/dist/core/screenreader/_options.js @@ -0,0 +1,24 @@ +var options = { + aria: true, + text: true +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + aria: options, + text: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/core/screenreader/mmenu.screenreader.css b/dist/core/screenreader/mmenu.screenreader.css new file mode 100644 index 0000000..44e688e --- /dev/null +++ b/dist/core/screenreader/mmenu.screenreader.css @@ -0,0 +1 @@ +.mm-sronly{border:0!important;clip:rect(1px,1px,1px,1px)!important;-webkit-clip-path:inset(50%)!important;clip-path:inset(50%)!important;white-space:nowrap!important;width:1px!important;min-width:1px!important;height:1px!important;min-height:1px!important;padding:0!important;overflow:hidden!important;position:absolute!important} \ No newline at end of file diff --git a/dist/core/screenreader/mmenu.screenreader.js b/dist/core/screenreader/mmenu.screenreader.js new file mode 100644 index 0000000..f9d57a4 --- /dev/null +++ b/dist/core/screenreader/mmenu.screenreader.js @@ -0,0 +1,189 @@ +import Mmenu from './../oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import translate from './translations/translate'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; +// Add the translations. +translate(); +// Add the options and configs. +Mmenu.options.screenReader = options; +Mmenu.configs.screenReader = configs; +export default function () { + var _this = this; + // Extend options. + var options = extendShorthandOptions(this.opts.screenReader); + this.opts.screenReader = extend(options, Mmenu.options.screenReader); + // Extend configs. + var configs = this.conf.screenReader; + // Add Aria-* attributes + if (options.aria) { + // Add screenreader / aria hooks for add-ons + // In orde to keep this list short, only extend hooks that are actually used by other add-ons. + this.bind('initAddons:after', function () { + _this.bind('initMenu:after', function () { + this.trigger('initMenu:after:sr-aria', [].slice.call(arguments)); + }); + _this.bind('initNavbar:after', function () { + this.trigger('initNavbar:after:sr-aria', [].slice.call(arguments)); + }); + _this.bind('openPanel:start', function () { + this.trigger('openPanel:start:sr-aria', [].slice.call(arguments)); + }); + _this.bind('close:start', function () { + this.trigger('close:start:sr-aria', [].slice.call(arguments)); + }); + _this.bind('close:finish', function () { + this.trigger('close:finish:sr-aria', [].slice.call(arguments)); + }); + _this.bind('open:start', function () { + this.trigger('open:start:sr-aria', [].slice.call(arguments)); + }); + _this.bind('initOpened:after', function () { + this.trigger('initOpened:after:sr-aria', [].slice.call(arguments)); + }); + }); + // Update aria-hidden for hidden / visible listitems + this.bind('updateListview', function () { + _this.node.pnls + .querySelectorAll('.mm-listitem') + .forEach(function (listitem) { + Mmenu.sr_aria(listitem, 'hidden', listitem.matches('.mm-hidden')); + }); + }); + // Update aria-hidden for the panels when opening and closing a panel. + this.bind('openPanel:start', function (panel) { + /** Panels that should be considered "hidden". */ + var hidden = DOM.find(_this.node.pnls, '.mm-panel') + .filter(function (hide) { return hide !== panel; }) + .filter(function (hide) { return !hide.parentElement.matches('.mm-panel'); }); + /** Panels that should be considered "visible". */ + var visible = [panel]; + DOM.find(panel, '.mm-listitem_vertical .mm-listitem_opened').forEach(function (listitem) { + visible.push.apply(visible, DOM.children(listitem, '.mm-panel')); + }); + // Set the panels to be considered "hidden" or "visible". + hidden.forEach(function (panel) { + Mmenu.sr_aria(panel, 'hidden', true); + }); + visible.forEach(function (panel) { + Mmenu.sr_aria(panel, 'hidden', false); + }); + }); + this.bind('closePanel', function (panel) { + Mmenu.sr_aria(panel, 'hidden', true); + }); + // Add aria-haspopup and aria-owns to prev- and next buttons. + this.bind('initPanel:after', function (panel) { + DOM.find(panel, '.mm-btn').forEach(function (button) { + Mmenu.sr_aria(button, 'haspopup', true); + var href = button.getAttribute('href'); + if (href) { + Mmenu.sr_aria(button, 'owns', href.replace('#', '')); + } + }); + }); + // Add aria-hidden for navbars in panels. + this.bind('initNavbar:after', function (panel) { + /** The navbar in the panel. */ + var navbar = DOM.children(panel, '.mm-navbar')[0]; + /** Whether or not the navbar should be considered "hidden". */ + var hidden = navbar.matches('.mm-hidden'); + // Set the navbar to be considered "hidden" or "visible". + Mmenu.sr_aria(navbar, 'hidden', hidden); + }); + // Text + if (options.text) { + // Add aria-hidden to titles in navbars + if (this.opts.navbar.titleLink == 'parent') { + this.bind('initNavbar:after', function (panel) { + /** The navbar in the panel. */ + var navbar = DOM.children(panel, '.mm-navbar')[0]; + /** Whether or not the navbar should be considered "hidden". */ + var hidden = navbar.querySelector('.mm-btn_prev') + ? true + : false; + // Set the navbar-title to be considered "hidden" or "visible". + Mmenu.sr_aria(DOM.find(navbar, '.mm-navbar__title')[0], 'hidden', hidden); + }); + } + } + } + // Add screenreader text + if (options.text) { + // Add screenreader / text hooks for add-ons + // In orde to keep this list short, only extend hooks that are actually used by other add-ons. + this.bind('initAddons:after', function () { + _this.bind('setPage:after', function () { + this.trigger('setPage:after:sr-text', [].slice.call(arguments)); + }); + _this.bind('initBlocker:after', function () { + this.trigger('initBlocker:after:sr-text', [].slice.call(arguments)); + }); + }); + // Add text to the prev-buttons. + this.bind('initNavbar:after', function (panel) { + var navbar = DOM.children(panel, '.mm-navbar')[0]; + if (navbar) { + var button = DOM.children(navbar, '.mm-btn_prev')[0]; + if (button) { + button.innerHTML = Mmenu.sr_text(_this.i18n(configs.text.closeSubmenu)); + } + } + }); + // Add text to the next-buttons. + this.bind('initListview:after', function (listview) { + var parent = listview.closest('.mm-panel')['mmParent']; + if (parent) { + var next = DOM.children(parent, '.mm-btn_next')[0]; + if (next) { + var text = _this.i18n(configs.text[next.parentElement.matches('.mm-listitem_vertical') + ? 'toggleSubmenu' + : 'openSubmenu']); + next.innerHTML += Mmenu.sr_text(text); + } + } + }); + } +} +// Methods +(function () { + var attr = function (element, attr, value) { + element[attr] = value; + if (value) { + element.setAttribute(attr, value.toString()); + } + else { + element.removeAttribute(attr); + } + }; + /** + * Add aria (property and) attribute to a HTML element. + * + * @param {HTMLElement} element The node to add the attribute to. + * @param {string} name The (non-aria-prefixed) attribute name. + * @param {string|boolean} value The attribute value. + */ + Mmenu.sr_aria = function (element, name, value) { + attr(element, 'aria-' + name, value); + }; + /** + * Add role attribute to a HTML element. + * + * @param {HTMLElement} element The node to add the attribute to. + * @param {string|boolean} value The attribute value. + */ + Mmenu.sr_role = function (element, value) { + attr(element, 'role', value); + }; + /** + * Wrap a text in a screen-reader-only node. + * + * @param {string} text The text to wrap. + * @return {string} The wrapped text. + */ + Mmenu.sr_text = function (text) { + return '' + text + ''; + }; +})(); diff --git a/dist/core/screenreader/translations/de.js b/dist/core/screenreader/translations/de.js new file mode 100644 index 0000000..9011118 --- /dev/null +++ b/dist/core/screenreader/translations/de.js @@ -0,0 +1,6 @@ +export default { + 'Close menu': 'Menü schließen', + 'Close submenu': 'Untermenü schließen', + 'Open submenu': 'Untermenü öffnen', + 'Toggle submenu': 'Untermenü wechseln' +}; diff --git a/dist/core/screenreader/translations/fa.js b/dist/core/screenreader/translations/fa.js new file mode 100644 index 0000000..da07a77 --- /dev/null +++ b/dist/core/screenreader/translations/fa.js @@ -0,0 +1,6 @@ +export default { + 'Close menu': 'بستن منو', + 'Close submenu': 'بستن زیرمنو', + 'Open submenu': 'بازکردن زیرمنو', + 'Toggle submenu': 'سوییچ زیرمنو' +}; diff --git a/dist/core/screenreader/translations/nl.js b/dist/core/screenreader/translations/nl.js new file mode 100644 index 0000000..8afcae7 --- /dev/null +++ b/dist/core/screenreader/translations/nl.js @@ -0,0 +1,6 @@ +export default { + 'Close menu': 'Menu sluiten', + 'Close submenu': 'Submenu sluiten', + 'Open submenu': 'Submenu openen', + 'Toggle submenu': 'Submenu wisselen' +}; diff --git a/dist/core/screenreader/translations/ru.js b/dist/core/screenreader/translations/ru.js new file mode 100644 index 0000000..b3dcd3c --- /dev/null +++ b/dist/core/screenreader/translations/ru.js @@ -0,0 +1,6 @@ +export default { + 'Close menu': 'Закрыть меню', + 'Close submenu': 'Закрыть подменю', + 'Open submenu': 'Открыть подменю', + 'Toggle submenu': 'Переключить подменю' +}; diff --git a/dist/core/screenreader/translations/translate.js b/dist/core/screenreader/translations/translate.js new file mode 100644 index 0000000..42e19b8 --- /dev/null +++ b/dist/core/screenreader/translations/translate.js @@ -0,0 +1,11 @@ +import { add } from '../../../_modules/i18n'; +import nl from './nl'; +import fa from './fa'; +import de from './de'; +import ru from './ru'; +export default function () { + add(nl, 'nl'); + add(fa, 'fa'); + add(de, 'de'); + add(ru, 'ru'); +} diff --git a/dist/core/scrollbugfix/_options.js b/dist/core/scrollbugfix/_options.js new file mode 100644 index 0000000..8b5017a --- /dev/null +++ b/dist/core/scrollbugfix/_options.js @@ -0,0 +1,22 @@ +var options = { + fix: true +}; +export default options; +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options) { + if (typeof options == 'boolean') { + options = { + fix: options + }; + } + if (typeof options != 'object') { + options = {}; + } + return options; +} +; diff --git a/dist/core/scrollbugfix/mmenu.scrollbugfix.js b/dist/core/scrollbugfix/mmenu.scrollbugfix.js new file mode 100644 index 0000000..c9504bc --- /dev/null +++ b/dist/core/scrollbugfix/mmenu.scrollbugfix.js @@ -0,0 +1,91 @@ +import Mmenu from './../oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as support from '../../_modules/support'; +import { extend, touchDirection } from '../../_modules/helpers'; +// Add the options. +Mmenu.options.scrollBugFix = options; +export default function () { + var _this = this; + // The scrollBugFix add-on fixes a scrolling bug + // 1) on touch devices + // 2) in an off-canvas menu + // 3) that -when opened- blocks the UI from interaction + if (!support.touch || // 1 + !this.opts.offCanvas || // 2 + !this.opts.offCanvas.blockUI // 3 + ) { + return; + } + // Extend options. + var options = extendShorthandOptions(this.opts.scrollBugFix); + this.opts.scrollBugFix = extend(options, Mmenu.options.scrollBugFix); + if (!options.fix) { + return; + } + var touchDir = touchDirection(this.node.menu); + /** + * Prevent an event from doing its default and stop its propagation. + * @param {ScrollBehavior} evnt The event to stop. + */ + function stop(evnt) { + evnt.preventDefault(); + evnt.stopPropagation(); + } + // Prevent the page from scrolling when scrolling in the menu. + this.node.menu.addEventListener('scroll', stop, { + // Make sure to tell the browser the event will be prevented. + passive: false + }); + // Prevent the page from scrolling when dragging in the menu. + this.node.menu.addEventListener('touchmove', function (evnt) { + var panel = evnt.target.closest('.mm-panel'); + if (panel) { + // When dragging a non-scrollable panel, + // we can simple preventDefault and stopPropagation. + if (panel.scrollHeight === panel.offsetHeight) { + stop(evnt); + } + // When dragging a scrollable panel, + // that is fully scrolled up (or down). + // It will not trigger the scroll event when dragging down (or up) (because you can't scroll up (or down)), + // so we need to match the dragging direction with the scroll position before preventDefault and stopPropagation, + // otherwise the panel would not scroll at all in any direction. + else if ( + // When scrolled up and dragging down + (panel.scrollTop == 0 && touchDir.get() == 'down') || + // When scrolled down and dragging up + (panel.scrollHeight == + panel.scrollTop + panel.offsetHeight && + touchDir.get() == 'up')) { + stop(evnt); + } + // When dragging anything other than a panel. + } + else { + stop(evnt); + } + }, { + // Make sure to tell the browser the event can be prevented. + passive: false + }); + // Some small additional improvements + // Scroll the current opened panel to the top when opening the menu. + this.bind('open:start', function () { + var panel = DOM.children(_this.node.pnls, '.mm-panel_opened')[0]; + if (panel) { + panel.scrollTop = 0; + } + }); + // Fix issue after device rotation change. + window.addEventListener('orientationchange', function (evnt) { + var panel = DOM.children(_this.node.pnls, '.mm-panel_opened')[0]; + if (panel) { + panel.scrollTop = 0; + // Apparently, changing the overflow-scrolling property triggers some event :) + panel.style['-webkit-overflow-scrolling'] = 'auto'; + panel.style['-webkit-overflow-scrolling'] = 'touch'; + } + }); +} diff --git a/dist/extensions/borderstyle/mmenu.borderstyle.css b/dist/extensions/borderstyle/mmenu.borderstyle.css new file mode 100644 index 0000000..414101b --- /dev/null +++ b/dist/extensions/borderstyle/mmenu.borderstyle.css @@ -0,0 +1 @@ +.mm-menu_border-none .mm-listitem:after{content:none}.mm-menu_border-full .mm-listitem:after{left:0!important} \ No newline at end of file diff --git a/dist/extensions/effects/mmenu.effects.css b/dist/extensions/effects/mmenu.effects.css new file mode 100644 index 0000000..d22a3f8 --- /dev/null +++ b/dist/extensions/effects/mmenu.effects.css @@ -0,0 +1 @@ +.mm-menu_fx-menu-slide{-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;-o-transition:transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease}.mm-wrapper_opened .mm-menu_fx-menu-slide{-webkit-transform:translate3d(-30%,0,0);transform:translate3d(-30%,0,0)}.mm-wrapper_opening .mm-menu_fx-menu-slide{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-wrapper_opened .mm-menu_fx-menu-slide.mm-menu_position-right{-webkit-transform:translate3d(30%,0,0);transform:translate3d(30%,0,0)}.mm-wrapper_opening .mm-menu_fx-menu-slide.mm-menu_position-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-menu_fx-panels-none .mm-panel,.mm-panel_fx-none{-webkit-transition-property:none;-o-transition-property:none;transition-property:none}.mm-menu_fx-panels-none .mm-panel.mm-panel_opened-parent,.mm-panel_fx-none.mm-panel_opened-parent{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-menu_fx-panels-slide-0 .mm-panel_opened-parent{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-menu_fx-panels-slide-100 .mm-panel_opened-parent{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)} \ No newline at end of file diff --git a/dist/extensions/fullscreen/mmenu.fullscreen.css b/dist/extensions/fullscreen/mmenu.fullscreen.css new file mode 100644 index 0000000..6e3d275 --- /dev/null +++ b/dist/extensions/fullscreen/mmenu.fullscreen.css @@ -0,0 +1 @@ +.mm-menu_fullscreen{width:100%;min-width:140px;max-width:10000px}.mm-wrapper_opening .mm-menu_fullscreen~.mm-slideout{-webkit-transform:translate3d(100vw,0,0);transform:translate3d(100vw,0,0)}@media all and (max-width:140px){.mm-wrapper_opening .mm-menu_fullscreen~.mm-slideout{-webkit-transform:translate3d(140px,0,0);transform:translate3d(140px,0,0)}}@media all and (min-width:10000px){.mm-wrapper_opening .mm-menu_fullscreen~.mm-slideout{-webkit-transform:translate3d(10000px,0,0);transform:translate3d(10000px,0,0)}}.mm-wrapper_opening .mm-menu_fullscreen.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-100vw,0,0);transform:translate3d(-100vw,0,0)}@media all and (max-width:140px){.mm-wrapper_opening .mm-menu_fullscreen.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-140px,0,0);transform:translate3d(-140px,0,0)}}@media all and (min-width:10000px){.mm-wrapper_opening .mm-menu_fullscreen.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-10000px,0,0);transform:translate3d(-10000px,0,0)}}.mm-menu_fullscreen.mm-menu_position-top{height:100vh;min-height:140px;max-height:10000px}.mm-menu_fullscreen.mm-menu_position-bottom{height:100vh;min-height:140px;max-height:10000px} \ No newline at end of file diff --git a/dist/extensions/listview/mmenu.listview.css b/dist/extensions/listview/mmenu.listview.css new file mode 100644 index 0000000..63240c9 --- /dev/null +++ b/dist/extensions/listview/mmenu.listview.css @@ -0,0 +1 @@ +.mm-menu_listview-justify .mm-panels>.mm-panel{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.mm-menu_listview-justify .mm-panels>.mm-panel:after{content:none;display:none}.mm-menu_listview-justify .mm-panels>.mm-panel .mm-listview{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:100%;margin-top:0;margin-bottom:0}.mm-menu_listview-justify .mm-panels>.mm-panel .mm-listitem{-webkit-box-flex:1;-ms-flex:1 0 auto;flex:1 0 auto;min-height:50px}.mm-menu_listview-justify .mm-panels>.mm-panel .mm-listitem__text{-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1 0 auto;flex:1 0 auto;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.mm-listview_inset{list-style:inside disc;width:100%;padding:0 30px 15px 30px;margin:0}.mm-listview_inset .mm-listitem{padding:5px 0} \ No newline at end of file diff --git a/dist/extensions/multiline/mmenu.multiline.css b/dist/extensions/multiline/mmenu.multiline.css new file mode 100644 index 0000000..283a493 --- /dev/null +++ b/dist/extensions/multiline/mmenu.multiline.css @@ -0,0 +1 @@ +.mm-menu_multiline .mm-listitem__text{-o-text-overflow:clip;text-overflow:clip;white-space:normal} \ No newline at end of file diff --git a/dist/extensions/pagedim/mmenu.pagedim.css b/dist/extensions/pagedim/mmenu.pagedim.css new file mode 100644 index 0000000..88bd20e --- /dev/null +++ b/dist/extensions/pagedim/mmenu.pagedim.css @@ -0,0 +1 @@ +[class*=mm-menu_pagedim].mm-menu_opened~.mm-wrapper__blocker{opacity:0}.mm-wrapper_opening [class*=mm-menu_pagedim].mm-menu_opened~.mm-wrapper__blocker{opacity:.3;-webkit-transition:opacity .4s ease .4s;-o-transition:opacity .4s ease .4s;transition:opacity .4s ease .4s}.mm-menu_opened.mm-menu_pagedim~.mm-wrapper__blocker{background:inherit}.mm-menu_opened.mm-menu_pagedim-black~.mm-wrapper__blocker{background:#000}.mm-menu_opened.mm-menu_pagedim-white~.mm-wrapper__blocker{background:#fff} \ No newline at end of file diff --git a/dist/extensions/popup/mmenu.popup.css b/dist/extensions/popup/mmenu.popup.css new file mode 100644 index 0000000..1dbacd0 --- /dev/null +++ b/dist/extensions/popup/mmenu.popup.css @@ -0,0 +1 @@ +.mm-menu_popup{-webkit-transition:opacity .4s ease;-o-transition:opacity .4s ease;transition:opacity .4s ease;opacity:0;-webkit-box-shadow:0 2px 10px rgba(0,0,0,.3);box-shadow:0 2px 10px rgba(0,0,0,.3);height:80%;min-height:140px;max-height:880px;top:50%;left:50%;bottom:auto;right:auto;z-index:2;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.mm-menu_popup.mm-menu_opened~.mm-slideout{-webkit-transform:none!important;-ms-transform:none!important;transform:none!important;z-index:0}.mm-menu_popup.mm-menu_opened~.mm-wrapper__blocker{-webkit-transition-delay:0s!important;-o-transition-delay:0s!important;transition-delay:0s!important;z-index:1}.mm-wrapper_opening .mm-menu_popup{opacity:1} \ No newline at end of file diff --git a/dist/extensions/positioning/mmenu.positioning.css b/dist/extensions/positioning/mmenu.positioning.css new file mode 100644 index 0000000..c17b19e --- /dev/null +++ b/dist/extensions/positioning/mmenu.positioning.css @@ -0,0 +1 @@ +.mm-menu_position-right{left:auto;right:0}.mm-wrapper_opening .mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:550px){.mm-wrapper_opening .mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-440px,0,0);transform:translate3d(-440px,0,0)}}.mm-menu_position-bottom,.mm-menu_position-front,.mm-menu_position-top{-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;-o-transition:transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease}.mm-menu_position-bottom.mm-menu_opened,.mm-menu_position-front.mm-menu_opened,.mm-menu_position-top.mm-menu_opened{z-index:2}.mm-menu_position-bottom.mm-menu_opened~.mm-slideout,.mm-menu_position-front.mm-menu_opened~.mm-slideout,.mm-menu_position-top.mm-menu_opened~.mm-slideout{-webkit-transform:none!important;-ms-transform:none!important;transform:none!important;z-index:0}.mm-menu_position-bottom.mm-menu_opened~.mm-wrapper__blocker,.mm-menu_position-front.mm-menu_opened~.mm-wrapper__blocker,.mm-menu_position-top.mm-menu_opened~.mm-wrapper__blocker{z-index:1}.mm-menu_position-front{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.mm-menu_position-front.mm-menu_position-right{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.mm-menu_position-bottom,.mm-menu_position-top{width:100%;min-width:100%;max-width:100%}.mm-menu_position-top{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}.mm-menu_position-top{height:80vh;min-height:140px;max-height:880px}.mm-menu_position-bottom{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);top:auto}.mm-menu_position-bottom{height:80vh;min-height:140px;max-height:880px}.mm-wrapper_opening .mm-menu_position-bottom,.mm-wrapper_opening .mm-menu_position-front,.mm-wrapper_opening .mm-menu_position-top{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)} \ No newline at end of file diff --git a/dist/extensions/shadows/mmenu.shadows.css b/dist/extensions/shadows/mmenu.shadows.css new file mode 100644 index 0000000..4b2e010 --- /dev/null +++ b/dist/extensions/shadows/mmenu.shadows.css @@ -0,0 +1 @@ +.mm-menu_shadow-page:after{-webkit-box-shadow:0 0 10px rgba(0,0,0,.3);box-shadow:0 0 10px rgba(0,0,0,.3);content:'';display:block;width:20px;height:120%;position:absolute;left:100%;top:-10%;z-index:100;-webkit-clip-path:polygon(-20px 0,0 0,0 100%,-20px 100%);clip-path:polygon(-20px 0,0 0,0 100%,-20px 100%);-webkit-box-shadow:var(--mm-shadow);box-shadow:var(--mm-shadow)}.mm-menu_shadow-page.mm-menu_position-right:after{left:auto;right:100%;-webkit-clip-path:polygon(20px 0,40px 0,40px 100%,20px 100%);clip-path:polygon(20px 0,40px 0,40px 100%,20px 100%)}.mm-menu_shadow-page.mm-menu_position-front:after{content:none;display:none}.mm-menu_shadow-menu{-webkit-box-shadow:0 0 10px rgba(0,0,0,.3);box-shadow:0 0 10px rgba(0,0,0,.3);-webkit-box-shadow:var(--mm-shadow);box-shadow:var(--mm-shadow)}.mm-menu_shadow-panels .mm-panels>.mm-panel{-webkit-box-shadow:0 0 10px rgba(0,0,0,.3);box-shadow:0 0 10px rgba(0,0,0,.3);-webkit-box-shadow:var(--mm-shadow);box-shadow:var(--mm-shadow)} \ No newline at end of file diff --git a/dist/extensions/themes/mmenu.themes.css b/dist/extensions/themes/mmenu.themes.css new file mode 100644 index 0000000..5406b07 --- /dev/null +++ b/dist/extensions/themes/mmenu.themes.css @@ -0,0 +1 @@ +.mm-menu_theme-white{--mm-color-border:rgba( 0,0,0, 0.1 );--mm-color-button:rgba( 0,0,0, 0.3 );--mm-color-text:rgba( 0,0,0, 0.7 );--mm-color-text-dimmed:rgba( 0,0,0, 0.3 );--mm-color-background:#fff;--mm-color-background-highlight:rgba( 0,0,0, 0.06 );--mm-color-background-emphasis:rgba( 0,0,0, 0.03 );--mm-shadow:0 0 10px rgba( 0,0,0, 0.2 )}.mm-menu_theme-dark{--mm-color-border:rgba( 0,0,0, 0.3 );--mm-color-button:rgba( 255,255,255, 0.4 );--mm-color-text:rgba( 255,255,255, 0.85 );--mm-color-text-dimmed:rgba( 255,255,255, 0.4 );--mm-color-background:#333;--mm-color-background-highlight:rgba( 255,255,255, 0.08 );--mm-color-background-emphasis:rgba( 0,0,0, 0.1 );--mm-shadow:0 0 20px rgba( 0,0,0, 0.5 )}.mm-menu_theme-black{--mm-color-border:rgba( 255,255,255, 0.25 );--mm-color-button:rgba( 255,255,255, 0.4 );--mm-color-text:rgba( 255,255,255, 0.75 );--mm-color-text-dimmed:rgba( 255,255,255, 0.4 );--mm-color-background:#000;--mm-color-background-highlight:rgba( 255,255,255, 0.2 );--mm-color-background-emphasis:rgba( 255,255,255, 0.15 );--mm-shadow:none} \ No newline at end of file diff --git a/dist/mmenu.css b/dist/mmenu.css new file mode 100644 index 0000000..4195835 --- /dev/null +++ b/dist/mmenu.css @@ -0,0 +1,10 @@ +/*! + * mmenu.js + * mmenujs.com + * + * Copyright (c) Fred Heusschen + * frebsite.nl + * + * License: CC-BY-NC-4.0 + * http://creativecommons.org/licenses/by-nc/4.0/ + */.mm-menu_theme-white{--mm-color-border:rgba( 0,0,0, 0.1 );--mm-color-button:rgba( 0,0,0, 0.3 );--mm-color-text:rgba( 0,0,0, 0.7 );--mm-color-text-dimmed:rgba( 0,0,0, 0.3 );--mm-color-background:#fff;--mm-color-background-highlight:rgba( 0,0,0, 0.06 );--mm-color-background-emphasis:rgba( 0,0,0, 0.03 );--mm-shadow:0 0 10px rgba( 0,0,0, 0.2 )}.mm-menu_theme-dark{--mm-color-border:rgba( 0,0,0, 0.3 );--mm-color-button:rgba( 255,255,255, 0.4 );--mm-color-text:rgba( 255,255,255, 0.85 );--mm-color-text-dimmed:rgba( 255,255,255, 0.4 );--mm-color-background:#333;--mm-color-background-highlight:rgba( 255,255,255, 0.08 );--mm-color-background-emphasis:rgba( 0,0,0, 0.1 );--mm-shadow:0 0 20px rgba( 0,0,0, 0.5 )}.mm-menu_theme-black{--mm-color-border:rgba( 255,255,255, 0.25 );--mm-color-button:rgba( 255,255,255, 0.4 );--mm-color-text:rgba( 255,255,255, 0.75 );--mm-color-text-dimmed:rgba( 255,255,255, 0.4 );--mm-color-background:#000;--mm-color-background-highlight:rgba( 255,255,255, 0.2 );--mm-color-background-emphasis:rgba( 255,255,255, 0.15 );--mm-shadow:none}:root{--mm-line-height:20px;--mm-listitem-size:44px;--mm-navbar-size:44px;--mm-offset-top:0;--mm-offset-right:0;--mm-offset-bottom:0;--mm-offset-left:0;--mm-color-border:rgba(0, 0, 0, 0.1);--mm-color-button:rgba(0, 0, 0, 0.3);--mm-color-text:rgba(0, 0, 0, 0.75);--mm-color-text-dimmed:rgba(0, 0, 0, 0.3);--mm-color-background:#f3f3f3;--mm-color-background-highlight:rgba(0, 0, 0, 0.05);--mm-color-background-emphasis:rgba(255, 255, 255, 0.4);--mm-shadow:0 0 10px rgba(0, 0, 0, 0.3)}.mm-hidden{display:none!important}.mm-wrapper{overflow-x:hidden;position:relative}.mm-menu{top:0;right:0;bottom:0;left:0;background:#f3f3f3;border-color:rgba(0,0,0,.1);color:rgba(0,0,0,.75);line-height:20px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;padding:0;margin:0;-webkit-box-sizing:border-box;box-sizing:border-box;position:absolute;top:var(--mm-offset-top);right:var(--mm-offset-right);bottom:var(--mm-offset-bottom);left:var(--mm-offset-left);z-index:0;background:var(--mm-color-background);border-color:var(--mm-color-border);color:var(--mm-color-text);line-height:var(--mm-line-height);-webkit-tap-highlight-color:var(--mm-color-background-emphasis);-webkit-font-smoothing:antialiased;-moz-osx-font-smoothing:grayscale}.mm-menu a,.mm-menu a:active,.mm-menu a:hover,.mm-menu a:link,.mm-menu a:visited{text-decoration:none;color:inherit}[dir=rtl] .mm-menu{direction:rtl}.mm-panel{background:#f3f3f3;border-color:rgba(0,0,0,.1);color:rgba(0,0,0,.75);z-index:0;-webkit-box-sizing:border-box;box-sizing:border-box;width:100%;-webkit-overflow-scrolling:touch;overflow:scroll;overflow-x:hidden;overflow-y:auto;background:var(--mm-color-background);border-color:var(--mm-color-border);color:var(--mm-color-text);-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0);-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;-o-transition:transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease}.mm-panel:after{height:44px}.mm-panel:not(.mm-hidden){display:block}.mm-panel:after{content:'';display:block;height:var(--mm-listitem-size)}.mm-panel_opened{z-index:1;-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-panel_opened-parent{-webkit-transform:translate3d(-30%,0,0);transform:translate3d(-30%,0,0)}.mm-panel_highest{z-index:2}.mm-panel_noanimation{-webkit-transition:none!important;-o-transition:none!important;transition:none!important}.mm-panel_noanimation.mm-panel_opened-parent{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-panels>.mm-panel{position:absolute;left:0;right:0;top:0;bottom:0}.mm-panel__content{padding:20px 20px 0}.mm-panels{background:#f3f3f3;border-color:rgba(0,0,0,.1);color:rgba(0,0,0,.75);position:relative;height:100%;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;overflow:hidden;background:var(--mm-color-background);border-color:var(--mm-color-border);color:var(--mm-color-text)}[dir=rtl] .mm-panel:not(.mm-panel_opened){-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}[dir=rtl] .mm-panel.mm-panel_opened-parent{-webkit-transform:translate3d(30%,0,0);transform:translate3d(30%,0,0)}.mm-listitem_vertical>.mm-panel{display:none;width:100%;padding:10px 0 10px 10px;-webkit-transform:none!important;-ms-transform:none!important;transform:none!important}.mm-listitem_vertical>.mm-panel:after,.mm-listitem_vertical>.mm-panel:before{content:none;display:none}.mm-listitem_opened>.mm-panel{display:block}.mm-listitem_vertical>.mm-listitem__btn{height:44px;height:var(--mm-listitem-size);bottom:auto}.mm-listitem_vertical .mm-listitem:last-child:after{border-color:transparent}.mm-listitem_opened>.mm-listitem__btn:after{-webkit-transform:rotate(225deg);-ms-transform:rotate(225deg);transform:rotate(225deg);right:19px}.mm-btn{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0;-ms-flex-negative:0;flex-shrink:0;position:relative;-webkit-box-sizing:border-box;box-sizing:border-box;width:50px;padding:0}.mm-btn:after,.mm-btn:before{border:2px solid rgba(0,0,0,.3);border:2px solid var(--mm-color-button)}.mm-btn_next:after,.mm-btn_prev:before{content:'';border-bottom:none;border-right:none;-webkit-box-sizing:content-box;box-sizing:content-box;display:block;width:8px;height:8px;margin:auto;position:absolute;top:0;bottom:0}.mm-btn_prev:before{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg);left:23px;right:auto}.mm-btn_next:after{-webkit-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg);right:23px;left:auto}.mm-btn_close:after,.mm-btn_close:before{content:'';-webkit-box-sizing:content-box;box-sizing:content-box;display:block;width:5px;height:5px;margin:auto;position:absolute;top:0;bottom:0;-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg)}.mm-btn_close:before{border-right:none;border-bottom:none;right:18px}.mm-btn_close:after{border-left:none;border-top:none;right:25px}[dir=rtl] .mm-btn_next:after{-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg);left:23px;right:auto}[dir=rtl] .mm-btn_prev:before{-webkit-transform:rotate(135deg);-ms-transform:rotate(135deg);transform:rotate(135deg);right:23px;left:auto}[dir=rtl] .mm-btn_close:after,[dir=rtl] .mm-btn_close:before{right:auto}[dir=rtl] .mm-btn_close:before{left:25px}[dir=rtl] .mm-btn_close:after{left:18px}.mm-navbar{min-height:44px;border-bottom:1px solid rgba(0,0,0,.1);background:#f3f3f3;color:rgba(0,0,0,.3);display:-webkit-box;display:-ms-flexbox;display:flex;min-height:var(--mm-navbar-size);border-bottom:1px solid var(--mm-color-border);background:var(--mm-color-background);color:var(--mm-color-text-dimmed);text-align:center;opacity:1;-webkit-transition:opacity .4s ease;-o-transition:opacity .4s ease;transition:opacity .4s ease}.mm-navbar>*{min-height:44px}@supports ((position:-webkit-sticky) or (position:sticky)){.mm-navbar_sticky{position:-webkit-sticky;position:sticky;top:0;z-index:1}}.mm-navbar>*{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;-webkit-box-sizing:border-box;box-sizing:border-box}.mm-navbar__btn{-webkit-box-flex:0;-ms-flex-positive:0;flex-grow:0}.mm-navbar__title{-webkit-box-flex:1;-ms-flex:1 1 50%;flex:1 1 50%;display:-webkit-box;display:-ms-flexbox;display:flex;padding-left:20px;padding-right:20px;overflow:hidden}.mm-navbar__title:not(:last-child){padding-right:0}.mm-navbar__title>span{-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;overflow:hidden}.mm-navbar__btn:not(.mm-hidden)+.mm-navbar__title{padding-left:0}.mm-navbar__btn:not(.mm-hidden)+.mm-navbar__title:last-child{padding-right:50px}[dir=rtl] .mm-navbar{-webkit-box-orient:horizontal;-webkit-box-direction:reverse;-ms-flex-direction:row-reverse;flex-direction:row-reverse}.mm-listview{list-style:none;display:block;padding:0;margin:0}.mm-listitem{color:rgba(0,0,0,.75);border-color:rgba(0,0,0,.1);color:var(--mm-color-text);border-color:var(--mm-color-border);list-style:none;display:block;padding:0;margin:0;position:relative;display:-webkit-box;display:-ms-flexbox;display:flex;-ms-flex-wrap:wrap;flex-wrap:wrap}.mm-listitem:after{content:'';border-color:inherit;border-bottom-width:1px;border-bottom-style:solid;display:block;position:absolute;left:20px;right:0;bottom:0}.mm-listitem a,.mm-listitem a:hover{text-decoration:none}.mm-listitem__btn,.mm-listitem__text{padding:12px;display:block;padding:calc((var(--mm-listitem-size) - var(--mm-line-height))/ 2);padding-left:0;padding-right:0;color:inherit}.mm-listitem__text{-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;padding-left:20px;padding-right:10px;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;-ms-flex-preferred-size:10%;flex-basis:10%}.mm-listitem__btn{background:rgba(3,2,1,0);border-color:inherit;width:auto;padding-right:50px;position:relative}.mm-listitem__btn:not(.mm-listitem__text){border-left-width:1px;border-left-style:solid}.mm-listitem_selected>.mm-listitem__text{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)}.mm-listitem_opened>.mm-listitem__btn,.mm-listitem_opened>.mm-panel{background:rgba(0,0,0,.05);background:var(--mm-color-background-highlight)}[dir=rtl] .mm-listitem:after{left:0;right:20px}[dir=rtl] .mm-listitem__text{padding-left:10px;padding-right:20px}[dir=rtl] .mm-listitem__btn{padding-left:50px;border-left-width:0;border-left-style:none}[dir=rtl] .mm-listitem__btn:not(.mm-listitem__text){padding-right:0;border-right-width:1px;border-right-style:solid}.mm-page{-webkit-box-sizing:border-box;box-sizing:border-box;position:relative}.mm-slideout{-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;-o-transition:transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease;z-index:1}.mm-wrapper_opened{overflow-x:hidden;position:relative}.mm-wrapper_opened .mm-page{min-height:100vh}.mm-wrapper_background .mm-page{background:inherit}.mm-menu_offcanvas{position:fixed;right:auto;z-index:0}.mm-menu_offcanvas:not(.mm-menu_opened){display:none}.mm-menu_offcanvas{width:80%;min-width:240px;max-width:440px}.mm-wrapper_opening .mm-menu_offcanvas~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_offcanvas~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:550px){.mm-wrapper_opening .mm-menu_offcanvas~.mm-slideout{-webkit-transform:translate3d(440px,0,0);transform:translate3d(440px,0,0)}}.mm-wrapper__blocker{background:rgba(3,2,1,0);overflow:hidden;display:none;position:fixed;top:0;right:0;bottom:0;left:0;z-index:2}.mm-wrapper_blocking{overflow:hidden}.mm-wrapper_blocking body{overflow:hidden}.mm-wrapper_blocking .mm-wrapper__blocker{display:block}.mm-sronly{border:0!important;clip:rect(1px,1px,1px,1px)!important;-webkit-clip-path:inset(50%)!important;clip-path:inset(50%)!important;white-space:nowrap!important;width:1px!important;min-width:1px!important;height:1px!important;min-height:1px!important;padding:0!important;overflow:hidden!important;position:absolute!important}.mm-menu_autoheight:not(.mm-menu_offcanvas){position:relative}.mm-menu_autoheight.mm-menu_position-bottom,.mm-menu_autoheight.mm-menu_position-top{max-height:80%}.mm-menu_autoheight-measuring .mm-panel{display:block!important}.mm-menu_autoheight-measuring .mm-panels>.mm-panel{bottom:auto!important;height:auto!important}.mm-menu_autoheight-measuring .mm-listitem_vertical:not(.mm-listitem_opened) .mm-panel{display:none!important}[class*=mm-menu_columns-]{-webkit-transition-property:width;-o-transition-property:width;transition-property:width}[class*=mm-menu_columns-] .mm-panels>.mm-panel{right:auto;-webkit-transition-property:width,-webkit-transform;transition-property:width,-webkit-transform;-o-transition-property:width,transform;transition-property:width,transform;transition-property:width,transform,-webkit-transform}[class*=mm-menu_columns-] .mm-panels>.mm-panel_opened,[class*=mm-menu_columns-] .mm-panels>.mm-panel_opened-parent{display:block!important}[class*=mm-panel_columns-]{border-right:1px solid;border-color:inherit}.mm-menu_columns-1 .mm-panel_columns-0,.mm-menu_columns-2 .mm-panel_columns-1,.mm-menu_columns-3 .mm-panel_columns-2,.mm-menu_columns-4 .mm-panel_columns-3{border-right:none}[class*=mm-menu_columns-] .mm-panels>.mm-panel_columns-0{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-menu_columns-0 .mm-panels>.mm-panel{z-index:0}.mm-menu_columns-0 .mm-panels>.mm-panel else{width:100%}.mm-menu_columns-0 .mm-panels>.mm-panel:not(.mm-panel_opened):not(.mm-panel_opened-parent){-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.mm-menu_columns-0{width:80%;min-width:240px;max-width:0}.mm-wrapper_opening .mm-menu_columns-0~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-0~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:0px){.mm-wrapper_opening .mm-menu_columns-0~.mm-slideout{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}.mm-wrapper_opening .mm-menu_columns-0.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-0.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:0px){.mm-wrapper_opening .mm-menu_columns-0.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}}[class*=mm-menu_columns-] .mm-panels>.mm-panel_columns-1{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.mm-menu_columns-1 .mm-panels>.mm-panel{z-index:1;width:100%}.mm-menu_columns-1 .mm-panels>.mm-panel else{width:100%}.mm-menu_columns-1 .mm-panels>.mm-panel:not(.mm-panel_opened):not(.mm-panel_opened-parent){-webkit-transform:translate3d(200%,0,0);transform:translate3d(200%,0,0)}.mm-menu_columns-1{width:80%;min-width:240px;max-width:440px}.mm-wrapper_opening .mm-menu_columns-1~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-1~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:550px){.mm-wrapper_opening .mm-menu_columns-1~.mm-slideout{-webkit-transform:translate3d(440px,0,0);transform:translate3d(440px,0,0)}}.mm-wrapper_opening .mm-menu_columns-1.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-1.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:550px){.mm-wrapper_opening .mm-menu_columns-1.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-440px,0,0);transform:translate3d(-440px,0,0)}}[class*=mm-menu_columns-] .mm-panels>.mm-panel_columns-2{-webkit-transform:translate3d(200%,0,0);transform:translate3d(200%,0,0)}.mm-menu_columns-2 .mm-panels>.mm-panel{z-index:2;width:50%}.mm-menu_columns-2 .mm-panels>.mm-panel else{width:100%}.mm-menu_columns-2 .mm-panels>.mm-panel:not(.mm-panel_opened):not(.mm-panel_opened-parent){-webkit-transform:translate3d(300%,0,0);transform:translate3d(300%,0,0)}.mm-menu_columns-2{width:80%;min-width:240px;max-width:880px}.mm-wrapper_opening .mm-menu_columns-2~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-2~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:1100px){.mm-wrapper_opening .mm-menu_columns-2~.mm-slideout{-webkit-transform:translate3d(880px,0,0);transform:translate3d(880px,0,0)}}.mm-wrapper_opening .mm-menu_columns-2.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-2.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:1100px){.mm-wrapper_opening .mm-menu_columns-2.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-880px,0,0);transform:translate3d(-880px,0,0)}}[class*=mm-menu_columns-] .mm-panels>.mm-panel_columns-3{-webkit-transform:translate3d(300%,0,0);transform:translate3d(300%,0,0)}.mm-menu_columns-3 .mm-panels>.mm-panel{z-index:3;width:33.34%}.mm-menu_columns-3 .mm-panels>.mm-panel else{width:100%}.mm-menu_columns-3 .mm-panels>.mm-panel:not(.mm-panel_opened):not(.mm-panel_opened-parent){-webkit-transform:translate3d(400%,0,0);transform:translate3d(400%,0,0)}.mm-menu_columns-3{width:80%;min-width:240px;max-width:1320px}.mm-wrapper_opening .mm-menu_columns-3~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-3~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:1650px){.mm-wrapper_opening .mm-menu_columns-3~.mm-slideout{-webkit-transform:translate3d(1320px,0,0);transform:translate3d(1320px,0,0)}}.mm-wrapper_opening .mm-menu_columns-3.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-3.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:1650px){.mm-wrapper_opening .mm-menu_columns-3.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-1320px,0,0);transform:translate3d(-1320px,0,0)}}[class*=mm-menu_columns-] .mm-panels>.mm-panel_columns-4{-webkit-transform:translate3d(400%,0,0);transform:translate3d(400%,0,0)}.mm-menu_columns-4 .mm-panels>.mm-panel{z-index:4;width:25%}.mm-menu_columns-4 .mm-panels>.mm-panel else{width:100%}.mm-menu_columns-4 .mm-panels>.mm-panel:not(.mm-panel_opened):not(.mm-panel_opened-parent){-webkit-transform:translate3d(500%,0,0);transform:translate3d(500%,0,0)}.mm-menu_columns-4{width:80%;min-width:240px;max-width:1760px}.mm-wrapper_opening .mm-menu_columns-4~.mm-slideout{-webkit-transform:translate3d(80vw,0,0);transform:translate3d(80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-4~.mm-slideout{-webkit-transform:translate3d(240px,0,0);transform:translate3d(240px,0,0)}}@media all and (min-width:2200px){.mm-wrapper_opening .mm-menu_columns-4~.mm-slideout{-webkit-transform:translate3d(1760px,0,0);transform:translate3d(1760px,0,0)}}.mm-wrapper_opening .mm-menu_columns-4.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_columns-4.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:2200px){.mm-wrapper_opening .mm-menu_columns-4.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-1760px,0,0);transform:translate3d(-1760px,0,0)}}[class*=mm-menu_columns-].mm-menu_position-bottom,[class*=mm-menu_columns-].mm-menu_position-top{width:100%;max-width:100%;min-width:100%}.mm-wrapper_opening [class*=mm-menu_columns-].mm-menu_position-front{-webkit-transition-property:width,min-width,max-width,-webkit-transform;transition-property:width,min-width,max-width,-webkit-transform;-o-transition-property:width,min-width,max-width,transform;transition-property:width,min-width,max-width,transform;transition-property:width,min-width,max-width,transform,-webkit-transform}.mm-counter{color:rgba(0,0,0,.3);display:block;padding-left:20px;float:right;text-align:right;color:var(--mm-color-text-dimmed)}.mm-listitem_nosubitems>.mm-counter{display:none}[dir=rtl] .mm-counter{text-align:left;float:left;padding-left:0;padding-right:20px}.mm-divider{position:relative;min-height:20px;padding:4.3px;background:#f3f3f3;-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;min-height:var(--mm-line-height);padding:calc(((var(--mm-listitem-size) * .65) - var(--mm-line-height)) * .5);padding-right:10px;padding-left:20px;font-size:75%;text-transform:uppercase;background:var(--mm-color-background);opacity:1;-webkit-transition:opacity .4s ease;-o-transition:opacity .4s ease;transition:opacity .4s ease}.mm-divider:before{background:rgba(0,0,0,.05)}@supports ((position:-webkit-sticky) or (position:sticky)){.mm-divider{position:-webkit-sticky;position:sticky;z-index:2;top:0}.mm-navbar_sticky:not(.mm-hidden)~.mm-listview .mm-divider{top:var(--mm-navbar-size)}}.mm-divider:before{content:'';position:absolute;top:0;right:0;bottom:0;left:0;z-index:-1;background:var(--mm-color-background-highlight)}.mm-wrapper_dragging .mm-menu,.mm-wrapper_dragging .mm-slideout{-webkit-transition-duration:0s!important;-o-transition-duration:0s!important;transition-duration:0s!important;-webkit-user-select:none!important;-moz-user-select:none!important;-ms-user-select:none!important;user-select:none!important}.mm-wrapper_dragging .mm-menu{pointer-events:none!important}.mm-wrapper_dragging .mm-wrapper__blocker{display:none!important}.mm-menu_dropdown{-webkit-box-shadow:0 2px 10px rgba(0,0,0,.3);box-shadow:0 2px 10px rgba(0,0,0,.3);height:80%}.mm-wrapper_dropdown .mm-slideout{-webkit-transform:none!important;-ms-transform:none!important;transform:none!important;z-index:0}.mm-wrapper_dropdown .mm-wrapper__blocker{-webkit-transition-delay:0s!important;-o-transition-delay:0s!important;transition-delay:0s!important;z-index:1}.mm-wrapper_dropdown .mm-menu_dropdown{z-index:2}.mm-wrapper_dropdown.mm-wrapper_opened:not(.mm-wrapper_opening) .mm-menu_dropdown{display:none}.mm-menu_tip-bottom:before,.mm-menu_tip-left:before,.mm-menu_tip-right:before,.mm-menu_tip-top:before{content:'';background:inherit;-webkit-box-shadow:0 2px 10px rgba(0,0,0,.3);box-shadow:0 2px 10px rgba(0,0,0,.3);display:block;width:15px;height:15px;position:absolute;z-index:-1;-webkit-transform:rotate(45deg);-ms-transform:rotate(45deg);transform:rotate(45deg)}.mm-menu_tip-left:before{left:22px}.mm-menu_tip-right:before{right:22px}.mm-menu_tip-top:before{top:-8px}.mm-menu_tip-bottom:before{bottom:-8px}:root{--mm-iconbar-size:50px}.mm-menu_iconbar-left .mm-navbars_bottom,.mm-menu_iconbar-left .mm-navbars_top,.mm-menu_iconbar-left .mm-panels{margin-left:50px;margin-left:var(--mm-iconbar-size)}.mm-menu_iconbar-left .mm-iconbar{border-right-width:1px;display:block;left:0}.mm-menu_iconbar-right .mm-navbars_bottom,.mm-menu_iconbar-right .mm-navbars_top,.mm-menu_iconbar-right .mm-panels{margin-right:50px;margin-right:var(--mm-iconbar-size)}.mm-menu_iconbar-right .mm-iconbar{border-left-width:1px;display:block;right:0}.mm-iconbar{width:50px;border-color:rgba(0,0,0,.1);background:#f3f3f3;color:rgba(0,0,0,.3);display:none;width:var(--mm-iconbar-size);overflow:hidden;-webkit-box-sizing:border-box;box-sizing:border-box;position:absolute;top:0;bottom:0;z-index:2;border:0 solid;border-color:var(--mm-color-border);background:var(--mm-color-background);color:var(--mm-color-text-dimmed);text-align:center}.mm-iconbar__bottom,.mm-iconbar__top{width:inherit;position:absolute}.mm-iconbar__bottom>*,.mm-iconbar__top>*{-webkit-box-sizing:border-box;box-sizing:border-box;display:block;padding:12.5px 0}.mm-iconbar__bottom a,.mm-iconbar__bottom a:hover,.mm-iconbar__top a,.mm-iconbar__top a:hover{text-decoration:none}.mm-iconbar__top{top:0}.mm-iconbar__bottom{bottom:0}.mm-iconbar__tab_selected{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)}:root{--mm-iconpanel-size:50px}.mm-panel_iconpanel-1{width:calc(100% - 50px);width:calc(100% - (var(--mm-iconpanel-size) * 1))}.mm-panel_iconpanel-2{width:calc(100% - 100px);width:calc(100% - (var(--mm-iconpanel-size) * 2))}.mm-panel_iconpanel-3{width:calc(100% - 150px);width:calc(100% - (var(--mm-iconpanel-size) * 3))}.mm-panel_iconpanel-first~.mm-panel{width:calc(100% - 50px);width:calc(100% - var(--mm-iconpanel-size))}.mm-menu_iconpanel .mm-panels>.mm-panel{left:auto;-webkit-transition-property:width,-webkit-transform;transition-property:width,-webkit-transform;-o-transition-property:transform,width;transition-property:transform,width;transition-property:transform,width,-webkit-transform}.mm-menu_iconpanel .mm-panels>.mm-panel_opened,.mm-menu_iconpanel .mm-panels>.mm-panel_opened-parent{display:block!important}.mm-menu_iconpanel .mm-panels>.mm-panel_opened-parent{overflow-y:hidden;-webkit-transform:unset;-ms-transform:unset;transform:unset}.mm-menu_iconpanel .mm-panels>.mm-panel:not(.mm-panel_iconpanel-first):not(.mm-panel_iconpanel-0){border-left-width:1px;border-left-style:solid}.mm-menu_hidedivider .mm-panel_opened-parent .mm-divider,.mm-menu_hidenavbar .mm-panel_opened-parent .mm-navbar{opacity:0}.mm-panel__blocker{background:inherit;opacity:0;display:block;position:absolute;top:0;right:0;left:0;z-index:3;-webkit-transition:opacity .4s ease;-o-transition:opacity .4s ease;transition:opacity .4s ease}.mm-panel_opened-parent .mm-panel__blocker{opacity:.6;bottom:-100000px}[dir=rtl] .mm-menu_iconpanel .mm-panels>.mm-panel{left:0;right:auto;-webkit-transition-property:width,-webkit-transform;transition-property:width,-webkit-transform;-o-transition-property:transform,width;transition-property:transform,width;transition-property:transform,width,-webkit-transform}[dir=rtl] .mm-menu_iconpanel .mm-panels>.mm-panel:not(.mm-panel_iconpanel-first):not(.mm-panel_iconpanel-0){border-left:none;border-right:1px solid;border-color:inherit}.mm-menu_keyboardfocus a:focus,.mm-menu_keyboardfocus.mm-menu_opened~.mm-wrapper__blocker a:focus{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis);outline:0}.mm-wrapper__blocker .mm-tabstart{cursor:default;display:block;width:100%;height:100%}.mm-wrapper__blocker .mm-tabend{opacity:0;position:absolute;bottom:0}.mm-navbars_top{-ms-flex-negative:0;flex-shrink:0}.mm-navbars_top .mm-navbar:not(:last-child){border-bottom:none}.mm-navbars_bottom{-ms-flex-negative:0;flex-shrink:0}.mm-navbars_bottom .mm-navbar{border-bottom:none}.mm-navbars_bottom .mm-navbar:first-child{border-top:1px solid rgba(0,0,0,.1);border-top:1px solid var(--mm-color-border)}.mm-btn:not(.mm-hidden)+.mm-navbar__searchfield .mm-searchfield__input{padding-left:0}.mm-navbar__searchfield:not(:last-child) .mm-searchfield__input{padding-right:0}.mm-navbar__breadcrumbs{-o-text-overflow:ellipsis;text-overflow:ellipsis;white-space:nowrap;overflow:hidden;-webkit-box-flex:1;-ms-flex:1 1 50%;flex:1 1 50%;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-pack:start;-ms-flex-pack:start;justify-content:flex-start;padding:0 20px;overflow-x:auto;-webkit-overflow-scrolling:touch}.mm-navbar__breadcrumbs>*{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center;-webkit-box-pack:center;-ms-flex-pack:center;justify-content:center;padding-right:6px}.mm-navbar__breadcrumbs>a{text-decoration:underline}.mm-navbar__breadcrumbs:not(:last-child){padding-right:0}.mm-btn:not(.mm-hidden)+.mm-navbar__breadcrumbs{padding-left:0}.mm-navbar_tabs>*{padding:0 10px;border:1px solid transparent}.mm-navbar__tab_selected{background:#f3f3f3;color:rgba(0,0,0,.75);background:var(--mm-color-background);color:var(--mm-color-text)}.mm-navbar__tab_selected:not(:first-child){border-left-color:rgba(0,0,0,.1)}.mm-navbar__tab_selected:not(:last-child){border-right-color:rgba(0,0,0,.1)}.mm-navbar__tab_selected:not(:first-child){border-left-color:var(--mm-color-border)}.mm-navbar__tab_selected:not(:last-child){border-right-color:var(--mm-color-border)}.mm-navbars_top .mm-navbar_tabs{border-bottom:none}.mm-navbars_top .mm-navbar_tabs>*{border-bottom-color:rgba(0,0,0,.1);border-bottom-color:var(--mm-color-border)}.mm-navbars_top .mm-navbar__tab_selected{border-top-color:rgba(0,0,0,.1);border-top-color:var(--mm-color-border);border-bottom-color:transparent}.mm-navbars_top.mm-navbars_has-tabs .mm-navbar{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)}.mm-navbars_top.mm-navbars_has-tabs .mm-navbar_tabs~.mm-navbar{background:#f3f3f3;background:var(--mm-color-background)}.mm-navbars_bottom .mm-navbar_tabs:first-child{border-top:none}.mm-navbars_bottom .mm-navbar_tabs>*{border-top-color:rgba(0,0,0,.1);border-top-color:var(--mm-color-border)}.mm-navbars_bottom .mm-navbar__tab_selected{border-bottom-color:rgba(0,0,0,.1);border-bottom-color:var(--mm-color-border);border-top-color:transparent}.mm-navbars_bottom.mm-navbars_has-tabs .mm-navbar{background:#f3f3f3;background:var(--mm-color-background)}.mm-navbars_bottom.mm-navbars_has-tabs .mm-navbar_tabs,.mm-navbars_bottom.mm-navbars_has-tabs .mm-navbar_tabs~.mm-navbar{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)}.mm-searchfield{height:44px;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;height:var(--mm-navbar-size);padding:0;overflow:hidden}.mm-searchfield input{height:30.8px;line-height:30.8px}.mm-searchfield input,.mm-searchfield input:focus,.mm-searchfield input:hover{background:rgba(0,0,0,.05);color:rgba(0,0,0,.75)}.mm-searchfield input{display:block;width:100%;max-width:100%;height:calc(var(--mm-navbar-size) * .7);min-height:unset;max-height:unset;margin:0;padding:0 10px;-webkit-box-sizing:border-box;box-sizing:border-box;border:none!important;border-radius:4px;line-height:calc(var(--mm-navbar-size) * .7);-webkit-box-shadow:none!important;box-shadow:none!important;outline:0!important;font:inherit;font-size:inherit}.mm-searchfield input,.mm-searchfield input:focus,.mm-searchfield input:hover{background:var(--mm-color-background-highlight);color:var(--mm-color-text)}.mm-searchfield input::-ms-clear{display:none}.mm-searchfield__input{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-flex:1;-ms-flex:1;flex:1;-webkit-box-align:center;-ms-flex-align:center;align-items:center;position:relative;width:100%;max-width:100%;padding:0 10px;-webkit-box-sizing:border-box;box-sizing:border-box}.mm-panel__noresultsmsg{color:rgba(0,0,0,.3);padding:50px 0;color:var(--mm-color-text-dimmed);text-align:center;font-size:150%}.mm-searchfield__btn{position:absolute;right:0;top:0;bottom:0}.mm-panel_search{left:0!important;right:0!important;width:100%!important;border-left:none!important}.mm-searchfield__cancel{line-height:44px;display:block;padding-right:10px;margin-right:-100px;line-height:var(--mm-navbar-size);text-decoration:none;-webkit-transition:margin .4s ease;-o-transition:margin .4s ease;transition:margin .4s ease}.mm-searchfield__cancel-active{margin-right:0}.mm-listitem_nosubitems>.mm-listitem__btn{display:none}.mm-listitem_nosubitems>.mm-listitem__text{padding-right:10px}.mm-listitem_onlysubitems>.mm-listitem__text:not(.mm-listitem__btn){z-index:-1;pointer-events:none}.mm-sectionindexer{background:inherit;text-align:center;font-size:12px;-webkit-box-sizing:border-box;box-sizing:border-box;width:20px;position:absolute;top:0;bottom:0;right:-20px;z-index:5;-webkit-transition:right .4s ease;-o-transition:right .4s ease;transition:right .4s ease;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;-webkit-box-pack:space-evenly;-ms-flex-pack:space-evenly;justify-content:space-evenly}.mm-sectionindexer a{color:rgba(0,0,0,.3);color:var(--mm-color-text-dimmed);line-height:1;text-decoration:none;display:block}.mm-sectionindexer~.mm-panel{padding-right:0}.mm-sectionindexer_active{right:0}.mm-sectionindexer_active~.mm-panel{padding-right:20px}.mm-menu_selected-hover .mm-listitem__btn,.mm-menu_selected-hover .mm-listitem__text,.mm-menu_selected-parent .mm-listitem__btn,.mm-menu_selected-parent .mm-listitem__text{-webkit-transition:background-color .4s ease;-o-transition:background-color .4s ease;transition:background-color .4s ease}.mm-menu_selected-hover .mm-listview:hover>.mm-listitem_selected>.mm-listitem__text{background:0 0}.mm-menu_selected-hover .mm-listitem__btn:hover,.mm-menu_selected-hover .mm-listitem__text:hover{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)}.mm-menu_selected-parent .mm-panel_opened-parent .mm-listitem:not(.mm-listitem_selected-parent)>.mm-listitem__text{background:0 0}.mm-menu_selected-parent .mm-listitem_selected-parent>.mm-listitem__btn,.mm-menu_selected-parent .mm-listitem_selected-parent>.mm-listitem__text{background:rgba(255,255,255,.4);background:var(--mm-color-background-emphasis)}:root{--mm-sidebar-collapsed-size:50px;--mm-sidebar-expanded-size:440px}.mm-wrapper_sidebar-collapsed body,.mm-wrapper_sidebar-expanded body{position:relative}.mm-wrapper_sidebar-collapsed .mm-slideout,.mm-wrapper_sidebar-expanded .mm-slideout{-webkit-transition-property:width,-webkit-transform;transition-property:width,-webkit-transform;-o-transition-property:width,transform;transition-property:width,transform;transition-property:width,transform,-webkit-transform}.mm-wrapper_sidebar-collapsed .mm-page,.mm-wrapper_sidebar-expanded .mm-page{background:inherit;-webkit-box-sizing:border-box;box-sizing:border-box;min-height:100vh}.mm-wrapper_sidebar-collapsed .mm-menu_sidebar-collapsed,.mm-wrapper_sidebar-expanded .mm-menu_sidebar-expanded{display:-webkit-box!important;display:-ms-flexbox!important;display:flex!important;top:0!important;right:auto!important;bottom:0!important;left:0!important}.mm-wrapper_sidebar-collapsed .mm-slideout{width:calc(100% - 50px);-webkit-transform:translate3d(50px,0,0);transform:translate3d(50px,0,0);width:calc(100% - var(--mm-sidebar-collapsed-size));-webkit-transform:translate3d(var(--mm-sidebar-collapsed-size),0,0);transform:translate3d(var(--mm-sidebar-collapsed-size),0,0)}.mm-wrapper_sidebar-collapsed:not(.mm-wrapper_opening) .mm-menu_hidedivider .mm-divider,.mm-wrapper_sidebar-collapsed:not(.mm-wrapper_opening) .mm-menu_hidenavbar .mm-navbar{opacity:0}.mm-wrapper_sidebar-expanded .mm-menu_sidebar-expanded{width:440px;width:var(--mm-sidebar-expanded-size);min-width:0!important;max-width:100000px!important;border-right-width:1px;border-right-style:solid}.mm-wrapper_sidebar-expanded .mm-menu_sidebar-expanded.mm-menu_pageshadow:after{content:none;display:none}.mm-wrapper_sidebar-expanded.mm-wrapper_blocking,.mm-wrapper_sidebar-expanded.mm-wrapper_blocking body{overflow:visible}.mm-wrapper_sidebar-expanded .mm-wrapper__blocker{display:none!important}.mm-wrapper_sidebar-expanded:not(.mm-wrapper_sidebar-closed) .mm-menu_sidebar-expanded.mm-menu_opened~.mm-slideout{width:calc(100% - 440px);-webkit-transform:translate3d(440px,0,0);transform:translate3d(440px,0,0);width:calc(100% - var(--mm-sidebar-expanded-size));-webkit-transform:translate3d(var(--mm-sidebar-expanded-size),0,0);transform:translate3d(var(--mm-sidebar-expanded-size),0,0)}.mm-menu__blocker{background:rgba(3,2,1,0);display:block;position:absolute;top:0;right:0;bottom:0;left:0;z-index:3}.mm-menu_opened .mm-menu__blocker{display:none}[dir=rtl].mm-wrapper_sidebar-collapsed .mm-slideout{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}[dir=rtl].mm-wrapper_sidebar-expanded .mm-slideout{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}[dir=rtl].mm-wrapper_sidebar-expanded:not(.mm-wrapper_sidebar-closed) .mm-menu_sidebar-expanded.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}input.mm-toggle{margin-top:5px;background:rgba(0,0,0,.1);display:inline-block;min-width:58px;width:58px;height:34px;margin:0 10px;margin-top:calc((var(--mm-listitem-size) - 34px)/ 2);border:none!important;background:var(--mm-color-border);border-radius:34px;-webkit-appearance:none!important;-moz-appearance:none!important;appearance:none!important;cursor:pointer;-webkit-transition:background-color .2s ease;-o-transition:background-color .2s ease;transition:background-color .2s ease}input.mm-toggle:before{background:#f3f3f3}input.mm-toggle:before{content:'';display:block;width:32px;height:32px;margin:1px;border-radius:34px;background:var(--mm-color-background);-webkit-transition:-webkit-transform .2s ease;transition:-webkit-transform .2s ease;-o-transition:transform .2s ease;transition:transform .2s ease;transition:transform .2s ease,-webkit-transform .2s ease}input.mm-toggle:checked{background:#4bd963}input.mm-toggle:checked:before{-webkit-transform:translateX(24px);-ms-transform:translateX(24px);transform:translateX(24px)}input.mm-check{margin-top:2px;-webkit-appearance:none!important;-moz-appearance:none!important;appearance:none!important;border:none!important;background:0 0!important;cursor:pointer;display:inline-block;width:40px;height:40px;margin:0 10px;margin-top:calc((var(--mm-listitem-size) - 40px)/ 2)}input.mm-check:before{content:'';display:block;width:40%;height:20%;margin:25% 0 0 20%;border-left:3px solid;border-bottom:3px solid;border-color:var(--mm-color-text);opacity:.3;-webkit-transform:rotate(-45deg);-ms-transform:rotate(-45deg);transform:rotate(-45deg);-webkit-transition:opacity .2s ease;-o-transition:opacity .2s ease;transition:opacity .2s ease}input.mm-check:checked:before{opacity:1}[dir=rtl] input.mm-toggle:checked~label.mm-toggle:before{float:left}.mm-menu_border-none .mm-listitem:after{content:none}.mm-menu_border-full .mm-listitem:after{left:0!important}.mm-menu_fx-menu-slide{-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;-o-transition:transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease}.mm-wrapper_opened .mm-menu_fx-menu-slide{-webkit-transform:translate3d(-30%,0,0);transform:translate3d(-30%,0,0)}.mm-wrapper_opening .mm-menu_fx-menu-slide{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-wrapper_opened .mm-menu_fx-menu-slide.mm-menu_position-right{-webkit-transform:translate3d(30%,0,0);transform:translate3d(30%,0,0)}.mm-wrapper_opening .mm-menu_fx-menu-slide.mm-menu_position-right{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-menu_fx-panels-none .mm-panel,.mm-panel_fx-none{-webkit-transition-property:none;-o-transition-property:none;transition-property:none}.mm-menu_fx-panels-none .mm-panel.mm-panel_opened-parent,.mm-panel_fx-none.mm-panel_opened-parent{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-menu_fx-panels-slide-0 .mm-panel_opened-parent{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-menu_fx-panels-slide-100 .mm-panel_opened-parent{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.mm-menu_fullscreen{width:100%;min-width:140px;max-width:10000px}.mm-wrapper_opening .mm-menu_fullscreen~.mm-slideout{-webkit-transform:translate3d(100vw,0,0);transform:translate3d(100vw,0,0)}@media all and (max-width:140px){.mm-wrapper_opening .mm-menu_fullscreen~.mm-slideout{-webkit-transform:translate3d(140px,0,0);transform:translate3d(140px,0,0)}}@media all and (min-width:10000px){.mm-wrapper_opening .mm-menu_fullscreen~.mm-slideout{-webkit-transform:translate3d(10000px,0,0);transform:translate3d(10000px,0,0)}}.mm-wrapper_opening .mm-menu_fullscreen.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-100vw,0,0);transform:translate3d(-100vw,0,0)}@media all and (max-width:140px){.mm-wrapper_opening .mm-menu_fullscreen.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-140px,0,0);transform:translate3d(-140px,0,0)}}@media all and (min-width:10000px){.mm-wrapper_opening .mm-menu_fullscreen.mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-10000px,0,0);transform:translate3d(-10000px,0,0)}}.mm-menu_fullscreen.mm-menu_position-top{height:100vh;min-height:140px;max-height:10000px}.mm-menu_fullscreen.mm-menu_position-bottom{height:100vh;min-height:140px;max-height:10000px}.mm-menu_listview-justify .mm-panels>.mm-panel{display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column}.mm-menu_listview-justify .mm-panels>.mm-panel:after{content:none;display:none}.mm-menu_listview-justify .mm-panels>.mm-panel .mm-listview{-webkit-box-flex:1;-ms-flex-positive:1;flex-grow:1;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-orient:vertical;-webkit-box-direction:normal;-ms-flex-direction:column;flex-direction:column;height:100%;margin-top:0;margin-bottom:0}.mm-menu_listview-justify .mm-panels>.mm-panel .mm-listitem{-webkit-box-flex:1;-ms-flex:1 0 auto;flex:1 0 auto;min-height:50px}.mm-menu_listview-justify .mm-panels>.mm-panel .mm-listitem__text{-webkit-box-sizing:border-box;box-sizing:border-box;-webkit-box-flex:1;-ms-flex:1 0 auto;flex:1 0 auto;display:-webkit-box;display:-ms-flexbox;display:flex;-webkit-box-align:center;-ms-flex-align:center;align-items:center}.mm-listview_inset{list-style:inside disc;width:100%;padding:0 30px 15px 30px;margin:0}.mm-listview_inset .mm-listitem{padding:5px 0}.mm-menu_multiline .mm-listitem__text{-o-text-overflow:clip;text-overflow:clip;white-space:normal}[class*=mm-menu_pagedim].mm-menu_opened~.mm-wrapper__blocker{opacity:0}.mm-wrapper_opening [class*=mm-menu_pagedim].mm-menu_opened~.mm-wrapper__blocker{opacity:.3;-webkit-transition:opacity .4s ease .4s;-o-transition:opacity .4s ease .4s;transition:opacity .4s ease .4s}.mm-menu_opened.mm-menu_pagedim~.mm-wrapper__blocker{background:inherit}.mm-menu_opened.mm-menu_pagedim-black~.mm-wrapper__blocker{background:#000}.mm-menu_opened.mm-menu_pagedim-white~.mm-wrapper__blocker{background:#fff}.mm-menu_popup{-webkit-transition:opacity .4s ease;-o-transition:opacity .4s ease;transition:opacity .4s ease;opacity:0;-webkit-box-shadow:0 2px 10px rgba(0,0,0,.3);box-shadow:0 2px 10px rgba(0,0,0,.3);height:80%;min-height:140px;max-height:880px;top:50%;left:50%;bottom:auto;right:auto;z-index:2;-webkit-transform:translate3d(-50%,-50%,0);transform:translate3d(-50%,-50%,0)}.mm-menu_popup.mm-menu_opened~.mm-slideout{-webkit-transform:none!important;-ms-transform:none!important;transform:none!important;z-index:0}.mm-menu_popup.mm-menu_opened~.mm-wrapper__blocker{-webkit-transition-delay:0s!important;-o-transition-delay:0s!important;transition-delay:0s!important;z-index:1}.mm-wrapper_opening .mm-menu_popup{opacity:1}.mm-menu_position-right{left:auto;right:0}.mm-wrapper_opening .mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-80vw,0,0);transform:translate3d(-80vw,0,0)}@media all and (max-width:300px){.mm-wrapper_opening .mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-240px,0,0);transform:translate3d(-240px,0,0)}}@media all and (min-width:550px){.mm-wrapper_opening .mm-menu_position-right.mm-menu_opened~.mm-slideout{-webkit-transform:translate3d(-440px,0,0);transform:translate3d(-440px,0,0)}}.mm-menu_position-bottom,.mm-menu_position-front,.mm-menu_position-top{-webkit-transition:-webkit-transform .4s ease;transition:-webkit-transform .4s ease;-o-transition:transform .4s ease;transition:transform .4s ease;transition:transform .4s ease,-webkit-transform .4s ease}.mm-menu_position-bottom.mm-menu_opened,.mm-menu_position-front.mm-menu_opened,.mm-menu_position-top.mm-menu_opened{z-index:2}.mm-menu_position-bottom.mm-menu_opened~.mm-slideout,.mm-menu_position-front.mm-menu_opened~.mm-slideout,.mm-menu_position-top.mm-menu_opened~.mm-slideout{-webkit-transform:none!important;-ms-transform:none!important;transform:none!important;z-index:0}.mm-menu_position-bottom.mm-menu_opened~.mm-wrapper__blocker,.mm-menu_position-front.mm-menu_opened~.mm-wrapper__blocker,.mm-menu_position-top.mm-menu_opened~.mm-wrapper__blocker{z-index:1}.mm-menu_position-front{-webkit-transform:translate3d(-100%,0,0);transform:translate3d(-100%,0,0)}.mm-menu_position-front.mm-menu_position-right{-webkit-transform:translate3d(100%,0,0);transform:translate3d(100%,0,0)}.mm-menu_position-bottom,.mm-menu_position-top{width:100%;min-width:100%;max-width:100%}.mm-menu_position-top{-webkit-transform:translate3d(0,-100%,0);transform:translate3d(0,-100%,0)}.mm-menu_position-top{height:80vh;min-height:140px;max-height:880px}.mm-menu_position-bottom{-webkit-transform:translate3d(0,100%,0);transform:translate3d(0,100%,0);top:auto}.mm-menu_position-bottom{height:80vh;min-height:140px;max-height:880px}.mm-wrapper_opening .mm-menu_position-bottom,.mm-wrapper_opening .mm-menu_position-front,.mm-wrapper_opening .mm-menu_position-top{-webkit-transform:translate3d(0,0,0);transform:translate3d(0,0,0)}.mm-menu_shadow-page:after{-webkit-box-shadow:0 0 10px rgba(0,0,0,.3);box-shadow:0 0 10px rgba(0,0,0,.3);content:'';display:block;width:20px;height:120%;position:absolute;left:100%;top:-10%;z-index:100;-webkit-clip-path:polygon(-20px 0,0 0,0 100%,-20px 100%);clip-path:polygon(-20px 0,0 0,0 100%,-20px 100%);-webkit-box-shadow:var(--mm-shadow);box-shadow:var(--mm-shadow)}.mm-menu_shadow-page.mm-menu_position-right:after{left:auto;right:100%;-webkit-clip-path:polygon(20px 0,40px 0,40px 100%,20px 100%);clip-path:polygon(20px 0,40px 0,40px 100%,20px 100%)}.mm-menu_shadow-page.mm-menu_position-front:after{content:none;display:none}.mm-menu_shadow-menu{-webkit-box-shadow:0 0 10px rgba(0,0,0,.3);box-shadow:0 0 10px rgba(0,0,0,.3);-webkit-box-shadow:var(--mm-shadow);box-shadow:var(--mm-shadow)}.mm-menu_shadow-panels .mm-panels>.mm-panel{-webkit-box-shadow:0 0 10px rgba(0,0,0,.3);box-shadow:0 0 10px rgba(0,0,0,.3);-webkit-box-shadow:var(--mm-shadow);box-shadow:var(--mm-shadow)}.mm-menu_theme-white{--mm-color-border:rgba( 0,0,0, 0.1 );--mm-color-button:rgba( 0,0,0, 0.3 );--mm-color-text:rgba( 0,0,0, 0.7 );--mm-color-text-dimmed:rgba( 0,0,0, 0.3 );--mm-color-background:#fff;--mm-color-background-highlight:rgba( 0,0,0, 0.06 );--mm-color-background-emphasis:rgba( 0,0,0, 0.03 );--mm-shadow:0 0 10px rgba( 0,0,0, 0.2 )}.mm-menu_theme-dark{--mm-color-border:rgba( 0,0,0, 0.3 );--mm-color-button:rgba( 255,255,255, 0.4 );--mm-color-text:rgba( 255,255,255, 0.85 );--mm-color-text-dimmed:rgba( 255,255,255, 0.4 );--mm-color-background:#333;--mm-color-background-highlight:rgba( 255,255,255, 0.08 );--mm-color-background-emphasis:rgba( 0,0,0, 0.1 );--mm-shadow:0 0 20px rgba( 0,0,0, 0.5 )}.mm-menu_theme-black{--mm-color-border:rgba( 255,255,255, 0.25 );--mm-color-button:rgba( 255,255,255, 0.4 );--mm-color-text:rgba( 255,255,255, 0.75 );--mm-color-text-dimmed:rgba( 255,255,255, 0.4 );--mm-color-background:#000;--mm-color-background-highlight:rgba( 255,255,255, 0.2 );--mm-color-background-emphasis:rgba( 255,255,255, 0.15 );--mm-shadow:none}body.modal-open .mm-slideout{z-index:unset} \ No newline at end of file diff --git a/dist/mmenu.js b/dist/mmenu.js new file mode 100644 index 0000000..8520905 --- /dev/null +++ b/dist/mmenu.js @@ -0,0 +1,12 @@ +!function(e){var t={};function n(i){if(t[i])return t[i].exports;var s=t[i]={i:i,l:!1,exports:{}};return e[i].call(s.exports,s,s.exports,n),s.l=!0,s.exports}n.m=e,n.c=t,n.d=function(e,t,i){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:i})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var i=Object.create(null);if(n.r(i),Object.defineProperty(i,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var s in e)n.d(i,s,function(t){return e[t]}.bind(null,s));return i},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t);var i={hooks:{},extensions:[],wrappers:[],navbar:{add:!0,sticky:!0,title:"Menu",titleLink:"parent"},onClick:{close:null,preventDefault:null,setSelected:!0},slidingSubmenus:!0},s={classNames:{inset:"Inset",nolistview:"NoListview",nopanel:"NoPanel",panel:"Panel",selected:"Selected",vertical:"Vertical"},language:null,openingInterval:25,panelNodetype:["ul","ol","div"],transitionDuration:400};function a(e,t){for(var n in"object"!=o(e)&&(e={}),"object"!=o(t)&&(t={}),t)t.hasOwnProperty(n)&&(void 0===e[n]?e[n]=t[n]:"object"==o(e[n])&&a(e[n],t[n]));return e}function o(e){return{}.toString.call(e).match(/\s([a-zA-Z]+)/)[1].toLowerCase()}function r(e,t,n){if("function"==typeof t){var i=t.call(e);if(void 0!==i)return i}return null!==t&&"function"!=typeof t&&void 0!==t||void 0===n?t:n}function c(e,t,n){var i=!1,s=function(n){void 0!==n&&n.target!==e||(i||(e.removeEventListener("transitionend",s),e.removeEventListener("webkitTransitionEnd",s),t.call(e)),i=!0)};e.addEventListener("transitionend",s),e.addEventListener("webkitTransitionEnd",s),setTimeout(s,1.1*n)}function l(){return"mm-"+m++}var m=0;function d(e){return"mm-"==e.slice(0,3)?e.slice(3):e}var p={};function u(e,t){void 0===p[t]&&(p[t]={}),a(p[t],e)}var f={Menu:"منو"},h={Menu:"Menü"},v={Menu:"Меню"};function b(e){var t=e.split("."),n=document.createElement(t.shift());return t.forEach((function(e){n.classList.add(e)})),n}function g(e,t){return Array.prototype.slice.call(e.querySelectorAll(t))}function _(e,t){var n=Array.prototype.slice.call(e.children);return t?n.filter((function(e){return e.matches(t)})):n}function y(e,t){for(var n=[],i=e.parentElement;i;)n.push(i),i=i.parentElement;return t?n.filter((function(e){return e.matches(t)})):n}function w(e){return e.filter((function(e){return!e.matches(".mm-hidden")}))}function L(e){var t=[];return w(e).forEach((function(e){t.push.apply(t,_(e,"a.mm-listitem__text"))})),t.filter((function(e){return!e.matches(".mm-btn_next")}))}function E(e,t,n){e.matches("."+t)&&(e.classList.remove(t),e.classList.add(n))}var x={};function P(e,t,n){"number"==typeof e&&(e="(min-width: "+e+"px)"),x[e]=x[e]||[],x[e].push({yes:t,no:n})}function k(e,t){for(var n=t.matches?"yes":"no",i=0;i-1&&t.append(n)})),this.node.menu.append(t),this.node.pnls=t,this.node.menu.classList.add("mm-menu"),this.trigger("initMenu:after")},e.prototype._initPanels=function(){var e=this;this.trigger("initPanels:before"),this.clck.push((function(t,n){if(n.inMenu){var i=t.getAttribute("href");if(i&&i.length>1&&"#"==i.slice(0,1))try{var s=g(e.node.menu,i)[0];if(s&&s.matches(".mm-panel"))return t.parentElement.matches(".mm-listitem_vertical")?e.togglePanel(s):e.openPanel(s),!0}catch(e){}}})),_(this.node.pnls).forEach((function(t){e.initPanel(t)})),this.trigger("initPanels:after")},e.prototype.initPanel=function(e){var t=this,n=this.conf.panelNodetype.join(", ");if(e.matches(n)&&(e.matches(".mm-panel")||(e=this._initPanel(e)),e)){var i=[];i.push.apply(i,_(e,"."+this.conf.classNames.panel)),_(e,".mm-listview").forEach((function(e){_(e,".mm-listitem").forEach((function(e){i.push.apply(i,_(e,n))}))})),i.forEach((function(e){t.initPanel(e)}))}},e.prototype._initPanel=function(e){var t=this;if(this.trigger("initPanel:before",[e]),E(e,this.conf.classNames.panel,"mm-panel"),E(e,this.conf.classNames.nopanel,"mm-nopanel"),E(e,this.conf.classNames.inset,"mm-listview_inset"),e.matches(".mm-listview_inset")&&e.classList.add("mm-nopanel"),e.matches(".mm-nopanel"))return null;var n=e.id||l(),i=e.matches("."+this.conf.classNames.vertical)||!this.opts.slidingSubmenus;if(e.classList.remove(this.conf.classNames.vertical),e.matches("ul, ol")){e.removeAttribute("id");var s=b("div");e.before(s),s.append(e),e=s}e.id=n,e.classList.add("mm-panel"),e.classList.add("mm-hidden");var a=[e.parentElement].filter((function(e){return e.matches("li")}))[0];if(i?a&&a.classList.add("mm-listitem_vertical"):this.node.pnls.append(e),a&&(a.mmChild=e,e.mmParent=a,a&&a.matches(".mm-listitem")&&!_(a,".mm-btn").length)){var o=_(a,".mm-listitem__text")[0];if(o){var r=b("a.mm-btn.mm-btn_next.mm-listitem__btn");r.setAttribute("href","#"+e.id),o.matches("span")?(r.classList.add("mm-listitem__text"),r.innerHTML=o.innerHTML,a.insertBefore(r,o.nextElementSibling),o.remove()):a.insertBefore(r,_(a,".mm-panel")[0])}}return this._initNavbar(e),_(e,"ul, ol").forEach((function(e){t.initListview(e)})),this.trigger("initPanel:after",[e]),e},e.prototype._initNavbar=function(e){if(this.trigger("initNavbar:before",[e]),!_(e,".mm-navbar").length){var t=null,n=null;if(e.getAttribute("data-mm-parent")?n=g(this.node.pnls,e.getAttribute("data-mm-parent"))[0]:(t=e.mmParent)&&(n=t.closest(".mm-panel")),!t||!t.matches(".mm-listitem_vertical")){var i=b("div.mm-navbar");if(this.opts.navbar.add?this.opts.navbar.sticky&&i.classList.add("mm-navbar_sticky"):i.classList.add("mm-hidden"),n){var s=b("a.mm-btn.mm-btn_prev.mm-navbar__btn");s.setAttribute("href","#"+n.id),i.append(s)}var a=null;t?a=_(t,".mm-listitem__text")[0]:n&&(a=g(n,'a[href="#'+e.id+'"]')[0]);var o=b("a.mm-navbar__title"),r=b("span");switch(o.append(r),r.innerHTML=e.getAttribute("data-mm-title")||(a?a.textContent:"")||this.i18n(this.opts.navbar.title)||this.i18n("Menu"),this.opts.navbar.titleLink){case"anchor":a&&o.setAttribute("href",a.getAttribute("href"));break;case"parent":n&&o.setAttribute("href","#"+n.id)}i.append(o),e.prepend(i),this.trigger("initNavbar:after",[e])}}},e.prototype.initListview=function(e){var t=this;this.trigger("initListview:before",[e]),E(e,this.conf.classNames.nolistview,"mm-nolistview"),e.matches(".mm-nolistview")||(e.classList.add("mm-listview"),_(e).forEach((function(e){e.classList.add("mm-listitem"),E(e,t.conf.classNames.selected,"mm-listitem_selected"),_(e,"a, span").forEach((function(e){e.matches(".mm-btn")||e.classList.add("mm-listitem__text")}))}))),this.trigger("initListview:after",[e])},e.prototype._initOpened=function(){this.trigger("initOpened:before");var e=this.node.pnls.querySelectorAll(".mm-listitem_selected"),t=null;e.forEach((function(e){t=e,e.classList.remove("mm-listitem_selected")})),t&&t.classList.add("mm-listitem_selected");var n=t?t.closest(".mm-panel"):_(this.node.pnls,".mm-panel")[0];this.openPanel(n,!1),this.trigger("initOpened:after")},e.prototype._initAnchors=function(){var e=this;this.trigger("initAnchors:before"),document.addEventListener("click",(function(t){var n=t.target.closest("a[href]");if(n){for(var i={inMenu:n.closest(".mm-menu")===e.node.menu,inListview:n.matches(".mm-listitem > a"),toExternal:n.matches('[rel="external"]')||n.matches('[target="_blank"]')},s={close:null,setSelected:null,preventDefault:"#"==n.getAttribute("href").slice(0,1)},c=0;c1){var i=b("div");n[0].before(i),n.forEach((function(e){i.append(e)})),n=[i]}e=n[0]}e.classList.add("mm-page"),e.classList.add("mm-slideout"),e.id=e.id||l(),S.node.page=e,this.trigger("setPage:after",[e])};var H=function(){var e=this;N(document.body,"keydown.tabguard"),C(document.body,"keydown.tabguard",(function(t){9==t.keyCode&&e.node.wrpr.matches(".mm-wrapper_opened")&&t.preventDefault()}))},j=function(){var e=this;this.trigger("initBlocker:before");var t=this.opts.offCanvas,n=this.conf.offCanvas;if(t.blockUI){if(!S.node.blck){var i=b("div.mm-wrapper__blocker.mm-slideout");i.innerHTML="",document.querySelector(n.menu.insertSelector).append(i),S.node.blck=i}var s=function(t){t.preventDefault(),t.stopPropagation(),e.node.wrpr.matches(".mm-wrapper_modal")||e.close()};S.node.blck.addEventListener("mousedown",s),S.node.blck.addEventListener("touchstart",s),S.node.blck.addEventListener("touchmove",s),this.trigger("initBlocker:after")}},D={aria:!0,text:!0};var O={text:{closeMenu:"Close menu",closeSubmenu:"Close submenu",openSubmenu:"Open submenu",toggleSubmenu:"Toggle submenu"}},I={"Close menu":"بستن منو","Close submenu":"بستن زیرمنو","Open submenu":"بازکردن زیرمنو","Toggle submenu":"سوییچ زیرمنو"},q={"Close menu":"Menü schließen","Close submenu":"Untermenü schließen","Open submenu":"Untermenü öffnen","Toggle submenu":"Untermenü wechseln"},B={"Close menu":"Закрыть меню","Close submenu":"Закрыть подменю","Open submenu":"Открыть подменю","Toggle submenu":"Переключить подменю"};u({"Close menu":"Menu sluiten","Close submenu":"Submenu sluiten","Open submenu":"Submenu openen","Toggle submenu":"Submenu wisselen"},"nl"),u(I,"fa"),u(q,"de"),u(B,"ru"),S.options.screenReader=D,S.configs.screenReader=O;var z;z=function(e,t,n){e[t]=n,n?e.setAttribute(t,n.toString()):e.removeAttribute(t)},S.sr_aria=function(e,t,n){z(e,"aria-"+t,n)},S.sr_role=function(e,t){z(e,"role",t)},S.sr_text=function(e){return''+e+""};var R={fix:!0};var U="ontouchstart"in window||!!navigator.msMaxTouchPoints||!1;S.options.scrollBugFix=R;var W={height:"default"};S.options.autoHeight=W;var Y={close:!1,open:!1};S.options.backButton=Y;var F={add:!1,visible:{min:1,max:3}};S.options.columns=F;var X={add:!1,addTo:"panels",count:!1};S.options.counters=X,S.configs.classNames.counters={counter:"Counter"};var V={add:!1,addTo:"panels"};S.options.dividers=V,S.configs.classNames.divider="Divider";var Z={open:!1,node:null};var G="ontouchstart"in window||!!navigator.msMaxTouchPoints||!1,K={top:0,right:0,bottom:0,left:0},Q={start:15,swipe:15},J={x:["Right","Left"],y:["Down","Up"]},$=0,ee=1,te=2,ne=function(e,t){return"string"==typeof e&&"%"==e.slice(-1)&&(e=t*((e=parseInt(e.slice(0,-1),10))/100)),e},ie=function(){function e(e,t,n){this.surface=e,this.area=a(t,K),this.treshold=a(n,Q),this.surface.mmHasDragEvents||(this.surface.addEventListener(G?"touchstart":"mousedown",this.start.bind(this)),this.surface.addEventListener(G?"touchend":"mouseup",this.stop.bind(this)),this.surface.addEventListener(G?"touchleave":"mouseleave",this.stop.bind(this)),this.surface.addEventListener(G?"touchmove":"mousemove",this.move.bind(this))),this.surface.mmHasDragEvents=!0}return e.prototype.start=function(e){this.currentPosition={x:e.touches?e.touches[0].pageX:e.pageX||0,y:e.touches?e.touches[0].pageY:e.pageY||0};var t=this.surface.clientWidth,n=this.surface.clientHeight,i=ne(this.area.top,n);if(!("number"==typeof i&&this.currentPosition.ys))){var a=ne(this.area.bottom,n);if(!("number"==typeof a&&(a=n-a,this.currentPosition.y>a))){var o=ne(this.area.left,t);"number"==typeof o&&this.currentPosition.xthis.treshold.swipe){var i=this._swipeDirection();n.direction=i,this._dispatchEvents("swipe*",n)}}this.state=$},e.prototype.move=function(e){switch(this.state){case ee:case te:var t={x:e.changedTouches?e.touches[0].pageX:e.pageX||0,y:e.changedTouches?e.touches[0].pageY:e.pageY||0};this.movement={x:t.x-this.currentPosition.x,y:t.y-this.currentPosition.y},this.distance={x:t.x-this.startPosition.x,y:t.y-this.startPosition.y},this.currentPosition={x:t.x,y:t.y},this.axis=Math.abs(this.distance.x)>Math.abs(this.distance.y)?"x":"y";var n=this._dragDirection(),i=this._eventDetail(n);this.state==ee&&Math.abs(this.distance[this.axis])>this.treshold.start&&(this._dispatchEvents("drag*Start",i),this.state=te),this.state==te&&this._dispatchEvents("drag*Move",i)}},e.prototype._eventDetail=function(e){var t=this.distance.x,n=this.distance.y;return"x"==this.axis&&(t-=t>0?this.treshold.start:0-this.treshold.start),"y"==this.axis&&(n-=n>0?this.treshold.start:0-this.treshold.start),{axis:this.axis,direction:e,movementX:this.movement.x,movementY:this.movement.y,distanceX:t,distanceY:n}},e.prototype._dispatchEvents=function(e,t){var n=new CustomEvent(e.replace("*",""),{detail:t});this.surface.dispatchEvent(n);var i=new CustomEvent(e.replace("*",this.axis.toUpperCase()),{detail:t});this.surface.dispatchEvent(i);var s=new CustomEvent(e.replace("*",t.direction),{detail:t});this.surface.dispatchEvent(s)},e.prototype._dragDirection=function(){return J[this.axis][this.distance[this.axis]>0?0:1]},e.prototype._swipeDirection=function(){return J[this.axis][this.movement[this.axis]>0?0:1]},e}(),se=null,ae=null,oe=0,re=function(e){var t=this,n={},i=!1,s=function(){var e=Object.keys(t.opts.extensions);e.length?(P(e.join(", "),(function(){}),(function(){n=ce(n,[],t.node.menu)})),e.forEach((function(e){P(e,(function(){n=ce(n,t.opts.extensions[e],t.node.menu)}),(function(){}))}))):n=ce(n,[],t.node.menu)};ae&&(N(ae,"dragStart"),N(ae,"dragMove"),N(ae,"dragEnd")),se=new ie(ae=e),s(),s=function(){},ae&&(C(ae,"dragStart",(function(e){e.detail.direction==n.direction&&(i=!0,t.node.wrpr.classList.add("mm-wrapper_dragging"),t._openSetup(),t.trigger("open:start"),oe=t.node.menu["x"==n.axis?"clientWidth":"clientHeight"])})),C(ae,"dragMove",(function(e){if(e.detail.axis==n.axis&&i){var t=e.detail["distance"+n.axis.toUpperCase()];switch(n.position){case"right":case"bottom":t=Math.min(Math.max(t,-oe),0);break;default:t=Math.max(Math.min(t,oe),0)}if("front"==n.zposition)switch(n.position){case"right":case"bottom":t+=oe;break;default:t-=oe}n.slideOutNodes.forEach((function(e){e.style.transform="translate"+n.axis.toUpperCase()+"("+t+"px)"}))}})),C(ae,"dragEnd",(function(e){if(e.detail.axis==n.axis&&i){i=!1,t.node.wrpr.classList.remove("mm-wrapper_dragging"),n.slideOutNodes.forEach((function(e){e.style.transform=""}));var s=Math.abs(e.detail["distance"+n.axis.toUpperCase()])>=.75*oe;if(!s){var a=e.detail["movement"+n.axis.toUpperCase()];switch(n.position){case"right":case"bottom":s=a<=0;break;default:s=a>=0}}s?t._openStart():t.close()}})))},ce=function(e,t,n){switch(e.position="left",e.zposition="back",["right","top","bottom"].forEach((function(n){t.indexOf("position-"+n)>-1&&(e.position=n)})),["front","top","bottom"].forEach((function(n){t.indexOf("position-"+n)>-1&&(e.zposition="front")})),se.area={top:"bottom"==e.position?"75%":0,right:"left"==e.position?"75%":0,bottom:"top"==e.position?"75%":0,left:"right"==e.position?"75%":0},e.position){case"top":case"bottom":e.axis="y";break;default:e.axis="x"}switch(e.position){case"top":e.direction="Down";break;case"right":e.direction="Left";break;case"bottom":e.direction="Up";break;default:e.direction="Right"}switch(e.zposition){case"front":e.slideOutNodes=[n];break;default:e.slideOutNodes=g(document.body,".mm-slideout")}return e};S.options.drag=Z;var le={drop:!1,fitViewport:!0,event:"click",position:{},tip:!0};var me={offset:{button:{x:-5,y:5},viewport:{x:20,y:20}},height:{max:880},width:{max:440}};S.options.dropdown=le,S.configs.dropdown=me;var de={insertMethod:"append",insertSelector:"body"};S.configs.fixedElements=de,S.configs.classNames.fixedElements={fixed:"Fixed"};var pe={use:!1,top:[],bottom:[],position:"left",type:"default"};S.options.iconbar=pe;var ue={add:!1,blockPanel:!0,hideDivider:!1,hideNavbar:!0,visible:3};S.options.iconPanels=ue;var fe={enable:!1,enhance:!1};S.options.keyboardNavigation=fe;var he=function(e){var t=this;N(document.body,"keydown.tabguard"),N(document.body,"focusin.tabguard"),C(document.body,"focusin.tabguard",(function(e){if(t.node.wrpr.matches(".mm-wrapper_opened")){var n=e.target;if(n.matches(".mm-tabend")){var i=void 0;n.parentElement.matches(".mm-menu")&&S.node.blck&&(i=S.node.blck),n.parentElement.matches(".mm-wrapper__blocker")&&(i=g(document.body,".mm-menu_offcanvas.mm-menu_opened")[0]),i||(i=n.parentElement),i&&_(i,".mm-tabstart")[0].focus()}}})),N(document.body,"keydown.navigate"),C(document.body,"keydown.navigate",(function(t){var n=t.target,i=n.closest(".mm-menu");if(i){i.mmApi;if(!n.matches("input, textarea"))switch(t.keyCode){case 13:(n.matches(".mm-toggle")||n.matches(".mm-check"))&&n.dispatchEvent(new Event("click"));break;case 32:case 37:case 38:case 39:case 40:t.preventDefault()}if(e)if(n.matches("input"))switch(t.keyCode){case 27:n.value=""}else{var s=i.mmApi;switch(t.keyCode){case 8:var a=g(i,".mm-panel_opened")[0].mmParent;a&&s.openPanel(a.closest(".mm-panel"));break;case 27:i.matches(".mm-menu_offcanvas")&&s.close()}}}}))},ve={load:!1};S.options.lazySubmenus=ve;var be=[];var ge={breadcrumbs:{separator:"/",removeFirst:!1}};function _e(){var e=this,t=this.opts.navbars;if(void 0!==t){t instanceof Array||(t=[t]);var n={};t.length&&(t.forEach((function(t){if(!(t=function(e){return"boolean"==typeof e&&e&&(e={}),"object"!=typeof e&&(e={}),void 0===e.content&&(e.content=["prev","title"]),e.content instanceof Array||(e.content=[e.content]),void 0===e.use&&(e.use=!0),"boolean"==typeof e.use&&e.use&&(e.use=!0),e}(t)).use)return!1;var i=b("div.mm-navbar"),s=t.position;"bottom"!==s&&(s="top"),n[s]||(n[s]=b("div.mm-navbars_"+s)),n[s].append(i);for(var a=0,o=t.content.length;a"+r+"":''+r+"")}a=!1}s=s.mmParent}t.conf.navbars.breadcrumbs.removeFirst&&n.shift(),i.innerHTML=n.join(''+t.conf.navbars.breadcrumbs.separator+""),_(e,".mm-navbar")[0].append(i)}})),this.bind("openPanel:start",(function(e){var t=e.querySelector(".mm-navbar__breadcrumbs");n.innerHTML=t?t.innerHTML:""})),this.bind("initNavbar:after:sr-aria",(function(e){g(e,".mm-breadcrumbs a").forEach((function(e){S.sr_aria(e,"owns",e.getAttribute("href").slice(1))}))}))},close:function(e){var t=this,n=b("a.mm-btn.mm-btn_close.mm-navbar__btn");e.append(n),this.bind("setPage:after",(function(e){n.setAttribute("href","#"+e.id)})),this.bind("setPage:after:sr-text",(function(){n.innerHTML=S.sr_text(t.i18n(t.conf.screenReader.text.closeMenu)),S.sr_aria(n,"owns",n.getAttribute("href").slice(1))}))},prev:function(e){var t,n,i,s=this,a=b("a.mm-btn.mm-btn_prev.mm-navbar__btn");e.append(a),this.bind("initNavbar:after",(function(e){_(e,".mm-navbar")[0].classList.add("mm-hidden")})),this.bind("openPanel:start",(function(e){e.parentElement.matches(".mm-listitem_vertical")||((t=e.querySelector("."+s.conf.classNames.navbars.panelPrev))||(t=e.querySelector(".mm-navbar__btn.mm-btn_prev")),n=t?t.getAttribute("href"):"",i=t?t.innerHTML:"",n?a.setAttribute("href",n):a.removeAttribute("href"),a.classList[n||i?"remove":"add"]("mm-hidden"),a.innerHTML=i)})),this.bind("initNavbar:after:sr-aria",(function(e){S.sr_aria(e.querySelector(".mm-navbar"),"hidden",!0)})),this.bind("openPanel:start:sr-aria",(function(e){S.sr_aria(a,"hidden",a.matches(".mm-hidden")),S.sr_aria(a,"owns",(a.getAttribute("href")||"").slice(1))}))},searchfield:function(e){"object"!=o(this.opts.searchfield)&&(this.opts.searchfield={});var t=b("div.mm-navbar__searchfield");e.append(t),this.opts.searchfield.add=!0,this.opts.searchfield.addTo=[t]},title:function(e){var t,n,i,s,a=this,o=b("a.mm-navbar__title"),r=b("span");o.append(r),e.append(o),this.bind("openPanel:start",(function(e){e.parentElement.matches(".mm-listitem_vertical")||((i=e.querySelector("."+a.conf.classNames.navbars.panelTitle))||(i=e.querySelector(".mm-navbar__title span")),(t=i&&i.closest("a")?i.closest("a").getAttribute("href"):"")?o.setAttribute("href",t):o.removeAttribute("href"),n=i?i.innerHTML:"",r.innerHTML=n)})),this.bind("openPanel:start:sr-aria",(function(e){if(a.opts.screenReader.text){if(!s)_(a.node.menu,".mm-navbars_top, .mm-navbars_bottom").forEach((function(e){var t=e.querySelector(".mm-btn_prev");t&&(s=t)}));if(s){var t=!0;"parent"==a.opts.navbar.titleLink&&(t=!s.matches(".mm-hidden")),S.sr_aria(o,"hidden",t)}}}))}},_e.navbarTypes={tabs:function(e){var t=this;e.classList.add("mm-navbar_tabs"),e.parentElement.classList.add("mm-navbars_has-tabs");var n=_(e,"a");e.addEventListener("click",(function(e){var n=e.target;if(n.matches("a"))if(n.matches(".mm-navbar__tab_selected"))e.stopImmediatePropagation();else try{t.openPanel(t.node.menu.querySelector(n.getAttribute("href")),!1),e.stopImmediatePropagation()}catch(e){}})),this.bind("openPanel:start",(function e(t){n.forEach((function(e){e.classList.remove("mm-navbar__tab_selected")}));var i=n.filter((function(e){return e.matches('[href="#'+t.id+'"]')}))[0];if(i)i.classList.add("mm-navbar__tab_selected");else{var s=t.mmParent;s&&e.call(this,s.closest(".mm-panel"))}}))}};var ye={scroll:!1,update:!1};var we={scrollOffset:0,updateOffset:50};S.options.pageScroll=ye,S.configs.pageScroll=we;var Le={add:!1,addTo:"panels",cancel:!1,noResults:"No results found.",placeholder:"Search",panel:{add:!1,dividers:!0,fx:"none",id:null,splash:null,title:"Search"},search:!0,showTextItems:!1,showSubPanels:!0};var Ee={clear:!1,form:!1,input:!1,submit:!1},xe={Search:"جستجو","No results found.":"نتیجه‌ای یافت نشد.",cancel:"انصراف"},Pe={Search:"Suche","No results found.":"Keine Ergebnisse gefunden.",cancel:"beenden"},ke={Search:"Найти","No results found.":"Ничего не найдено.",cancel:"отменить"};u({Search:"Zoeken","No results found.":"Geen resultaten gevonden.",cancel:"annuleren"},"nl"),u(xe,"fa"),u(Pe,"de"),u(ke,"ru"),S.options.searchfield=Le,S.configs.searchfield=Ee;var Se=function(){var e=this.opts.searchfield,t=(this.conf.searchfield,_(this.node.pnls,".mm-panel_search")[0]);if(t)return t;t=b("div.mm-panel.mm-panel_search.mm-hidden"),e.panel.id&&(t.id=e.panel.id),e.panel.title&&t.setAttribute("data-mm-title",e.panel.title);var n=b("ul");switch(t.append(n),this.node.pnls.append(t),this.initListview(n),this._initNavbar(t),e.panel.fx){case!1:break;case"none":t.classList.add("mm-panel_noanimation");break;default:t.classList.add("mm-panel_fx-"+e.panel.fx)}if(e.panel.splash){var i=b("div.mm-panel__content");i.innerHTML=e.panel.splash,t.append(i)}return t.classList.add("mm-panel"),t.classList.add("mm-hidden"),this.node.pnls.append(t),t},Me=function(e){var t=this.opts.searchfield,n=this.conf.searchfield;if(e.parentElement.matches(".mm-listitem_vertical"))return null;if(a=g(e,".mm-searchfield")[0])return a;function i(e,t){if(t)for(var n in t)e.setAttribute(n,t[n])}var s,a=b((n.form?"form":"div")+".mm-searchfield"),o=b("div.mm-searchfield__input"),r=b("input");(r.type="text",r.autocomplete="off",r.placeholder=this.i18n(t.placeholder),o.append(r),a.append(o),e.prepend(a),i(r,n.input),n.clear)&&((s=b("a.mm-btn.mm-btn_close.mm-searchfield__btn")).setAttribute("href","#"),o.append(s));(i(a,n.form),n.form&&n.submit&&!n.clear)&&((s=b("a.mm-btn.mm-btn_next.mm-searchfield__btn")).setAttribute("href","#"),o.append(s));t.cancel&&((s=b("a.mm-searchfield__cancel")).setAttribute("href","#"),s.textContent=this.i18n("cancel"),a.append(s));return a},Ae=function(e){var t=this,n=this.opts.searchfield,i=(this.conf.searchfield,{});e.closest(".mm-panel_search")?(i.panels=g(this.node.pnls,".mm-panel"),i.noresults=[e.closest(".mm-panel")]):e.closest(".mm-panel")?(i.panels=[e.closest(".mm-panel")],i.noresults=i.panels):(i.panels=g(this.node.pnls,".mm-panel"),i.noresults=[this.node.menu]),i.panels=i.panels.filter((function(e){return!e.matches(".mm-panel_search")})),i.panels=i.panels.filter((function(e){return!e.parentElement.matches(".mm-listitem_vertical")})),i.listitems=[],i.dividers=[],i.panels.forEach((function(e){var t,n;(t=i.listitems).push.apply(t,g(e,".mm-listitem")),(n=i.dividers).push.apply(n,g(e,".mm-divider"))}));var s=_(this.node.pnls,".mm-panel_search")[0],a=g(e,"input")[0],o=g(e,".mm-searchfield__cancel")[0];a.mmSearchfield=i,n.panel.add&&n.panel.splash&&(N(a,"focus.splash"),C(a,"focus.splash",(function(e){t.openPanel(s)}))),n.cancel&&(N(a,"focus.cancel"),C(a,"focus.cancel",(function(e){o.classList.add("mm-searchfield__cancel-active")})),N(o,"click.splash"),C(o,"click.splash",(function(e){if(e.preventDefault(),o.classList.remove("mm-searchfield__cancel-active"),s.matches(".mm-panel_opened")){var n=_(t.node.pnls,".mm-panel_opened-parent");n.length&&t.openPanel(n[n.length-1])}}))),n.panel.add&&"panel"==n.addTo&&this.bind("openPanel:finish",(function(e){e===s&&a.focus()})),N(a,"input.search"),C(a,"input.search",(function(e){switch(e.keyCode){case 9:case 16:case 17:case 18:case 37:case 38:case 39:case 40:break;default:t.search(a)}})),this.search(a)},Te=function(e){if(e){var t=this.opts.searchfield;this.conf.searchfield;if(e.closest(".mm-panel")||(e=_(this.node.pnls,".mm-panel")[0]),!_(e,".mm-panel__noresultsmsg").length){var n=b("div.mm-panel__noresultsmsg.mm-hidden");n.innerHTML=this.i18n(t.noResults),e.append(n)}}};S.prototype.search=function(e,t){var n,i=this,s=this.opts.searchfield;this.conf.searchfield;t=(t=t||""+e.value).toLowerCase().trim();var a=e.mmSearchfield,o=g(e.closest(".mm-searchfield"),".mm-btn"),r=_(this.node.pnls,".mm-panel_search")[0],c=a.panels,l=a.noresults,m=a.listitems,d=a.dividers;if(m.forEach((function(e){e.classList.remove("mm-listitem_nosubitems"),e.classList.remove("mm-listitem_onlysubitems"),e.classList.remove("mm-hidden")})),r&&(_(r,".mm-listview")[0].innerHTML=""),c.forEach((function(e){e.scrollTop=0})),t.length){d.forEach((function(e){e.classList.add("mm-hidden")})),m.forEach((function(e){var n,i=_(e,".mm-listitem__text")[0],a=!1;i&&(n=i,Array.prototype.slice.call(n.childNodes).filter((function(e){return 3==e.nodeType})).map((function(e){return e.textContent})).join(" ")).toLowerCase().indexOf(t)>-1&&(i.matches(".mm-listitem__btn")?s.showSubPanels&&(a=!0):i.matches("a")?a=!0:s.showTextItems&&(a=!0)),a||e.classList.add("mm-hidden")}));var p=m.filter((function(e){return!e.matches(".mm-hidden")})).length;if(s.panel.add){var u=[];c.forEach((function(e){var t=w(g(e,".mm-listitem"));if((t=t.filter((function(e){return!e.matches(".mm-hidden")}))).length){if(s.panel.dividers){var n=b("li.mm-divider"),i=g(e,".mm-navbar__title")[0];i&&(n.innerHTML=i.innerHTML,u.push(n))}t.forEach((function(e){u.push(e.cloneNode(!0))}))}})),u.forEach((function(e){e.querySelectorAll(".mm-toggle, .mm-check").forEach((function(e){e.remove()}))})),(n=_(r,".mm-listview")[0]).append.apply(n,u),this.openPanel(r)}else s.showSubPanels&&c.forEach((function(e){w(g(e,".mm-listitem")).forEach((function(e){var t=e.mmChild;t&&g(t,".mm-listitem").forEach((function(e){e.classList.remove("mm-hidden")}))}))})),c.slice().reverse().forEach((function(t,n){var s=t.mmParent;s&&(w(g(t,".mm-listitem")).length?(s.matches(".mm-hidden")&&s.classList.remove("mm-hidden"),s.classList.add("mm-listitem_onlysubitems")):e.closest(".mm-panel")||((t.matches(".mm-panel_opened")||t.matches(".mm-panel_opened-parent"))&&setTimeout((function(){i.openPanel(s.closest(".mm-panel"))}),(n+1)*(1.5*i.conf.openingInterval)),s.classList.add("mm-listitem_nosubitems")))})),c.forEach((function(e){w(g(e,".mm-listitem")).forEach((function(e){y(e,".mm-listitem_vertical").forEach((function(e){e.matches(".mm-hidden")&&(e.classList.remove("mm-hidden"),e.classList.add("mm-listitem_onlysubitems"))}))}))})),c.forEach((function(e){w(g(e,".mm-listitem")).forEach((function(e){var t=function(e,t){for(var n=[],i=e.previousElementSibling;i;)t&&!i.matches(t)||n.push(i),i=i.previousElementSibling;return n}(e,".mm-divider")[0];t&&t.classList.remove("mm-hidden")}))}));o.forEach((function(e){return e.classList.remove("mm-hidden")})),l.forEach((function(e){g(e,".mm-panel__noresultsmsg").forEach((function(e){return e.classList[p?"add":"remove"]("mm-hidden")}))})),s.panel.add&&(s.panel.splash&&g(r,".mm-panel__content").forEach((function(e){return e.classList.add("mm-hidden")})),m.forEach((function(e){return e.classList.remove("mm-hidden")})),d.forEach((function(e){return e.classList.remove("mm-hidden")})))}else if(m.forEach((function(e){return e.classList.remove("mm-hidden")})),d.forEach((function(e){return e.classList.remove("mm-hidden")})),o.forEach((function(e){return e.classList.add("mm-hidden")})),l.forEach((function(e){g(e,".mm-panel__noresultsmsg").forEach((function(e){return e.classList.add("mm-hidden")}))})),s.panel.add)if(s.panel.splash)g(r,".mm-panel__content").forEach((function(e){return e.classList.remove("mm-hidden")}));else if(!e.closest(".mm-panel_search")){var f=_(this.node.pnls,".mm-panel_opened-parent");this.openPanel(f.slice(-1)[0])}this.trigger("updateListview")};var Ce={add:!1,addTo:"panels"};S.options.sectionIndexer=Ce;var Ne={current:!0,hover:!1,parent:!1};S.options.setSelected=Ne;var He={collapsed:{use:!1,blockMenu:!0,hideDivider:!1,hideNavbar:!0},expanded:{use:!1,initial:"open"}};S.options.sidebar=He;S.configs.classNames.toggles={toggle:"Toggle",check:"Check"}; +/*! + * mmenu.js + * mmenujs.com + * + * Copyright (c) Fred Heusschen + * frebsite.nl + * + * License: CC-BY-NC-4.0 + * http://creativecommons.org/licenses/by-nc/4.0/ + */ +S.addons={offcanvas:function(){var e=this;if(this.opts.offCanvas){var t=function(e){return"object"!=typeof e&&(e={}),e}(this.opts.offCanvas);this.opts.offCanvas=a(t,S.options.offCanvas);var n=this.conf.offCanvas;this._api.push("open","close","setPage"),this.vars.opened=!1,this.bind("initMenu:before",(function(){n.clone&&(e.node.menu=e.node.menu.cloneNode(!0),e.node.menu.id&&(e.node.menu.id="mm-"+e.node.menu.id),g(e.node.menu,"[id]").forEach((function(e){e.id="mm-"+e.id}))),e.node.wrpr=document.body,document.querySelector(n.menu.insertSelector)[n.menu.insertMethod](e.node.menu)})),this.bind("initMenu:after",(function(){j.call(e),e.setPage(S.node.page),H.call(e),e.node.menu.classList.add("mm-menu_offcanvas");var t=window.location.hash;if(t){var n=d(e.node.menu.id);n&&n==t.slice(1)&&setTimeout((function(){e.open()}),1e3)}})),this.bind("setPage:after",(function(e){S.node.blck&&_(S.node.blck,"a").forEach((function(t){t.setAttribute("href","#"+e.id)}))})),this.bind("open:start:sr-aria",(function(){S.sr_aria(e.node.menu,"hidden",!1)})),this.bind("close:finish:sr-aria",(function(){S.sr_aria(e.node.menu,"hidden",!0)})),this.bind("initMenu:after:sr-aria",(function(){S.sr_aria(e.node.menu,"hidden",!0)})),this.bind("initBlocker:after:sr-text",(function(){_(S.node.blck,"a").forEach((function(t){t.innerHTML=S.sr_text(e.i18n(e.conf.screenReader.text.closeMenu))}))})),this.clck.push((function(t,n){var i=d(e.node.menu.id);if(i&&t.matches('[href="#'+i+'"]')){if(n.inMenu)return e.open(),!0;var s=t.closest(".mm-menu");if(s){var a=s.mmApi;if(a&&a.close)return a.close(),c(s,(function(){e.open()}),e.conf.transitionDuration),!0}return e.open(),!0}if((i=S.node.page.id)&&t.matches('[href="#'+i+'"]'))return e.close(),!0}))}},screenReader:function(){var e=this,t=function(e){return"boolean"==typeof e&&(e={aria:e,text:e}),"object"!=typeof e&&(e={}),e}(this.opts.screenReader);this.opts.screenReader=a(t,S.options.screenReader);var n=this.conf.screenReader;t.aria&&(this.bind("initAddons:after",(function(){e.bind("initMenu:after",(function(){this.trigger("initMenu:after:sr-aria",[].slice.call(arguments))})),e.bind("initNavbar:after",(function(){this.trigger("initNavbar:after:sr-aria",[].slice.call(arguments))})),e.bind("openPanel:start",(function(){this.trigger("openPanel:start:sr-aria",[].slice.call(arguments))})),e.bind("close:start",(function(){this.trigger("close:start:sr-aria",[].slice.call(arguments))})),e.bind("close:finish",(function(){this.trigger("close:finish:sr-aria",[].slice.call(arguments))})),e.bind("open:start",(function(){this.trigger("open:start:sr-aria",[].slice.call(arguments))})),e.bind("initOpened:after",(function(){this.trigger("initOpened:after:sr-aria",[].slice.call(arguments))}))})),this.bind("updateListview",(function(){e.node.pnls.querySelectorAll(".mm-listitem").forEach((function(e){S.sr_aria(e,"hidden",e.matches(".mm-hidden"))}))})),this.bind("openPanel:start",(function(t){var n=g(e.node.pnls,".mm-panel").filter((function(e){return e!==t})).filter((function(e){return!e.parentElement.matches(".mm-panel")})),i=[t];g(t,".mm-listitem_vertical .mm-listitem_opened").forEach((function(e){i.push.apply(i,_(e,".mm-panel"))})),n.forEach((function(e){S.sr_aria(e,"hidden",!0)})),i.forEach((function(e){S.sr_aria(e,"hidden",!1)}))})),this.bind("closePanel",(function(e){S.sr_aria(e,"hidden",!0)})),this.bind("initPanel:after",(function(e){g(e,".mm-btn").forEach((function(e){S.sr_aria(e,"haspopup",!0);var t=e.getAttribute("href");t&&S.sr_aria(e,"owns",t.replace("#",""))}))})),this.bind("initNavbar:after",(function(e){var t=_(e,".mm-navbar")[0],n=t.matches(".mm-hidden");S.sr_aria(t,"hidden",n)})),t.text&&"parent"==this.opts.navbar.titleLink&&this.bind("initNavbar:after",(function(e){var t=_(e,".mm-navbar")[0],n=!!t.querySelector(".mm-btn_prev");S.sr_aria(g(t,".mm-navbar__title")[0],"hidden",n)}))),t.text&&(this.bind("initAddons:after",(function(){e.bind("setPage:after",(function(){this.trigger("setPage:after:sr-text",[].slice.call(arguments))})),e.bind("initBlocker:after",(function(){this.trigger("initBlocker:after:sr-text",[].slice.call(arguments))}))})),this.bind("initNavbar:after",(function(t){var i=_(t,".mm-navbar")[0];if(i){var s=_(i,".mm-btn_prev")[0];s&&(s.innerHTML=S.sr_text(e.i18n(n.text.closeSubmenu)))}})),this.bind("initListview:after",(function(t){var i=t.closest(".mm-panel").mmParent;if(i){var s=_(i,".mm-btn_next")[0];if(s){var a=e.i18n(n.text[s.parentElement.matches(".mm-listitem_vertical")?"toggleSubmenu":"openSubmenu"]);s.innerHTML+=S.sr_text(a)}}})))},scrollBugFix:function(){var e=this;if(U&&this.opts.offCanvas&&this.opts.offCanvas.blockUI){var t=function(e){return"boolean"==typeof e&&(e={fix:e}),"object"!=typeof e&&(e={}),e}(this.opts.scrollBugFix);if(this.opts.scrollBugFix=a(t,S.options.scrollBugFix),t.fix){var n,i,s=(n=this.node.menu,i="",n.addEventListener("touchmove",(function(e){i="",e.movementY>0?i="down":e.movementY<0&&(i="up")})),{get:function(){return i}});this.node.menu.addEventListener("scroll",o,{passive:!1}),this.node.menu.addEventListener("touchmove",(function(e){var t=e.target.closest(".mm-panel");t?t.scrollHeight===t.offsetHeight?o(e):(0==t.scrollTop&&"down"==s.get()||t.scrollHeight==t.scrollTop+t.offsetHeight&&"up"==s.get())&&o(e):o(e)}),{passive:!1}),this.bind("open:start",(function(){var t=_(e.node.pnls,".mm-panel_opened")[0];t&&(t.scrollTop=0)})),window.addEventListener("orientationchange",(function(t){var n=_(e.node.pnls,".mm-panel_opened")[0];n&&(n.scrollTop=0,n.style["-webkit-overflow-scrolling"]="auto",n.style["-webkit-overflow-scrolling"]="touch")}))}}function o(e){e.preventDefault(),e.stopPropagation()}},autoHeight:function(){var e=this,t=function(e){return"boolean"==typeof e&&e&&(e={height:"auto"}),"string"==typeof e&&(e={height:e}),"object"!=typeof e&&(e={}),e}(this.opts.autoHeight);if(this.opts.autoHeight=a(t,S.options.autoHeight),"auto"==t.height||"highest"==t.height){var n,i=(n=function(e){return e.parentElement.matches(".mm-listitem_vertical")&&(e=y(e,".mm-panel").filter((function(e){return!e.parentElement.matches(".mm-listitem_vertical")}))[0]),e},function(){if(!e.opts.offCanvas||e.vars.opened){var i,s,a=0,o=e.node.menu.offsetHeight-e.node.pnls.offsetHeight;e.node.menu.classList.add("mm-menu_autoheight-measuring"),"auto"==t.height?((s=_(e.node.pnls,".mm-panel_opened")[0])&&(s=n(s)),s||(s=_(e.node.pnls,".mm-panel")[0]),a=s.scrollHeight):"highest"==t.height&&(i=0,_(e.node.pnls,".mm-panel").forEach((function(e){e=n(e),i=Math.max(i,e.scrollHeight)})),a=i),e.node.menu.style.height=a+o+"px",e.node.menu.classList.remove("mm-menu_autoheight-measuring")}});this.bind("initMenu:after",(function(){e.node.menu.classList.add("mm-menu_autoheight")})),this.opts.offCanvas&&this.bind("open:start",i),"highest"==t.height&&this.bind("initPanels:after",i),"auto"==t.height&&(this.bind("updateListview",i),this.bind("openPanel:start",i))}},backButton:function(){var e=this;if(this.opts.offCanvas){var t=function(e){return"boolean"==typeof e&&(e={close:e}),"object"!=typeof e&&(e={}),e}(this.opts.backButton);this.opts.backButton=a(t,S.options.backButton);var n="#"+this.node.menu.id;if(t.close){var i=[],s=function(){i=[n],_(e.node.pnls,".mm-panel_opened, .mm-panel_opened-parent").forEach((function(e){i.push("#"+e.id)}))};this.bind("open:finish",(function(){history.pushState(null,document.title,n)})),this.bind("open:finish",s),this.bind("openPanel:finish",s),this.bind("close:finish",(function(){i=[],history.back(),history.pushState(null,document.title,location.pathname+location.search)})),window.addEventListener("popstate",(function(t){if(e.vars.opened&&i.length){var s=(i=i.slice(0,-1))[i.length-1];s==n?e.close():(e.openPanel(e.node.menu.querySelector(s)),history.pushState(null,document.title,n))}}))}t.open&&window.addEventListener("popstate",(function(t){e.vars.opened||location.hash!=n||e.open()}))}},columns:function(){var e=this,t=function(e){return"boolean"==typeof e&&(e={add:e}),"number"==typeof e&&(e={add:!0,visible:e}),"object"!=typeof e&&(e={}),"number"==typeof e.visible&&(e.visible={min:e.visible,max:e.visible}),e}(this.opts.columns);if(this.opts.columns=a(t,S.options.columns),t.add){t.visible.min=Math.max(1,Math.min(6,t.visible.min)),t.visible.max=Math.max(t.visible.min,Math.min(6,t.visible.max));for(var n=[],i=[],s=["mm-panel_opened","mm-panel_opened-parent","mm-panel_highest"],o=0;o<=t.visible.max;o++)n.push("mm-menu_columns-"+o),i.push("mm-panel_columns-"+o);s.push.apply(s,i),this.bind("openPanel:before",(function(t){var n;if(t&&(n=t.mmParent),n&&(n=n.closest(".mm-panel"))){var i=n.className;if(i.length&&(i=i.split("mm-panel_columns-")[1]))for(var a=parseInt(i.split(" ")[0],10)+1;a>0;){if(!(t=_(e.node.pnls,".mm-panel_columns-"+a)[0])){a=-1;break}a++,t.classList.add("mm-hidden"),s.forEach((function(e){t.classList.remove(e)}))}}})),this.bind("openPanel:start",(function(s){var a=_(e.node.pnls,".mm-panel_opened-parent").length;s.matches(".mm-panel_opened-parent")||a++,a=Math.min(t.visible.max,Math.max(t.visible.min,a)),n.forEach((function(t){e.node.menu.classList.remove(t)})),e.node.menu.classList.add("mm-menu_columns-"+a);var o=[];_(e.node.pnls,".mm-panel").forEach((function(e){i.forEach((function(t){e.classList.remove(t)})),e.matches(".mm-panel_opened-parent")&&o.push(e)})),o.push(s),o.slice(-t.visible.max).forEach((function(e,t){e.classList.add("mm-panel_columns-"+t)}))}))}},counters:function(){var e=this,t=function(e){return"boolean"==typeof e&&(e={add:e,addTo:"panels",count:e}),"object"!=typeof e&&(e={}),"panels"==e.addTo&&(e.addTo=".mm-listview"),e}(this.opts.counters);if(this.opts.counters=a(t,S.options.counters),this.bind("initListview:after",(function(t){var n=e.conf.classNames.counters.counter;g(t,"."+n).forEach((function(e){E(e,n,"mm-counter")}))})),t.add&&this.bind("initListview:after",(function(e){if(e.matches(t.addTo)){var n=e.closest(".mm-panel").mmParent;if(n&&!g(n,".mm-counter").length){var i=_(n,".mm-btn")[0];i&&i.prepend(b("span.mm-counter"))}}})),t.count){var n=function(t){(t?[t.closest(".mm-panel")]:_(e.node.pnls,".mm-panel")).forEach((function(e){var t=e.mmParent;if(t){var n=g(t,".mm-counter")[0];if(n){var i=[];_(e,".mm-listview").forEach((function(e){i.push.apply(i,_(e))})),n.innerHTML=w(i).length.toString()}}}))};this.bind("initListview:after",n),this.bind("updateListview",n)}},dividers:function(){var e=this,t=function(e){return"boolean"==typeof e&&(e={add:e}),"object"!=typeof e&&(e={}),"panels"==e.addTo&&(e.addTo=".mm-listview"),e}(this.opts.dividers);this.opts.dividers=a(t,S.options.dividers),this.bind("initListview:after",(function(t){_(t).forEach((function(t){E(t,e.conf.classNames.divider,"mm-divider"),t.matches(".mm-divider")&&t.classList.remove("mm-listitem")}))})),t.add&&this.bind("initListview:after",(function(e){if(e.matches(t.addTo)){g(e,".mm-divider").forEach((function(e){e.remove()}));var n="";w(_(e)).forEach((function(t){var i=_(t,".mm-listitem__text")[0].textContent.trim().toLowerCase()[0];if(i.length&&i!=n){n=i;var s=b("li.mm-divider");s.textContent=i,e.insertBefore(s,t)}}))}}))},drag:function(){var e=this;if(this.opts.offCanvas){var t=function(e){return"boolean"==typeof e&&(e={open:e}),"object"!=typeof e&&(e={}),e}(this.opts.drag);this.opts.drag=a(t,S.options.drag),t.open&&this.bind("setPage:after",(function(n){re.call(e,t.node||n)}))}},dropdown:function(){var e=this;if(this.opts.offCanvas){var t=function(e){return"boolean"==typeof e&&e&&(e={drop:e}),"object"!=typeof e&&(e={}),"string"==typeof e.position&&(e.position={of:e.position}),e}(this.opts.dropdown);this.opts.dropdown=a(t,S.options.dropdown);var n=this.conf.dropdown;if(t.drop){var i;this.bind("initMenu:after",(function(){if(e.node.menu.classList.add("mm-menu_dropdown"),"string"!=typeof t.position.of){var n=d(e.node.menu.id);n&&(t.position.of='[href="#'+n+'"]')}if("string"==typeof t.position.of){i=g(document.body,t.position.of)[0];var s=t.event.split(" ");1==s.length&&(s[1]=s[0]),"hover"==s[0]&&i.addEventListener("mouseenter",(function(){e.open()}),{passive:!0}),"hover"==s[1]&&e.node.menu.addEventListener("mouseleave",(function(){e.close()}),{passive:!0})}})),this.bind("open:start",(function(){e.node.menu.mmStyle=e.node.menu.getAttribute("style"),e.node.wrpr.classList.add("mm-wrapper_dropdown")})),this.bind("close:finish",(function(){e.node.menu.setAttribute("style",e.node.menu.mmStyle),e.node.wrpr.classList.remove("mm-wrapper_dropdown")}));var s=function(e,s){var a,o,r,c=s[0],l=s[1],m="x"==e?"offsetWidth":"offsetHeight",d="x"==e?"left":"top",p="x"==e?"right":"bottom",u="x"==e?"width":"height",f="x"==e?"innerWidth":"innerHeight",h="x"==e?"maxWidth":"maxHeight",v=null,b=(a=d,i.getBoundingClientRect()[a]+document.body["left"===a?"scrollLeft":"scrollTop"]),g=b+i[m],_=window[f],y=n.offset.button[e]+n.offset.viewport[e];if(t.position[e])switch(t.position[e]){case"left":case"bottom":v="after";break;case"right":case"top":v="before"}return null===v&&(v=b+(g-b)/2<_/2?"after":"before"),"after"==v?(r=_-((o="x"==e?b:g)+y),c[d]=o+n.offset.button[e]+"px",c[p]="auto",t.tip&&l.push("mm-menu_tip-"+("x"==e?"left":"top"))):(r=(o="x"==e?g:b)-y,c[p]="calc( 100% - "+(o-n.offset.button[e])+"px )",c[d]="auto",t.tip&&l.push("mm-menu_tip-"+("x"==e?"right":"bottom"))),t.fitViewport&&(c[h]=Math.min(n[u].max,r)+"px"),[c,l]};this.bind("open:start",o),window.addEventListener("resize",(function(t){o.call(e)}),{passive:!0}),this.opts.offCanvas.blockUI||window.addEventListener("scroll",(function(t){o.call(e)}),{passive:!0})}}function o(){var e=this;if(this.vars.opened){this.node.menu.setAttribute("style",this.node.menu.mmStyle);var n=[{},[]];for(var i in n=s.call(this,"y",n),(n=s.call(this,"x",n))[0])this.node.menu.style[i]=n[0][i];if(t.tip){["mm-menu_tip-left","mm-menu_tip-right","mm-menu_tip-top","mm-menu_tip-bottom"].forEach((function(t){e.node.menu.classList.remove(t)})),n[1].forEach((function(t){e.node.menu.classList.add(t)}))}}}},fixedElements:function(){var e=this;if(this.opts.offCanvas){var t,n,i=this.conf.fixedElements;this.bind("setPage:after",(function(s){t=e.conf.classNames.fixedElements.fixed,n=g(document,i.insertSelector)[0],g(s,"."+t).forEach((function(e){E(e,t,"mm-slideout"),n[i.insertMethod](e)}))}))}},iconbar:function(){var e,t=this,n=function(e){return"array"==o(e)&&(e={use:!0,top:e}),"object"!=o(e)&&(e={}),void 0===e.use&&(e.use=!0),"boolean"==typeof e.use&&e.use&&(e.use=!0),e}(this.opts.iconbar);if((this.opts.iconbar=a(n,S.options.iconbar),n.use)&&(["top","bottom"].forEach((function(t,i){var s=n[t];"array"!=o(s)&&(s=[s]);for(var a=b("div.mm-iconbar__"+t),r=0,c=s.length;r"}));var n=b("div.mm-sectionindexer");n.innerHTML=t,e.node.pnls.prepend(n),e.node.indx=n,e.node.indx.addEventListener("click",(function(e){e.target.matches("a")&&e.preventDefault()}));var i=function(t){if(t.target.matches("a")){var n=t.target.textContent,i=_(e.node.pnls,".mm-panel_opened")[0],s=-1,a=i.scrollTop;i.scrollTop=0,g(i,".mm-divider").filter((function(e){return!e.matches(".mm-hidden")})).forEach((function(e){s<0&&n==e.textContent.trim().slice(0,1).toLowerCase()&&(s=e.offsetTop)})),i.scrollTop=s>-1?s:a}};U?(e.node.indx.addEventListener("touchstart",i),e.node.indx.addEventListener("touchmove",i)):e.node.indx.addEventListener("mouseover",i)}e.bind("openPanel:start",(function(t){var n=g(t,".mm-divider").filter((function(e){return!e.matches(".mm-hidden")})).length;e.node.indx.classList[n?"add":"remove"]("mm-sectionindexer_active")}))}))},setSelected:function(){var e=this,t=function(e){return"boolean"==typeof e&&(e={hover:e,parent:e}),"object"!=typeof e&&(e={}),e}(this.opts.setSelected);if(this.opts.setSelected=a(t,S.options.setSelected),"detect"==t.current){var n=function(t){t=t.split("?")[0].split("#")[0];var i=e.node.menu.querySelector('a[href="'+t+'"], a[href="'+t+'/"]');if(i)e.setSelected(i.parentElement);else{var s=t.split("/").slice(0,-1);s.length&&n(s.join("/"))}};this.bind("initMenu:after",(function(){n.call(e,window.location.href)}))}else t.current||this.bind("initListview:after",(function(e){_(e,".mm-listitem_selected").forEach((function(e){e.classList.remove("mm-listitem_selected")}))}));t.hover&&this.bind("initMenu:after",(function(){e.node.menu.classList.add("mm-menu_selected-hover")})),t.parent&&(this.bind("openPanel:finish",(function(t){g(e.node.pnls,".mm-listitem_selected-parent").forEach((function(e){e.classList.remove("mm-listitem_selected-parent")}));for(var n=t.mmParent;n;)n.matches(".mm-listitem_vertical")||n.classList.add("mm-listitem_selected-parent"),n=(n=n.closest(".mm-panel")).mmParent})),this.bind("initMenu:after",(function(){e.node.menu.classList.add("mm-menu_selected-parent")})))},sidebar:function(){var e=this;if(this.opts.offCanvas){var t=function(e){return("string"==typeof e||"boolean"==typeof e&&e||"number"==typeof e)&&(e={expanded:e}),"object"!=typeof e&&(e={}),"boolean"==typeof e.collapsed&&e.collapsed&&(e.collapsed={use:!0}),"string"!=typeof e.collapsed&&"number"!=typeof e.collapsed||(e.collapsed={use:e.collapsed}),"object"!=typeof e.collapsed&&(e.collapsed={}),"boolean"==typeof e.expanded&&e.expanded&&(e.expanded={use:!0}),"string"!=typeof e.expanded&&"number"!=typeof e.expanded||(e.expanded={use:e.expanded}),"object"!=typeof e.expanded&&(e.expanded={}),e}(this.opts.sidebar);if(this.opts.sidebar=a(t,S.options.sidebar),t.collapsed.use){this.bind("initMenu:after",(function(){if(e.node.menu.classList.add("mm-menu_sidebar-collapsed"),t.collapsed.blockMenu&&e.opts.offCanvas&&!_(e.node.menu,".mm-menu__blocker")[0]){var n=b("a.mm-menu__blocker");n.setAttribute("href","#"+e.node.menu.id),e.node.menu.prepend(n)}t.collapsed.hideNavbar&&e.node.menu.classList.add("mm-menu_hidenavbar"),t.collapsed.hideDivider&&e.node.menu.classList.add("mm-menu_hidedivider")}));var n=function(){e.node.wrpr.classList.add("mm-wrapper_sidebar-collapsed")},i=function(){e.node.wrpr.classList.remove("mm-wrapper_sidebar-collapsed")};"boolean"==typeof t.collapsed.use?this.bind("initMenu:after",n):P(t.collapsed.use,n,i)}if(t.expanded.use){this.bind("initMenu:after",(function(){e.node.menu.classList.add("mm-menu_sidebar-expanded")}));n=function(){e.node.wrpr.classList.add("mm-wrapper_sidebar-expanded"),e.node.wrpr.matches(".mm-wrapper_sidebar-closed")||e.open()},i=function(){e.node.wrpr.classList.remove("mm-wrapper_sidebar-expanded"),e.close()};"boolean"==typeof t.expanded.use?this.bind("initMenu:after",n):P(t.expanded.use,n,i),this.bind("close:start",(function(){e.node.wrpr.matches(".mm-wrapper_sidebar-expanded")&&(e.node.wrpr.classList.add("mm-wrapper_sidebar-closed"),"remember"==t.expanded.initial&&window.localStorage.setItem("mmenuExpandedState","closed"))})),this.bind("open:start",(function(){e.node.wrpr.matches(".mm-wrapper_sidebar-expanded")&&(e.node.wrpr.classList.remove("mm-wrapper_sidebar-closed"),"remember"==t.expanded.initial&&window.localStorage.setItem("mmenuExpandedState","open"))}));var s=t.expanded.initial;if("remember"==t.expanded.initial){var o=window.localStorage.getItem("mmenuExpandedState");switch(o){case"open":case"closed":s=o}}"closed"==s&&this.bind("initMenu:after",(function(){e.node.wrpr.classList.add("mm-wrapper_sidebar-closed")})),this.clck.push((function(n,i){if(i.inMenu&&i.inListview&&e.node.wrpr.matches(".mm-wrapper_sidebar-expanded"))return{close:"closed"==t.expanded.initial}}))}}},toggles:function(){var e=this;this.bind("initPanel:after",(function(t){g(t,"input").forEach((function(t){E(t,e.conf.classNames.toggles.toggle,"mm-toggle"),E(t,e.conf.classNames.toggles.check,"mm-check")}))}))}},S.wrappers={angular:function(){this.opts.onClick={close:!0,preventDefault:!1,setSelected:!0}},bootstrap:function(){var e=this;if(this.node.menu.matches(".navbar-collapse")){this.conf.offCanvas&&(this.conf.offCanvas.clone=!1);var t=b("nav"),n=b("div");t.append(n),_(this.node.menu).forEach((function(t){switch(!0){case t.matches(".navbar-nav"):n.append(function(e){var t=b("ul");return g(e,".nav-item").forEach((function(e){var n=b("li");if(e.matches(".active")&&n.classList.add("Selected"),!e.matches(".nav-link")){var i=_(e,".dropdown-menu")[0];i&&n.append(o(i)),e=_(e,".nav-link")[0]}n.prepend(a(e)),t.append(n)})),t}(t));break;case t.matches(".dropdown-menu"):n.append(o(t));break;case t.matches(".form-inline"):e.conf.searchfield.form={action:t.getAttribute("action")||null,method:t.getAttribute("method")||null},e.conf.searchfield.input={name:t.querySelector("input").getAttribute("name")||null},e.conf.searchfield.clear=!1,e.conf.searchfield.submit=!0;break;default:n.append(t.cloneNode(!0))}})),this.bind("initMenu:before",(function(){document.body.prepend(t),e.node.menu=t}));var i=this.node.menu.parentElement;if(i){var s=i.querySelector(".navbar-toggler");s&&(s.removeAttribute("data-target"),s.removeAttribute("aria-controls"),s.outerHTML=s.outerHTML,(s=i.querySelector(".navbar-toggler")).addEventListener("click",(function(t){t.preventDefault(),t.stopImmediatePropagation(),e[e.vars.opened?"close":"open"]()})))}}function a(e){for(var t=b(e.matches("a")?"a":"span"),n=["href","title","target"],i=0;i= 0 && matches.item(i) !== this) {} + return i > -1; + }; +} + +// Source: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest +if (!Element.prototype.matches) { + Element.prototype.matches = + Element.prototype.msMatchesSelector || + Element.prototype.webkitMatchesSelector; +} + +if (!Element.prototype.closest) { + Element.prototype.closest = function(s) { + var el = this; + + do { + if (el.matches(s)) return el; + el = el.parentElement || el.parentNode; + } while (el !== null && el.nodeType === 1); + return null; + }; +} + +// Source: https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/prepend()/prepend().md +(function(arr) { + arr.forEach(function(item) { + if (item.hasOwnProperty('prepend')) { + return; + } + Object.defineProperty(item, 'prepend', { + configurable: true, + enumerable: true, + writable: true, + value: function prepend() { + var argArr = Array.prototype.slice.call(arguments), + docFrag = document.createDocumentFragment(); + + argArr.forEach(function(argItem) { + var isNode = argItem instanceof Node; + docFrag.appendChild( + isNode + ? argItem + : document.createTextNode(String(argItem)) + ); + }); + + this.insertBefore(docFrag, this.firstChild); + } + }); + }); +})([Element.prototype, Document.prototype, DocumentFragment.prototype]); + +// Source: https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/append()/append().md +(function(arr) { + arr.forEach(function(item) { + if (item.hasOwnProperty('append')) { + return; + } + Object.defineProperty(item, 'append', { + configurable: true, + enumerable: true, + writable: true, + value: function append() { + var argArr = Array.prototype.slice.call(arguments), + docFrag = document.createDocumentFragment(); + + argArr.forEach(function(argItem) { + var isNode = argItem instanceof Node; + docFrag.appendChild( + isNode + ? argItem + : document.createTextNode(String(argItem)) + ); + }); + + this.appendChild(docFrag); + } + }); + }); +})([Element.prototype, Document.prototype, DocumentFragment.prototype]); + +// Source: https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/before()/before().md +(function(arr) { + arr.forEach(function(item) { + if (item.hasOwnProperty('before')) { + return; + } + Object.defineProperty(item, 'before', { + configurable: true, + enumerable: true, + writable: true, + value: function before() { + var argArr = Array.prototype.slice.call(arguments), + docFrag = document.createDocumentFragment(); + + argArr.forEach(function(argItem) { + var isNode = argItem instanceof Node; + docFrag.appendChild( + isNode + ? argItem + : document.createTextNode(String(argItem)) + ); + }); + + this.parentNode.insertBefore(docFrag, this); + } + }); + }); +})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); + +// Source: https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/remove()/remove().md +(function(arr) { + arr.forEach(function(item) { + if (item.hasOwnProperty('remove')) { + return; + } + Object.defineProperty(item, 'remove', { + configurable: true, + enumerable: true, + writable: true, + value: function remove() { + if (this.parentNode !== null) this.parentNode.removeChild(this); + } + }); + }); +})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); diff --git a/dist/wrappers/angular/mmenu.angular.js b/dist/wrappers/angular/mmenu.angular.js new file mode 100644 index 0000000..6748455 --- /dev/null +++ b/dist/wrappers/angular/mmenu.angular.js @@ -0,0 +1,8 @@ +export default function () { + this.opts.onClick = { + close: true, + preventDefault: false, + setSelected: true + }; +} +; diff --git a/dist/wrappers/bootstrap/mmenu.bootstrap.css b/dist/wrappers/bootstrap/mmenu.bootstrap.css new file mode 100644 index 0000000..5560420 --- /dev/null +++ b/dist/wrappers/bootstrap/mmenu.bootstrap.css @@ -0,0 +1 @@ +body.modal-open .mm-slideout{z-index:unset} \ No newline at end of file diff --git a/dist/wrappers/bootstrap/mmenu.bootstrap.js b/dist/wrappers/bootstrap/mmenu.bootstrap.js new file mode 100644 index 0000000..44f2768 --- /dev/null +++ b/dist/wrappers/bootstrap/mmenu.bootstrap.js @@ -0,0 +1,113 @@ +import * as DOM from '../../_modules/dom'; +export default function () { + var _this = this; + // Create the menu + if (this.node.menu.matches('.navbar-collapse')) { + // No need for cloning the menu... + if (this.conf.offCanvas) { + this.conf.offCanvas.clone = false; + } + // ... We'll create a new menu + var nav = DOM.create('nav'), panel = DOM.create('div'); + nav.append(panel); + DOM.children(this.node.menu).forEach(function (child) { + switch (true) { + case child.matches('.navbar-nav'): + panel.append(cloneNav(child)); + break; + case child.matches('.dropdown-menu'): + panel.append(cloneDropdown(child)); + break; + case child.matches('.form-inline'): + _this.conf.searchfield.form = { + action: child.getAttribute('action') || null, + method: child.getAttribute('method') || null + }; + _this.conf.searchfield.input = { + name: child.querySelector('input').getAttribute('name') || + null + }; + _this.conf.searchfield.clear = false; + _this.conf.searchfield.submit = true; + break; + default: + panel.append(child.cloneNode(true)); + break; + } + }); + // Set the menu + this.bind('initMenu:before', function () { + document.body.prepend(nav); + _this.node.menu = nav; + }); + // Hijack the toggler. + var parent_1 = this.node.menu.parentElement; + if (parent_1) { + var toggler = parent_1.querySelector('.navbar-toggler'); + if (toggler) { + toggler.removeAttribute('data-target'); + // delete toggler.dataset.target; // IE10 has no dataset :( + toggler.removeAttribute('aria-controls'); + // Remove all bound events. + toggler.outerHTML = toggler.outerHTML; + toggler = parent_1.querySelector('.navbar-toggler'); + // Open the menu on-click. + toggler.addEventListener('click', function (evnt) { + evnt.preventDefault(); + evnt.stopImmediatePropagation(); + _this[_this.vars.opened ? 'close' : 'open'](); + }); + } + } + } + function cloneLink(anchor) { + var link = DOM.create(anchor.matches('a') ? 'a' : 'span'); + // Copy attributes + var attr = ['href', 'title', 'target']; + for (var a = 0; a < attr.length; a++) { + if (typeof anchor.getAttribute(attr[a]) != 'undefined') { + link.setAttribute(attr[a], anchor.getAttribute(attr[a])); + } + } + // Copy contents + link.innerHTML = anchor.innerHTML; + // Remove Screen reader text. + DOM.find(link, '.sr-only').forEach(function (sro) { + sro.remove(); + }); + return link; + } + function cloneDropdown(dropdown) { + var list = DOM.create('ul'); + DOM.children(dropdown).forEach(function (anchor) { + var item = DOM.create('li'); + if (anchor.matches('.dropdown-divider')) { + item.classList.add('Divider'); + } + else if (anchor.matches('.dropdown-item')) { + item.append(cloneLink(anchor)); + } + list.append(item); + }); + return list; + } + function cloneNav(nav) { + var list = DOM.create('ul'); + DOM.find(nav, '.nav-item').forEach(function (anchor) { + var item = DOM.create('li'); + if (anchor.matches('.active')) { + item.classList.add('Selected'); + } + if (!anchor.matches('.nav-link')) { + var dropdown = DOM.children(anchor, '.dropdown-menu')[0]; + if (dropdown) { + item.append(cloneDropdown(dropdown)); + } + anchor = DOM.children(anchor, '.nav-link')[0]; + } + item.prepend(cloneLink(anchor)); + list.append(item); + }); + return list; + } +} diff --git a/dist/wrappers/magento/mmenu.magento.js b/dist/wrappers/magento/mmenu.magento.js new file mode 100644 index 0000000..f44f8de --- /dev/null +++ b/dist/wrappers/magento/mmenu.magento.js @@ -0,0 +1,4 @@ +export default function () { + this.conf.classNames.selected = 'active'; +} +; diff --git a/dist/wrappers/olark/mmenu.olark.js b/dist/wrappers/olark/mmenu.olark.js new file mode 100644 index 0000000..0b1dd54 --- /dev/null +++ b/dist/wrappers/olark/mmenu.olark.js @@ -0,0 +1,4 @@ +export default function () { + this.conf.offCanvas.page.noSelector.push('#olark'); +} +; diff --git a/dist/wrappers/turbolinks/mmenu.turbolinks.js b/dist/wrappers/turbolinks/mmenu.turbolinks.js new file mode 100644 index 0000000..aab8eaa --- /dev/null +++ b/dist/wrappers/turbolinks/mmenu.turbolinks.js @@ -0,0 +1,15 @@ +export default function () { + var classnames; + document.addEventListener('turbolinks:before-visit', function (evnt) { + classnames = document + .querySelector('.mm-wrapper') + .className.split(' ') + .filter(function (name) { return /mm-/.test(name); }); + }); + document.addEventListener('turbolinks:load', function (evnt) { + if (typeof classnames === 'undefined') { + return; + } + document.querySelector('.mm-wrapper').className = classnames; + }); +} diff --git a/dist/wrappers/wordpress/mmenu.wordpress.js b/dist/wrappers/wordpress/mmenu.wordpress.js new file mode 100644 index 0000000..821fda0 --- /dev/null +++ b/dist/wrappers/wordpress/mmenu.wordpress.js @@ -0,0 +1,8 @@ +export default function () { + this.conf.classNames.selected = 'current-menu-item'; + var wpadminbar = document.getElementById('wpadminbar'); + if (wpadminbar) { + wpadminbar.style.position = 'fixed'; + wpadminbar.classList.add('mm-slideout'); + } +} diff --git a/gulp/css.js b/gulp/css.js new file mode 100644 index 0000000..bd19d2c --- /dev/null +++ b/gulp/css.js @@ -0,0 +1,142 @@ +/* + CSS tasks. + *) The includes, variables and mixins are concatenated into the "input" dir. + **) For a custom build, the includes and variables are copied from the specified "custom input" dir (--i flag), into the "input" dir. +*/ + +const { src, dest, watch, series, parallel } = require('gulp'); + +const sass = require('gulp-sass'); +const autoprefixer = require('gulp-autoprefixer'); +const cleancss = require('gulp-clean-css'); +const concat = require('gulp-concat'); + +const dirs = require('./dirs'); +var dir = {}; + +/** Run all scripts. */ +exports.all = CSSall = cb => { + dir = dirs(false); + + series( + parallel(CSSconcatMixins, CSSconcatIncludes, CSSconcatVariables), + CSScompile + )(cb); +}; + +exports.custom = CSScustom = cb => { + dir = dirs(true); + + const CSScompileCustom = cb => CSScompile(cb, dir.build + '/mmenu.scss'); + + series(parallel(CSScopyIncludes, CSScopyVariables), CSScompileCustom)(cb); +}; + +/** Put a watch on all files. */ +exports.watch = CSSwatch = cb => { + dir = dirs(false); + + watch([ + dir.input + '/**/*.scss', + '!' + dir.input + '/_includes.scss', + '!' + dir.input + '/_variables.scss', + '!' + dir.input + '/_mixins.scss' + ]).on('change', path => { + console.log('Change detected to .scss file "' + path + '"'); + var cb = () => { + console.log('CSS compiled and concatenated.'); + }; + + switch (true) { + // Changing an include, a variable or a mixin potentially affects all .scss files: + // - run all CSS tasks. + case path.indexOf('_includes.scss') > -1: + case path.indexOf('_variables.scss') > -1: + case path.indexOf('_mixins.scss') > -1: + CSSall(cb); + break; + + // Changing any other file should only affect the files in the same directory: + // - compile only the directory to css; + // - concatenate all. + default: + var files = path.split('/'); + files.pop(); + files.shift(); + files = files.join('/'); + + var CSScompileOne = cb => + CSScompile( + cb, + dir.input + '/' + files + '/*.scss', + dir.output + '/' + files + ); + + series(CSScompileOne, CSScompile)(cb); + break; + } + }); + + cb(); +}; + +// *) Concatenate includes into a single file. +const CSSconcatIncludes = cb => { + var files = [ + dir.input + '/core/oncanvas/_includes.scss', // Include oncanvas includes first. + dir.input + '/core/**/_includes.scss', // Include core add-ons includes next. + dir.input + '/**/_includes.scss', // Include the rest of the includes. + '!' + dir.input + '/_includes.scss' // Exclude the includes destination file. + ]; + + return src(files) + .pipe(concat('_includes.scss')) + .pipe(dest(dir.input)); +}; + +// *) Concatenate variables into a single file. +const CSSconcatVariables = cb => { + var files = [ + dir.input + '/core/oncanvas/_variables.scss', // Include oncanvas variables first. + dir.input + '/core/**/_variables.scss', // Include core add-ons variables next. + dir.input + '/**/_variables.scss', // Include the rest of the variables. + '!' + dir.input + '/_variables.scss' // Exclude the variables destination file. + ]; + + return src(files) + .pipe(concat('_variables.scss')) + .pipe(dest(dir.input)); +}; + +// Concatenate mixins into a single file. +const CSSconcatMixins = cb => { + var files = [ + dir.input + '/core/oncanvas/_mixins.scss', // Include oncanvas mixins first. + dir.input + '/core/**/_mixins.scss', // Include core add-ons mixins next. + dir.input + '/**/_mixins.scss', // Include the rest of the mixins. + '!' + dir.input + '/_mixins.scss' // Exclude the mixins destination file. + ]; + + return src(files) + .pipe(concat('_mixins.scss')) + .pipe(dest(dir.input)); +}; + +// **) Copy includes from custom input into input. +const CSScopyIncludes = cb => { + return src(dir.build + '/**/_includes.scss').pipe(dest(dir.input)); +}; + +// **) Copy variables from custom input into input. +const CSScopyVariables = cb => { + return src(dir.build + '/**/_variables.scss').pipe(dest(dir.input)); +}; + +// Compile all (or some) SCSS files to CSS. +const CSScompile = (cb, input, output) => { + return src(input || dir.input + '/**/*.scss') + .pipe(sass().on('error', sass.logError)) + .pipe(autoprefixer(['> 5%', 'last 5 versions'])) + .pipe(cleancss()) + .pipe(dest(output || dir.output)); +}; diff --git a/gulp/dirs.js b/gulp/dirs.js new file mode 100644 index 0000000..9885e68 --- /dev/null +++ b/gulp/dirs.js @@ -0,0 +1,35 @@ +const getOption = opt => { + var index = process.argv.indexOf('--' + opt); + if (index > -1) { + opt = process.argv[index + 1]; + return opt && opt.slice(0, 2) !== '--' ? opt : false; + } + return false; +}; + +module.exports = findCustom => { + var dirs = { + input: 'src', + output: 'dist', + build: null + }; + + if (!findCustom) { + return dirs; + } + + var i = getOption('i'), + o = getOption('o'); + + // Set custom input dir. + if (i) { + dirs.build = i; + } + + // Set custom output dir. + if (o) { + dirs.output = o; + } + + return dirs; +}; diff --git a/gulp/js.js b/gulp/js.js new file mode 100644 index 0000000..720e33c --- /dev/null +++ b/gulp/js.js @@ -0,0 +1,93 @@ +/* + JS tasks. + *) The "module" file is transpiled from the specified "custom input" dir. +*/ + +const { src, dest, watch, series } = require('gulp'); + +const typescript = require('gulp-typescript'); +const webpack = require('webpack-stream'); + +const dirs = require('./dirs.js'); +var dir = {}; + +/** Run all scripts. */ +exports.all = JSall = cb => { + dir = dirs(false); + + series(JStranspile, JSpack)(cb); +}; + +exports.custom = JScustom = cb => { + dir = dirs(true); + + series(JSpack)(cb); +}; + +/** Put a watch on all files. */ +exports.watch = JSwatch = cb => { + dir = dirs(false); + + watch(dir.input + '/**/*.ts', { + ignored: [ + dir.input + '/**/*.d.ts' // Exclude all typings. + ] + }).on('change', path => { + console.log('Change detected to .ts file "' + path + '"'); + var cb = () => { + console.log('JS transpiled and concatenated.'); + }; + + // Changing any file only affects the files in the same directory: + // - transpile only the directory to js; + // - pack all. + var files = path.split('/'); + files.pop(); + files.shift(); + files = files.join('/'); + + var input = dir.input + '/' + files + '/*.ts', + output = dir.output + '/' + files; + + var JStranspileOne = cb => JStranspile(cb, input, output); + + series(JStranspileOne, JSpack)(cb); + }); + + cb(); +}; + +// *) Transpile all TS files to JS. +const JStranspile = (cb, input, output) => { + return src([ + dir.input + '/**/*.d.ts', // Include all typings. + input || dir.input + '/**/*.ts' // Include the needed ts files. + ]) + .pipe( + typescript({ + target: 'es5', + module: 'es6' + }) + ) + .pipe(dest(output || dir.output)); +}; + +// Pack the files. +const JSpack = () => { + var input = dir.build || dir.input; + + return src(input + '/mmenu.js') + .pipe( + webpack({ + // mode: 'development', + mode: 'production', + output: { + filename: 'mmenu.js' + } + // optimization: { + // minimize: false + // } + }) + ) + .pipe(dest(dir.output)); +}; diff --git a/gulp/polyfills.js b/gulp/polyfills.js new file mode 100644 index 0000000..93dadaa --- /dev/null +++ b/gulp/polyfills.js @@ -0,0 +1,27 @@ +/* + Polyfill tasks. +*/ + +const { src, dest } = require('gulp'); +const concat = require('gulp-concat'); +const dirs = require('./dirs.js'); + +var dir = {}; + +module.exports = cb => { + dir = dirs(true); + + // Some polyfills might rely on others, + // therefor we include 'em in a fixed order. + return src([ + dir.input + '/_polyfills/api.foreach.js', + dir.input + '/_polyfills/api.matches.js', + dir.input + '/_polyfills/api.closest.js', + dir.input + '/_polyfills/dom.prepend.js', + dir.input + '/_polyfills/dom.append.js', + dir.input + '/_polyfills/dom.before.js', + dir.input + '/_polyfills/dom.remove.js' + ]) + .pipe(concat('mmenu.polyfills.js')) + .pipe(dest(dir.output)); +}; diff --git a/gulpfile.js b/gulpfile.js new file mode 100755 index 0000000..c468b6f --- /dev/null +++ b/gulpfile.js @@ -0,0 +1,69 @@ +/* + Tasks: + + $ gulp : Runs the "js" and "css" tasks. + $ gulp js : Runs the "js" tasks. + $ gulp css : Runs the "css" tasks. + $ gulp watch : Starts a watch on the "js" and "css" tasks. + $ gulp polyfill : Creates the polyfill file. + + + Flags for the custom task: + + --i ../path/to : Create a custom build using "mmenu.module.ts", "_includes.scss" and "_variables.scss" from the specified directory. + --o ../path/to : Sets the "output" directory to the specified directory. + + + Example: + + $ gulp custom --i ../my-custom-input --o ../my-custom-output + $ gulp polyfill --i ../my-custom-input --o ../my-custom-output +*/ + +const { parallel, series } = require('gulp'); + +const js = require('./gulp/js'); +const css = require('./gulp/css'); +const polyfills = require('./gulp/polyfills'); + +/* + $ gulp +*/ +exports.default = cb => { + parallel(js.all, css.all)(cb); +}; + +/* + $ gulp js +*/ +exports.js = cb => { + js.all(cb); +}; + +/* + $ gulp css +*/ +exports.css = cb => { + css.all(cb); +}; + +/* + $ gulp custom +*/ +exports.custom = cb => { + parallel(js.custom, css.custom)(cb); +}; + +/* + $ gulp watch +*/ +exports.watch = cb => { + parallel(series(js.all, js.watch), series(css.all, css.watch))(cb); +}; + +/* + $ gulp polyfill +*/ +exports.polyfill = cb => { + parallel(polyfills)(cb); +}; diff --git a/index.html b/index.html new file mode 100644 index 0000000..6afbe62 --- /dev/null +++ b/index.html @@ -0,0 +1,28 @@ + + + + + + + + + mmenu.js, app look-alike menus with sliding submenus. + + + + + +
+
+ +
+
+

mmenu

+

The best javascript plugin for app look-alike on- and off-canvas menus with sliding submenus for your website and web-app.

+

Check out the example on the left or play around with the options.

+

For the full documentation please visit: mmenujs.com

+

There also is a WordPress plugin available.

+
+
+ + \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 0000000..cb18b05 --- /dev/null +++ b/package-lock.json @@ -0,0 +1,6270 @@ +{ + "name": "mmenu-js", + "version": "8.5.3", + "lockfileVersion": 1, + "requires": true, + "dependencies": { + "@webassemblyjs/ast": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ast/-/ast-1.8.5.tgz", + "integrity": "sha512-aJMfngIZ65+t71C3y2nBBg5FFG0Okt9m0XEgWZ7Ywgn1oMAT8cNwx00Uv1cQyHtidq0Xn94R4TAywO+LCQ+ZAQ==", + "dev": true, + "requires": { + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5" + } + }, + "@webassemblyjs/floating-point-hex-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/floating-point-hex-parser/-/floating-point-hex-parser-1.8.5.tgz", + "integrity": "sha512-9p+79WHru1oqBh9ewP9zW95E3XAo+90oth7S5Re3eQnECGq59ly1Ri5tsIipKGpiStHsUYmY3zMLqtk3gTcOtQ==", + "dev": true + }, + "@webassemblyjs/helper-api-error": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-api-error/-/helper-api-error-1.8.5.tgz", + "integrity": "sha512-Za/tnzsvnqdaSPOUXHyKJ2XI7PDX64kWtURyGiJJZKVEdFOsdKUCPTNEVFZq3zJ2R0G5wc2PZ5gvdTRFgm81zA==", + "dev": true + }, + "@webassemblyjs/helper-buffer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-buffer/-/helper-buffer-1.8.5.tgz", + "integrity": "sha512-Ri2R8nOS0U6G49Q86goFIPNgjyl6+oE1abW1pS84BuhP1Qcr5JqMwRFT3Ah3ADDDYGEgGs1iyb1DGX+kAi/c/Q==", + "dev": true + }, + "@webassemblyjs/helper-code-frame": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-code-frame/-/helper-code-frame-1.8.5.tgz", + "integrity": "sha512-VQAadSubZIhNpH46IR3yWO4kZZjMxN1opDrzePLdVKAZ+DFjkGD/rf4v1jap744uPVU6yjL/smZbRIIJTOUnKQ==", + "dev": true, + "requires": { + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/helper-fsm": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-fsm/-/helper-fsm-1.8.5.tgz", + "integrity": "sha512-kRuX/saORcg8se/ft6Q2UbRpZwP4y7YrWsLXPbbmtepKr22i8Z4O3V5QE9DbZK908dh5Xya4Un57SDIKwB9eow==", + "dev": true + }, + "@webassemblyjs/helper-module-context": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-module-context/-/helper-module-context-1.8.5.tgz", + "integrity": "sha512-/O1B236mN7UNEU4t9X7Pj38i4VoU8CcMHyy3l2cV/kIF4U5KoHXDVqcDuOs1ltkac90IM4vZdHc52t1x8Yfs3g==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "mamacro": "^0.0.3" + } + }, + "@webassemblyjs/helper-wasm-bytecode": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-bytecode/-/helper-wasm-bytecode-1.8.5.tgz", + "integrity": "sha512-Cu4YMYG3Ddl72CbmpjU/wbP6SACcOPVbHN1dI4VJNJVgFwaKf1ppeFJrwydOG3NDHxVGuCfPlLZNyEdIYlQ6QQ==", + "dev": true + }, + "@webassemblyjs/helper-wasm-section": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/helper-wasm-section/-/helper-wasm-section-1.8.5.tgz", + "integrity": "sha512-VV083zwR+VTrIWWtgIUpqfvVdK4ff38loRmrdDBgBT8ADXYsEZ5mPQ4Nde90N3UYatHdYoDIFb7oHzMncI02tA==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5" + } + }, + "@webassemblyjs/ieee754": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/ieee754/-/ieee754-1.8.5.tgz", + "integrity": "sha512-aaCvQYrvKbY/n6wKHb/ylAJr27GglahUO89CcGXMItrOBqRarUMxWLJgxm9PJNuKULwN5n1csT9bYoMeZOGF3g==", + "dev": true, + "requires": { + "@xtuc/ieee754": "^1.2.0" + } + }, + "@webassemblyjs/leb128": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/leb128/-/leb128-1.8.5.tgz", + "integrity": "sha512-plYUuUwleLIziknvlP8VpTgO4kqNaH57Y3JnNa6DLpu/sGcP6hbVdfdX5aHAV716pQBKrfuU26BJK29qY37J7A==", + "dev": true, + "requires": { + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/utf8": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/utf8/-/utf8-1.8.5.tgz", + "integrity": "sha512-U7zgftmQriw37tfD934UNInokz6yTmn29inT2cAetAsaU9YeVCveWEwhKL1Mg4yS7q//NGdzy79nlXh3bT8Kjw==", + "dev": true + }, + "@webassemblyjs/wasm-edit": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-edit/-/wasm-edit-1.8.5.tgz", + "integrity": "sha512-A41EMy8MWw5yvqj7MQzkDjU29K7UJq1VrX2vWLzfpRHt3ISftOXqrtojn7nlPsZ9Ijhp5NwuODuycSvfAO/26Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/helper-wasm-section": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-opt": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "@webassemblyjs/wast-printer": "1.8.5" + } + }, + "@webassemblyjs/wasm-gen": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-gen/-/wasm-gen-1.8.5.tgz", + "integrity": "sha512-BCZBT0LURC0CXDzj5FXSc2FPTsxwp3nWcqXQdOZE4U7h7i8FqtFK5Egia6f9raQLpEKT1VL7zr4r3+QX6zArWg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wasm-opt": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-opt/-/wasm-opt-1.8.5.tgz", + "integrity": "sha512-HKo2mO/Uh9A6ojzu7cjslGaHaUU14LdLbGEKqTR7PBKwT6LdPtLLh9fPY33rmr5wcOMrsWDbbdCHq4hQUdd37Q==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-buffer": "1.8.5", + "@webassemblyjs/wasm-gen": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5" + } + }, + "@webassemblyjs/wasm-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wasm-parser/-/wasm-parser-1.8.5.tgz", + "integrity": "sha512-pi0SYE9T6tfcMkthwcgCpL0cM9nRYr6/6fjgDtL6q/ZqKHdMWvxitRi5JcZ7RI4SNJJYnYNaWy5UUrHQy998lw==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-wasm-bytecode": "1.8.5", + "@webassemblyjs/ieee754": "1.8.5", + "@webassemblyjs/leb128": "1.8.5", + "@webassemblyjs/utf8": "1.8.5" + } + }, + "@webassemblyjs/wast-parser": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-parser/-/wast-parser-1.8.5.tgz", + "integrity": "sha512-daXC1FyKWHF1i11obK086QRlsMsY4+tIOKgBqI1lxAnkp9xe9YMcgOxm9kLe+ttjs5aWV2KKE1TWJCN57/Btsg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/floating-point-hex-parser": "1.8.5", + "@webassemblyjs/helper-api-error": "1.8.5", + "@webassemblyjs/helper-code-frame": "1.8.5", + "@webassemblyjs/helper-fsm": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@webassemblyjs/wast-printer": { + "version": "1.8.5", + "resolved": "https://registry.npmjs.org/@webassemblyjs/wast-printer/-/wast-printer-1.8.5.tgz", + "integrity": "sha512-w0U0pD4EhlnvRyeJzBqaVSJAo9w/ce7/WPogeXLzGkO6hzhr4GnQIZ4W4uUt5b9ooAaXPtnXlj0gzsXEOUNYMg==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/wast-parser": "1.8.5", + "@xtuc/long": "4.2.2" + } + }, + "@xtuc/ieee754": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/@xtuc/ieee754/-/ieee754-1.2.0.tgz", + "integrity": "sha512-DX8nKgqcGwsc0eJSqYt5lwP4DH5FlHnmuWWBRy7X0NcaGR0ZtuyeESgMwTYVEtxmsNGY+qit4QYT/MIYTOTPeA==", + "dev": true + }, + "@xtuc/long": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/@xtuc/long/-/long-4.2.2.tgz", + "integrity": "sha512-NuHqBY1PB/D8xU6s/thBgOAiAP7HOYDQ32+BFZILJ8ivkUkAHQnWfn6WhL79Owj1qmUnoN/YPhktdIoucipkAQ==", + "dev": true + }, + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true + }, + "acorn": { + "version": "6.4.1", + "resolved": "https://registry.npmjs.org/acorn/-/acorn-6.4.1.tgz", + "integrity": "sha512-ZVA9k326Nwrj3Cj9jlh3wGFutC2ZornPNARZwsNYqQYgN0EsV2d53w5RN/co65Ohn4sUAUtb1rSUAOD6XN9idA==", + "dev": true + }, + "ajv": { + "version": "6.7.0", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.7.0.tgz", + "integrity": "sha512-RZXPviBTtfmtka9n9sy1N5M5b82CbxWIR6HIis4s3WQTXDJamc/0gpCWNGz6EWdWp4DOfjzJfhz/AS9zVPjjWg==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + }, + "ajv-errors": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ajv-errors/-/ajv-errors-1.0.1.tgz", + "integrity": "sha512-DCRfO/4nQ+89p/RK43i8Ezd41EqdGIU4ld7nGF8OQ14oc/we5rEntLCUa7+jrn3nn83BosfwZA0wb4pon2o8iQ==", + "dev": true + }, + "ajv-keywords": { + "version": "3.4.1", + "resolved": "https://registry.npmjs.org/ajv-keywords/-/ajv-keywords-3.4.1.tgz", + "integrity": "sha512-RO1ibKvd27e6FEShVFfPALuHI3WjSVNeK5FIsmme/LYRNxjKuNj+Dt7bucLa6NdSv3JcVTyMlm9kGR84z1XpaQ==", + "dev": true + }, + "amdefine": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/amdefine/-/amdefine-1.0.1.tgz", + "integrity": "sha1-SlKCrBZHKek2Gbz9OtFR+BfOkfU=", + "dev": true + }, + "ansi-colors": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-1.1.0.tgz", + "integrity": "sha512-SFKX67auSNoVR38N3L+nvsPjOE0bybKTYbkf5tRvushrAPQ9V75huw0ZxBkKVeRU9kqH3d6HA4xTckbwZ4ixmA==", + "dev": true, + "requires": { + "ansi-wrap": "^0.1.0" + } + }, + "ansi-gray": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/ansi-gray/-/ansi-gray-0.1.1.tgz", + "integrity": "sha1-KWLPVOyXksSFEKPetSRDaGHvclE=", + "dev": true, + "requires": { + "ansi-wrap": "0.1.0" + } + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "ansi-styles": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-3.2.1.tgz", + "integrity": "sha512-VT0ZI6kZRdTh8YyJw3SMbYm/u+NqfsAxEpWO0Pf9sq8/e94WxxOpPKx9FR1FlyCtOVDNOQ+8ntlqFxiRc+r5qA==", + "dev": true, + "requires": { + "color-convert": "^1.9.0" + } + }, + "ansi-wrap": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/ansi-wrap/-/ansi-wrap-0.1.0.tgz", + "integrity": "sha1-qCJQ3bABXponyoLoLqYDu/pF768=", + "dev": true + }, + "anymatch": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/anymatch/-/anymatch-2.0.0.tgz", + "integrity": "sha512-5teOsQWABXHHBFP9y3skS5P3d/WfWXpv3FUpy+LorMrNYaT9pI4oLMQX7jzQ2KklNpGpWHzdCXTDT2Y3XGlZBw==", + "dev": true, + "requires": { + "micromatch": "^3.1.4", + "normalize-path": "^2.1.1" + } + }, + "append-buffer": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/append-buffer/-/append-buffer-1.0.2.tgz", + "integrity": "sha1-2CIM9GYIFSXv6lBhTz3mUU36WPE=", + "dev": true, + "requires": { + "buffer-equal": "^1.0.0" + } + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true + }, + "archy": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/archy/-/archy-1.0.0.tgz", + "integrity": "sha1-+cjBN1fMHde8N5rHeyxipcKGjEA=", + "dev": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "arr-diff": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/arr-diff/-/arr-diff-4.0.0.tgz", + "integrity": "sha1-1kYQdP6/7HHn4VI1dhoyml3HxSA=", + "dev": true + }, + "arr-filter": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/arr-filter/-/arr-filter-1.1.2.tgz", + "integrity": "sha1-Q/3d0JHo7xGqTEXZzcGOLf8XEe4=", + "dev": true, + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-flatten": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/arr-flatten/-/arr-flatten-1.1.0.tgz", + "integrity": "sha512-L3hKV5R/p5o81R7O02IGnwpDmkp6E982XhtbuwSe3O4qOtMMMtodicASA1Cny2U+aCXcNpml+m4dPsvsJ3jatg==", + "dev": true + }, + "arr-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/arr-map/-/arr-map-2.0.2.tgz", + "integrity": "sha1-Onc0X/wc814qkYJWAfnljy4kysQ=", + "dev": true, + "requires": { + "make-iterator": "^1.0.0" + } + }, + "arr-union": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/arr-union/-/arr-union-3.1.0.tgz", + "integrity": "sha1-45sJrqne+Gao8gbiiK9jkZuuOcQ=", + "dev": true + }, + "array-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/array-each/-/array-each-1.0.1.tgz", + "integrity": "sha1-p5SvDAWrF1KEbudTofIRoFugxE8=", + "dev": true + }, + "array-find-index": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/array-find-index/-/array-find-index-1.0.2.tgz", + "integrity": "sha1-3wEKoSh+Fku9pvlyOwqWoexBh6E=", + "dev": true + }, + "array-initial": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-initial/-/array-initial-1.1.0.tgz", + "integrity": "sha1-L6dLJnOTccOUe9enrcc74zSz15U=", + "dev": true, + "requires": { + "array-slice": "^1.0.0", + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "array-last": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/array-last/-/array-last-1.3.0.tgz", + "integrity": "sha512-eOCut5rXlI6aCOS7Z7kCplKRKyiFQ6dHFBem4PwlwKeNFk2/XxTrhRh5T9PyaEWGy/NHTZWbY+nsZlNFJu9rYg==", + "dev": true, + "requires": { + "is-number": "^4.0.0" + }, + "dependencies": { + "is-number": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-4.0.0.tgz", + "integrity": "sha512-rSklcAIlf1OmFdyAqbnWTLVelsQ58uvZ66S/ZyawjWqIviTWCjg2PzVGw8WUA+nNuPTqb4wgA+NszrJ+08LlgQ==", + "dev": true + } + } + }, + "array-slice": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/array-slice/-/array-slice-1.1.0.tgz", + "integrity": "sha512-B1qMD3RBP7O8o0H2KbrXDyB0IccejMF15+87Lvlor12ONPRHP6gTjXMNkt/d3ZuOGbAe66hFmaCfECI24Ufp6w==", + "dev": true + }, + "array-sort": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/array-sort/-/array-sort-1.0.0.tgz", + "integrity": "sha512-ihLeJkonmdiAsD7vpgN3CRcx2J2S0TiYW+IS/5zHBI7mKUq3ySvBdzzBfD236ubDBQFiiyG3SWCPc+msQ9KoYg==", + "dev": true, + "requires": { + "default-compare": "^1.0.0", + "get-value": "^2.0.6", + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "array-unique": { + "version": "0.3.2", + "resolved": "https://registry.npmjs.org/array-unique/-/array-unique-0.3.2.tgz", + "integrity": "sha1-qJS3XUvE9s1nnvMkSp/Y9Gri1Cg=", + "dev": true + }, + "asn1": { + "version": "0.2.4", + "resolved": "https://registry.npmjs.org/asn1/-/asn1-0.2.4.tgz", + "integrity": "sha512-jxwzQpLQjSmWXgwaCZE9Nz+glAG01yF1QnWgbhGwHI5A6FRIEY6IVqtHhIepHqI7/kyEyQEagBC5mBEFlIYvdg==", + "dev": true, + "requires": { + "safer-buffer": "~2.1.0" + } + }, + "asn1.js": { + "version": "4.10.1", + "resolved": "https://registry.npmjs.org/asn1.js/-/asn1.js-4.10.1.tgz", + "integrity": "sha512-p32cOF5q0Zqs9uBiONKYLm6BClCoBCM5O9JfeUSlnQLBTxYdTK+pW+nXflm8UkKd2UYlEbYz5qEi0JuZR9ckSw==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "assert": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/assert/-/assert-1.5.0.tgz", + "integrity": "sha512-EDsgawzwoun2CZkCgtxJbv392v4nbk9XDD06zI+kQYoBM/3RBWLlEyJARDOmhAAosBjWACEkKL6S+lIZtcAubA==", + "dev": true, + "requires": { + "object-assign": "^4.1.1", + "util": "0.10.3" + }, + "dependencies": { + "inherits": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.1.tgz", + "integrity": "sha1-sX0I0ya0Qj5Wjv9xn5GwscvfafE=", + "dev": true + }, + "util": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/util/-/util-0.10.3.tgz", + "integrity": "sha1-evsa/lCAUkZInj23/g7TeTNqwPk=", + "dev": true, + "requires": { + "inherits": "2.0.1" + } + } + } + }, + "assert-plus": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assert-plus/-/assert-plus-1.0.0.tgz", + "integrity": "sha1-8S4PPF13sLHN2RRpQuTpbB5N1SU=", + "dev": true + }, + "assign-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/assign-symbols/-/assign-symbols-1.0.0.tgz", + "integrity": "sha1-WWZ/QfrdTyDMvCu5a41Pf3jsA2c=", + "dev": true + }, + "async-done": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/async-done/-/async-done-1.3.1.tgz", + "integrity": "sha512-R1BaUeJ4PMoLNJuk+0tLJgjmEqVsdN118+Z8O+alhnQDQgy0kmD5Mqi0DNEmMx2LM0Ed5yekKu+ZXYvIHceicg==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.2", + "process-nextick-args": "^1.0.7", + "stream-exhaust": "^1.0.1" + } + }, + "async-each": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/async-each/-/async-each-1.0.1.tgz", + "integrity": "sha1-GdOGodntxufByF04iu28xW0zYC0=", + "dev": true + }, + "async-foreach": { + "version": "0.1.3", + "resolved": "https://registry.npmjs.org/async-foreach/-/async-foreach-0.1.3.tgz", + "integrity": "sha1-NhIfhFwFeBct5Bmpfb6x0W7DRUI=", + "dev": true + }, + "async-settle": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/async-settle/-/async-settle-1.0.0.tgz", + "integrity": "sha1-HQqRS7Aldb7IqPOnTlCA9yssDGs=", + "dev": true, + "requires": { + "async-done": "^1.2.2" + } + }, + "asynckit": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/asynckit/-/asynckit-0.4.0.tgz", + "integrity": "sha1-x57Zf380y48robyXkLzDZkdLS3k=", + "dev": true + }, + "atob": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/atob/-/atob-2.1.2.tgz", + "integrity": "sha512-Wm6ukoaOGJi/73p/cl2GvLjTI5JM1k/O14isD73YML8StrH/7/lRFgmg8nICZgD3bZZvjwCGxtMOD3wWNAu8cg==", + "dev": true + }, + "autoprefixer": { + "version": "9.5.1", + "resolved": "https://registry.npmjs.org/autoprefixer/-/autoprefixer-9.5.1.tgz", + "integrity": "sha512-KJSzkStUl3wP0D5sdMlP82Q52JLy5+atf2MHAre48+ckWkXgixmfHyWmA77wFDy6jTHU6mIgXv6hAQ2mf1PjJQ==", + "dev": true, + "requires": { + "browserslist": "^4.5.4", + "caniuse-lite": "^1.0.30000957", + "normalize-range": "^0.1.2", + "num2fraction": "^1.2.2", + "postcss": "^7.0.14", + "postcss-value-parser": "^3.3.1" + } + }, + "aws-sign2": { + "version": "0.7.0", + "resolved": "https://registry.npmjs.org/aws-sign2/-/aws-sign2-0.7.0.tgz", + "integrity": "sha1-tG6JCTSpWR8tL2+G1+ap8bP+dqg=", + "dev": true + }, + "aws4": { + "version": "1.9.1", + "resolved": "https://registry.npmjs.org/aws4/-/aws4-1.9.1.tgz", + "integrity": "sha512-wMHVg2EOHaMRxbzgFJ9gtjOOCrI80OHLG14rxi28XwOW8ux6IiEbRCGGGqCtdAIg4FQCbW20k9RsT4y3gJlFug==", + "dev": true + }, + "bach": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/bach/-/bach-1.2.0.tgz", + "integrity": "sha1-Szzpa/JxNPeaG0FKUcFONMO9mIA=", + "dev": true, + "requires": { + "arr-filter": "^1.1.1", + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "array-each": "^1.0.0", + "array-initial": "^1.0.0", + "array-last": "^1.1.1", + "async-done": "^1.2.2", + "async-settle": "^1.0.0", + "now-and-later": "^2.0.0" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "base": { + "version": "0.11.2", + "resolved": "https://registry.npmjs.org/base/-/base-0.11.2.tgz", + "integrity": "sha512-5T6P4xPgpp0YDFvSWwEZ4NoE3aM4QBQXDzmVbraCkFj8zHM+mba8SyqB5DbZWyR7mYHo6Y7BdQo3MoA4m0TeQg==", + "dev": true, + "requires": { + "cache-base": "^1.0.1", + "class-utils": "^0.3.5", + "component-emitter": "^1.2.1", + "define-property": "^1.0.0", + "isobject": "^3.0.1", + "mixin-deep": "^1.2.0", + "pascalcase": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "base64-js": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/base64-js/-/base64-js-1.3.1.tgz", + "integrity": "sha512-mLQ4i2QO1ytvGWFWmcngKO//JXAQueZvwEKtjgQFM4jIK0kU+ytMfplL8j+n5mspOfjHwoAg+9yhb7BwAHm36g==", + "dev": true + }, + "bcrypt-pbkdf": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/bcrypt-pbkdf/-/bcrypt-pbkdf-1.0.2.tgz", + "integrity": "sha1-pDAdOJtqQ/m2f/PKEaP2Y342Dp4=", + "dev": true, + "requires": { + "tweetnacl": "^0.14.3" + } + }, + "big.js": { + "version": "5.2.2", + "resolved": "https://registry.npmjs.org/big.js/-/big.js-5.2.2.tgz", + "integrity": "sha512-vyL2OymJxmarO8gxMr0mhChsO9QGwhynfuu4+MHTAW6czfq9humCB7rKpUjDd9YUiDPU4mzpyupFSvOClAwbmQ==", + "dev": true + }, + "binary-extensions": { + "version": "1.12.0", + "resolved": "https://registry.npmjs.org/binary-extensions/-/binary-extensions-1.12.0.tgz", + "integrity": "sha512-DYWGk01lDcxeS/K9IHPGWfT8PsJmbXRtRd2Sx72Tnb8pcYZQFF1oSDb8hJtS1vhp212q1Rzi5dUf9+nq0o9UIg==", + "dev": true + }, + "block-stream": { + "version": "0.0.9", + "resolved": "https://registry.npmjs.org/block-stream/-/block-stream-0.0.9.tgz", + "integrity": "sha1-E+v+d4oDIFz+A3UUgeu0szAMEmo=", + "dev": true, + "requires": { + "inherits": "~2.0.0" + } + }, + "bluebird": { + "version": "3.7.2", + "resolved": "https://registry.npmjs.org/bluebird/-/bluebird-3.7.2.tgz", + "integrity": "sha512-XpNj6GDQzdfW+r2Wnn7xiSAd7TM3jzkxGXBGTtWKuSXv1xUV+azxAm8jdWZN06QTQk+2N2XB9jRDkvbmQmcRtg==", + "dev": true + }, + "bn.js": { + "version": "4.11.8", + "resolved": "https://registry.npmjs.org/bn.js/-/bn.js-4.11.8.tgz", + "integrity": "sha512-ItfYfPLkWHUjckQCk8xC+LwxgK8NYcXywGigJgSwOP8Y2iyWT4f2vsZnoOXTTbo+o5yXmIUJ4gn5538SO5S3gA==", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "braces": { + "version": "2.3.2", + "resolved": "https://registry.npmjs.org/braces/-/braces-2.3.2.tgz", + "integrity": "sha512-aNdbnj9P8PjdXU4ybaWLK2IF3jc/EoDYbC7AazW6to3TRsfXxscC9UXOB5iDiEQrkyIbWp2SLQda4+QAa7nc3w==", + "dev": true, + "requires": { + "arr-flatten": "^1.1.0", + "array-unique": "^0.3.2", + "extend-shallow": "^2.0.1", + "fill-range": "^4.0.0", + "isobject": "^3.0.1", + "repeat-element": "^1.1.2", + "snapdragon": "^0.8.1", + "snapdragon-node": "^2.0.1", + "split-string": "^3.0.2", + "to-regex": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "brorand": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/brorand/-/brorand-1.1.0.tgz", + "integrity": "sha1-EsJe/kCkXjwyPrhnWgoM5XsiNx8=", + "dev": true + }, + "browserify-aes": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/browserify-aes/-/browserify-aes-1.2.0.tgz", + "integrity": "sha512-+7CHXqGuspUn/Sl5aO7Ea0xWGAtETPXNSAjHo48JfLdPWcMng33Xe4znFvQweqc/uzk5zSOI3H52CYnjCfb5hA==", + "dev": true, + "requires": { + "buffer-xor": "^1.0.3", + "cipher-base": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.3", + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "browserify-cipher": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/browserify-cipher/-/browserify-cipher-1.0.1.tgz", + "integrity": "sha512-sPhkz0ARKbf4rRQt2hTpAHqn47X3llLkUGn+xEJzLjwY8LRs2p0v7ljvI5EyoRO/mexrNunNECisZs+gw2zz1w==", + "dev": true, + "requires": { + "browserify-aes": "^1.0.4", + "browserify-des": "^1.0.0", + "evp_bytestokey": "^1.0.0" + } + }, + "browserify-des": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/browserify-des/-/browserify-des-1.0.2.tgz", + "integrity": "sha512-BioO1xf3hFwz4kc6iBhI3ieDFompMhrMlnDFC4/0/vd5MokpuAc3R+LYbwTA9A5Yc9pq9UYPqffKpW2ObuwX5A==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "des.js": "^1.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "browserify-rsa": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/browserify-rsa/-/browserify-rsa-4.0.1.tgz", + "integrity": "sha1-IeCr+vbyApzy+vsTNWenAdQTVSQ=", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "randombytes": "^2.0.1" + } + }, + "browserify-sign": { + "version": "4.0.4", + "resolved": "https://registry.npmjs.org/browserify-sign/-/browserify-sign-4.0.4.tgz", + "integrity": "sha1-qk62jl17ZYuqa/alfmMMvXqT0pg=", + "dev": true, + "requires": { + "bn.js": "^4.1.1", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.2", + "elliptic": "^6.0.0", + "inherits": "^2.0.1", + "parse-asn1": "^5.0.0" + } + }, + "browserify-zlib": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/browserify-zlib/-/browserify-zlib-0.2.0.tgz", + "integrity": "sha512-Z942RysHXmJrhqk88FmKBVq/v5tqmSkDz7p54G/MGyjMnCFFnC79XWNbg+Vta8W6Wb2qtSZTSxIGkJrRpCFEiA==", + "dev": true, + "requires": { + "pako": "~1.0.5" + } + }, + "browserslist": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/browserslist/-/browserslist-4.6.0.tgz", + "integrity": "sha512-Jk0YFwXBuMOOol8n6FhgkDzn3mY9PYLYGk29zybF05SbRTsMgPqmTNeQQhOghCxq5oFqAXE3u4sYddr4C0uRhg==", + "dev": true, + "requires": { + "caniuse-lite": "^1.0.30000967", + "electron-to-chromium": "^1.3.133", + "node-releases": "^1.1.19" + } + }, + "buffer": { + "version": "4.9.2", + "resolved": "https://registry.npmjs.org/buffer/-/buffer-4.9.2.tgz", + "integrity": "sha512-xq+q3SRMOxGivLhBNaUdC64hDTQwejJ+H0T/NB1XMtTVEwNTrfFF3gAxiyW0Bu/xWEGhjVKgUcMhCrUy2+uCWg==", + "dev": true, + "requires": { + "base64-js": "^1.0.2", + "ieee754": "^1.1.4", + "isarray": "^1.0.0" + } + }, + "buffer-equal": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/buffer-equal/-/buffer-equal-1.0.0.tgz", + "integrity": "sha1-WWFrSYME1Var1GaWayLu2j7KX74=", + "dev": true + }, + "buffer-from": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/buffer-from/-/buffer-from-1.1.1.tgz", + "integrity": "sha512-MQcXEUbCKtEo7bhqEs6560Hyd4XaovZlO/k9V3hjVUF/zwW7KBVdSK4gIt/bzwS9MbR5qob+F5jusZsb0YQK2A==", + "dev": true + }, + "buffer-xor": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/buffer-xor/-/buffer-xor-1.0.3.tgz", + "integrity": "sha1-JuYe0UIvtw3ULm42cp7VHYVf6Nk=", + "dev": true + }, + "builtin-modules": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/builtin-modules/-/builtin-modules-1.1.1.tgz", + "integrity": "sha1-Jw8HbFpywC9bZaR9+Uxf46J4iS8=", + "dev": true + }, + "builtin-status-codes": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/builtin-status-codes/-/builtin-status-codes-3.0.0.tgz", + "integrity": "sha1-hZgoeOIbmOHGZCXgPQF0eI9Wnug=", + "dev": true + }, + "cacache": { + "version": "12.0.3", + "resolved": "https://registry.npmjs.org/cacache/-/cacache-12.0.3.tgz", + "integrity": "sha512-kqdmfXEGFepesTuROHMs3MpFLWrPkSSpRqOw80RCflZXy/khxaArvFrQ7uJxSUduzAufc6G0g1VUCOZXxWavPw==", + "dev": true, + "requires": { + "bluebird": "^3.5.5", + "chownr": "^1.1.1", + "figgy-pudding": "^3.5.1", + "glob": "^7.1.4", + "graceful-fs": "^4.1.15", + "infer-owner": "^1.0.3", + "lru-cache": "^5.1.1", + "mississippi": "^3.0.0", + "mkdirp": "^0.5.1", + "move-concurrently": "^1.0.1", + "promise-inflight": "^1.0.1", + "rimraf": "^2.6.3", + "ssri": "^6.0.1", + "unique-filename": "^1.1.1", + "y18n": "^4.0.0" + }, + "dependencies": { + "glob": { + "version": "7.1.6", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.6.tgz", + "integrity": "sha512-LwaxwyZ72Lk7vZINtNNrywX0ZuLyStrdDtabefZKAY5ZGJhVtgdznluResxNmPitE0SAO+O26sWTHeKSI2wMBA==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "lru-cache": { + "version": "5.1.1", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-5.1.1.tgz", + "integrity": "sha512-KpNARQA3Iwv+jTA0utUVVbrh+Jlrr1Fv0e56GGzAFOXN7dk/FviaDW8LHmK52DlcH4WP2n6gI8vN1aesBFgo9w==", + "dev": true, + "requires": { + "yallist": "^3.0.2" + } + }, + "y18n": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-4.0.0.tgz", + "integrity": "sha512-r9S/ZyXu/Xu9q1tYlpsLIsa3EeLXXk0VwlxqTcFRfg9EhMW+17kbt9G0NrgCmhGb5vT2hyhJZLfDGx+7+5Uj/w==", + "dev": true + }, + "yallist": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.1.1.tgz", + "integrity": "sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g==", + "dev": true + } + } + }, + "cache-base": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cache-base/-/cache-base-1.0.1.tgz", + "integrity": "sha512-AKcdTnFSWATd5/GCPRxr2ChwIJ85CeyrEyjRHlKxQ56d4XJMGym0uAiKn0xbLOGOl3+yRpOTi484dVCEc5AUzQ==", + "dev": true, + "requires": { + "collection-visit": "^1.0.0", + "component-emitter": "^1.2.1", + "get-value": "^2.0.6", + "has-value": "^1.0.0", + "isobject": "^3.0.1", + "set-value": "^2.0.0", + "to-object-path": "^0.3.0", + "union-value": "^1.0.0", + "unset-value": "^1.0.0" + } + }, + "camelcase": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-3.0.0.tgz", + "integrity": "sha1-MvxLn82vhF/N9+c7uXysImHwqwo=", + "dev": true + }, + "camelcase-keys": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/camelcase-keys/-/camelcase-keys-2.1.0.tgz", + "integrity": "sha1-MIvur/3ygRkFHvodkyITyRuPkuc=", + "dev": true, + "requires": { + "camelcase": "^2.0.0", + "map-obj": "^1.0.0" + }, + "dependencies": { + "camelcase": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/camelcase/-/camelcase-2.1.1.tgz", + "integrity": "sha1-fB0W1nmhu+WcoCys7PsBHiAfWh8=", + "dev": true + } + } + }, + "caniuse-lite": { + "version": "1.0.30000971", + "resolved": "https://registry.npmjs.org/caniuse-lite/-/caniuse-lite-1.0.30000971.tgz", + "integrity": "sha512-TQFYFhRS0O5rdsmSbF1Wn+16latXYsQJat66f7S7lizXW1PVpWJeZw9wqqVLIjuxDRz7s7xRUj13QCfd8hKn6g==", + "dev": true + }, + "caseless": { + "version": "0.12.0", + "resolved": "https://registry.npmjs.org/caseless/-/caseless-0.12.0.tgz", + "integrity": "sha1-G2gcIf+EAzyCZUMJBolCDRhxUdw=", + "dev": true + }, + "chalk": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-2.4.2.tgz", + "integrity": "sha512-Mti+f9lpJNcwF4tWV8/OrTTtF1gZi+f8FqlyAdouralcFWFQWF2+NgCHShjkCb+IFBLq9buZwE1xckQU4peSuQ==", + "dev": true, + "requires": { + "ansi-styles": "^3.2.1", + "escape-string-regexp": "^1.0.5", + "supports-color": "^5.3.0" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "chokidar": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/chokidar/-/chokidar-2.0.4.tgz", + "integrity": "sha512-z9n7yt9rOvIJrMhvDtDictKrkFHeihkNl6uWMmZlmL6tJtX9Cs+87oK+teBx+JIgzvbX3yZHT3eF8vpbDxHJXQ==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-each": "^1.0.0", + "braces": "^2.3.0", + "fsevents": "^1.2.2", + "glob-parent": "^3.1.0", + "inherits": "^2.0.1", + "is-binary-path": "^1.0.0", + "is-glob": "^4.0.0", + "lodash.debounce": "^4.0.8", + "normalize-path": "^2.1.1", + "path-is-absolute": "^1.0.0", + "readdirp": "^2.0.0", + "upath": "^1.0.5" + } + }, + "chownr": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.3.tgz", + "integrity": "sha512-i70fVHhmV3DtTl6nqvZOnIjbY0Pe4kAUjwHj8z0zAdgBtYrJyYwLKCCuRBQ5ppkyL0AkN7HKRnETdmdp1zqNXw==", + "dev": true + }, + "chrome-trace-event": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/chrome-trace-event/-/chrome-trace-event-1.0.2.tgz", + "integrity": "sha512-9e/zx1jw7B4CO+c/RXoCsfg/x1AfUBioy4owYH0bJprEYAx5hRFLRhWBqHAG57D0ZM4H7vxbP7bPe0VwhQRYDQ==", + "dev": true, + "requires": { + "tslib": "^1.9.0" + } + }, + "cipher-base": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/cipher-base/-/cipher-base-1.0.4.tgz", + "integrity": "sha512-Kkht5ye6ZGmwv40uUDZztayT2ThLQGfnj/T71N/XzeZeo3nf8foyW7zGTsPYkEya3m5f3cAypH+qe7YOrM1U2Q==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "class-utils": { + "version": "0.3.6", + "resolved": "https://registry.npmjs.org/class-utils/-/class-utils-0.3.6.tgz", + "integrity": "sha512-qOhPa/Fj7s6TY8H8esGu5QNpMMQxz79h+urzrNYN6mn+9BnxlDGf5QZ+XeCDsxSjPqsSR56XOZOJmpeurnLMeg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "define-property": "^0.2.5", + "isobject": "^3.0.0", + "static-extend": "^0.1.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "clean-css": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/clean-css/-/clean-css-4.2.1.tgz", + "integrity": "sha512-4ZxI6dy4lrY6FHzfiy1aEOXgu4LIsW2MhwG0VBKdcoGoH/XLFgaHSdLTGr4O8Be6A8r3MOphEiI8Gc1n0ecf3g==", + "dev": true, + "requires": { + "source-map": "~0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "cliui": { + "version": "3.2.0", + "resolved": "https://registry.npmjs.org/cliui/-/cliui-3.2.0.tgz", + "integrity": "sha1-EgYBU3qRbSmUD5NNo7SNWFo5IT0=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wrap-ansi": "^2.0.0" + } + }, + "clone": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/clone/-/clone-2.1.2.tgz", + "integrity": "sha1-G39Ln1kfHo+DZwQBYANFoCiHQ18=", + "dev": true + }, + "clone-buffer": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-buffer/-/clone-buffer-1.0.0.tgz", + "integrity": "sha1-4+JbIHrE5wGvch4staFnksrD3Fg=", + "dev": true + }, + "clone-stats": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/clone-stats/-/clone-stats-1.0.0.tgz", + "integrity": "sha1-s3gt/4u1R04Yuba/D9/ngvh3doA=", + "dev": true + }, + "cloneable-readable": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/cloneable-readable/-/cloneable-readable-1.1.2.tgz", + "integrity": "sha512-Bq6+4t+lbM8vhTs/Bef5c5AdEMtapp/iFb6+s4/Hh9MVTt8OLKH7ZOOZSCT+Ys7hsHvqv0GuMPJ1lnQJVHvxpg==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "process-nextick-args": "^2.0.0", + "readable-stream": "^2.3.5" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + } + } + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "collection-map": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-map/-/collection-map-1.0.0.tgz", + "integrity": "sha1-rqDwb40mx4DCt1SUOFVEsiVa8Yw=", + "dev": true, + "requires": { + "arr-map": "^2.0.2", + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "collection-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/collection-visit/-/collection-visit-1.0.0.tgz", + "integrity": "sha1-S8A3PBZLwykbTTaMgpzxqApZ3KA=", + "dev": true, + "requires": { + "map-visit": "^1.0.0", + "object-visit": "^1.0.0" + } + }, + "color-convert": { + "version": "1.9.3", + "resolved": "https://registry.npmjs.org/color-convert/-/color-convert-1.9.3.tgz", + "integrity": "sha512-QfAUtd+vFdAtFQcC8CCyYt1fYWxSqAiK2cSD6zDB8N3cpsEBAvRxp9zOGg6G/SHHJYAT88/az/IuDGALsNVbGg==", + "dev": true, + "requires": { + "color-name": "1.1.3" + } + }, + "color-name": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-name/-/color-name-1.1.3.tgz", + "integrity": "sha1-p9BVi9icQveV3UIyj3QIMcpTvCU=", + "dev": true + }, + "color-support": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/color-support/-/color-support-1.1.3.tgz", + "integrity": "sha512-qiBjkpbMLO/HL68y+lh4q0/O1MZFj2RX6X/KmMa3+gJD3z+WwI1ZzDHysvqHGS3mP6mznPckpXmw1nI9cJjyRg==", + "dev": true + }, + "combined-stream": { + "version": "1.0.8", + "resolved": "https://registry.npmjs.org/combined-stream/-/combined-stream-1.0.8.tgz", + "integrity": "sha512-FQN4MRfuJeHf7cBbBMJFXhKSDq+2kAArBlmRBvcvFE5BB1HZKXtSFASDhdlz9zOYwxh8lDdnvmMOe/+5cdoEdg==", + "dev": true, + "requires": { + "delayed-stream": "~1.0.0" + } + }, + "commander": { + "version": "2.20.3", + "resolved": "https://registry.npmjs.org/commander/-/commander-2.20.3.tgz", + "integrity": "sha512-GpVkmM8vF2vQUkj2LvZmD35JxeJOLCwJ9cUkugyk2nuhbv3+mJvpLYYt+0+USMxE+oj+ey/lJEnhZw75x/OMcQ==", + "dev": true + }, + "commondir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/commondir/-/commondir-1.0.1.tgz", + "integrity": "sha1-3dgA2gxmEnOTzKWVDqloo6rxJTs=", + "dev": true + }, + "component-emitter": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/component-emitter/-/component-emitter-1.2.1.tgz", + "integrity": "sha1-E3kY1teCg/ffemt8WmPhQOaUJeY=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "concat-stream": { + "version": "1.6.2", + "resolved": "https://registry.npmjs.org/concat-stream/-/concat-stream-1.6.2.tgz", + "integrity": "sha512-27HBghJxjiZtIk3Ycvn/4kbJk/1uZuJFfuPEns6LaEvpvG1f0hTea8lilrouyo9mVc2GWdcEZ8OLoGmSADlrCw==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "inherits": "^2.0.3", + "readable-stream": "^2.2.2", + "typedarray": "^0.0.6" + } + }, + "concat-with-sourcemaps": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/concat-with-sourcemaps/-/concat-with-sourcemaps-1.1.0.tgz", + "integrity": "sha512-4gEjHJFT9e+2W/77h/DS5SGUgwDaOwprX8L/gl5+3ixnzkVJJsZWDSelmN3Oilw3LNDZjZV0yqH1hLG3k6nghg==", + "dev": true, + "requires": { + "source-map": "^0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "console-browserify": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/console-browserify/-/console-browserify-1.2.0.tgz", + "integrity": "sha512-ZMkYO/LkF17QvCPqM0gxw8yUzigAOZOSWSHg91FH6orS7vcEj5dVZTidN2fQ14yBSdg97RqhSNwLUXInd52OTA==", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "constants-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/constants-browserify/-/constants-browserify-1.0.0.tgz", + "integrity": "sha1-wguW2MYXdIqvHBYCF2DNJ/y4y3U=", + "dev": true + }, + "convert-source-map": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/convert-source-map/-/convert-source-map-1.6.0.tgz", + "integrity": "sha512-eFu7XigvxdZ1ETfbgPBohgyQ/Z++C0eEhTor0qRwBw9unw+L0/6V8wkSuGgzdThkiS5lSpdptOQPD8Ak40a+7A==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.1" + } + }, + "copy-concurrently": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/copy-concurrently/-/copy-concurrently-1.0.5.tgz", + "integrity": "sha512-f2domd9fsVDFtaFcbaRZuYXwtdmnzqbADSwhSWYxYB/Q8zsdUUFMXVRwXGDMWmbEzAn1kdRrtI1T/KTFOL4X2A==", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "fs-write-stream-atomic": "^1.0.8", + "iferr": "^0.1.5", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.0" + } + }, + "copy-descriptor": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/copy-descriptor/-/copy-descriptor-0.1.1.tgz", + "integrity": "sha1-Z29us8OZl8LuGsOpJP1hJHSPV40=", + "dev": true + }, + "copy-props": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/copy-props/-/copy-props-2.0.4.tgz", + "integrity": "sha512-7cjuUME+p+S3HZlbllgsn2CDwS+5eCCX16qBgNC4jgSTf49qR1VKy/Zhl400m0IQXl/bPGEVqncgUUMjrr4s8A==", + "dev": true, + "requires": { + "each-props": "^1.3.0", + "is-plain-object": "^2.0.1" + } + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true + }, + "create-ecdh": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/create-ecdh/-/create-ecdh-4.0.3.tgz", + "integrity": "sha512-GbEHQPMOswGpKXM9kCWVrremUcBmjteUaQ01T9rkKCPDXfUHX0IoP9LpHYo2NPFampa4e+/pFDc3jQdxrxQLaw==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "elliptic": "^6.0.0" + } + }, + "create-hash": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/create-hash/-/create-hash-1.2.0.tgz", + "integrity": "sha512-z00bCGNHDG8mHAkP7CtT1qVu+bFQUPjYq/4Iv3C3kWjTFV10zIjfSoeqXo9Asws8gwSHDGj/hl2u4OGIjapeCg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.1", + "inherits": "^2.0.1", + "md5.js": "^1.3.4", + "ripemd160": "^2.0.1", + "sha.js": "^2.4.0" + } + }, + "create-hmac": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/create-hmac/-/create-hmac-1.1.7.tgz", + "integrity": "sha512-MJG9liiZ+ogc4TzUwuvbER1JRdgvUFSB5+VR/g5h82fGaIRWMWddtKBHi7/sVhfjQZ6SehlyhvQYrcYkaUIpLg==", + "dev": true, + "requires": { + "cipher-base": "^1.0.3", + "create-hash": "^1.1.0", + "inherits": "^2.0.1", + "ripemd160": "^2.0.0", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "cross-spawn": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/cross-spawn/-/cross-spawn-3.0.1.tgz", + "integrity": "sha1-ElYDfsufDF9549bvE14wdwGEuYI=", + "dev": true, + "requires": { + "lru-cache": "^4.0.1", + "which": "^1.2.9" + } + }, + "crypto-browserify": { + "version": "3.12.0", + "resolved": "https://registry.npmjs.org/crypto-browserify/-/crypto-browserify-3.12.0.tgz", + "integrity": "sha512-fz4spIh+znjO2VjL+IdhEpRJ3YN6sMzITSBijk6FK2UvTqruSQW+/cCZTSNsMiZNvUeq0CqurF+dAbyiGOY6Wg==", + "dev": true, + "requires": { + "browserify-cipher": "^1.0.0", + "browserify-sign": "^4.0.0", + "create-ecdh": "^4.0.0", + "create-hash": "^1.1.0", + "create-hmac": "^1.1.0", + "diffie-hellman": "^5.0.0", + "inherits": "^2.0.1", + "pbkdf2": "^3.0.3", + "public-encrypt": "^4.0.0", + "randombytes": "^2.0.0", + "randomfill": "^1.0.3" + } + }, + "currently-unhandled": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/currently-unhandled/-/currently-unhandled-0.4.1.tgz", + "integrity": "sha1-mI3zP+qxke95mmE2nddsF635V+o=", + "dev": true, + "requires": { + "array-find-index": "^1.0.1" + } + }, + "cyclist": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/cyclist/-/cyclist-1.0.1.tgz", + "integrity": "sha1-WW6WmP0MgOEgOMK4LW6xs1tiJNk=", + "dev": true + }, + "d": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/d/-/d-1.0.0.tgz", + "integrity": "sha1-dUu1v+VUUdpppYuU1F9MWwRi1Y8=", + "dev": true, + "requires": { + "es5-ext": "^0.10.9" + } + }, + "dashdash": { + "version": "1.14.1", + "resolved": "https://registry.npmjs.org/dashdash/-/dashdash-1.14.1.tgz", + "integrity": "sha1-hTz6D3y+L+1d4gMmuN1YEDX24vA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "requires": { + "ms": "2.0.0" + } + }, + "decamelize": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/decamelize/-/decamelize-1.2.0.tgz", + "integrity": "sha1-9lNNFRSCabIDUue+4m9QH5oZEpA=", + "dev": true + }, + "decode-uri-component": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/decode-uri-component/-/decode-uri-component-0.2.0.tgz", + "integrity": "sha1-6zkTMzRYd1y4TNGh+uBiEGu4dUU=", + "dev": true + }, + "default-compare": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/default-compare/-/default-compare-1.0.0.tgz", + "integrity": "sha512-QWfXlM0EkAbqOCbD/6HjdwT19j7WCkMyiRhWilc4H9/5h/RzTF9gv5LYh1+CmDV5d1rki6KAWLtQale0xt20eQ==", + "dev": true, + "requires": { + "kind-of": "^5.0.2" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "default-resolution": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/default-resolution/-/default-resolution-2.0.0.tgz", + "integrity": "sha1-vLgrqnKtebQmp2cy8aga1t8m1oQ=", + "dev": true + }, + "define-properties": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/define-properties/-/define-properties-1.1.3.tgz", + "integrity": "sha512-3MqfYKj2lLzdMSf8ZIZE/V+Zuy+BgD6f164e8K2w7dgnpKArBDerGYpM46IYYcjnkdPNMjPk9A6VFB8+3SKlXQ==", + "dev": true, + "requires": { + "object-keys": "^1.0.12" + } + }, + "define-property": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-2.0.2.tgz", + "integrity": "sha512-jwK2UV4cnPpbcG7+VRARKTZPUWowwXA8bzH5NP6ud0oeAxyYPuGZUAC7hMugpCdz4BeSZl2Dl9k66CHJ/46ZYQ==", + "dev": true, + "requires": { + "is-descriptor": "^1.0.2", + "isobject": "^3.0.1" + }, + "dependencies": { + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "delayed-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delayed-stream/-/delayed-stream-1.0.0.tgz", + "integrity": "sha1-3zrhmayt+31ECqrgsp4icrJOxhk=", + "dev": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true + }, + "des.js": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/des.js/-/des.js-1.0.1.tgz", + "integrity": "sha512-Q0I4pfFrv2VPd34/vfLrFOoRmlYj3OV50i7fskps1jZWK1kApMWWT9G6RRUeYedLcBDIhnSDaUvJMb3AhUlaEA==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0" + } + }, + "detect-file": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/detect-file/-/detect-file-1.0.0.tgz", + "integrity": "sha1-8NZtA2cqglyxtzvbP+YjEMjlUrc=", + "dev": true + }, + "diffie-hellman": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/diffie-hellman/-/diffie-hellman-5.0.3.tgz", + "integrity": "sha512-kqag/Nl+f3GwyK25fhUMYj81BUOrZ9IuJsjIcDE5icNM9FJHAVm3VcUDxdLPoQtTuUylWm6ZIknYJwwaPxsUzg==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "miller-rabin": "^4.0.0", + "randombytes": "^2.0.0" + } + }, + "domain-browser": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/domain-browser/-/domain-browser-1.2.0.tgz", + "integrity": "sha512-jnjyiM6eRyZl2H+W8Q/zLMA481hzi0eszAaBUzIVnmYVDBbnLxVNnfu1HgEBvCbL+71FrxMl3E6lpKH7Ge3OXA==", + "dev": true + }, + "duplexify": { + "version": "3.6.1", + "resolved": "https://registry.npmjs.org/duplexify/-/duplexify-3.6.1.tgz", + "integrity": "sha512-vM58DwdnKmty+FSPzT14K9JXb90H+j5emaR4KYbr2KTIz00WHGbWOe5ghQTx233ZCLZtrGDALzKwcjEtSt35mA==", + "dev": true, + "requires": { + "end-of-stream": "^1.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.0.0", + "stream-shift": "^1.0.0" + } + }, + "each-props": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/each-props/-/each-props-1.3.2.tgz", + "integrity": "sha512-vV0Hem3zAGkJAyU7JSjixeU66rwdynTAa1vofCrSA5fEln+m67Az9CcnkVD776/fsN/UjIWmBDoNRS6t6G9RfA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.1", + "object.defaults": "^1.1.0" + } + }, + "ecc-jsbn": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/ecc-jsbn/-/ecc-jsbn-0.1.2.tgz", + "integrity": "sha1-OoOpBOVDUyh4dMVkt1SThoSamMk=", + "dev": true, + "requires": { + "jsbn": "~0.1.0", + "safer-buffer": "^2.1.0" + } + }, + "electron-to-chromium": { + "version": "1.3.137", + "resolved": "https://registry.npmjs.org/electron-to-chromium/-/electron-to-chromium-1.3.137.tgz", + "integrity": "sha512-kGi32g42a8vS/WnYE7ELJyejRT7hbr3UeOOu0WeuYuQ29gCpg9Lrf6RdcTQVXSt/v0bjCfnlb/EWOOsiKpTmkw==", + "dev": true + }, + "elliptic": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/elliptic/-/elliptic-6.5.2.tgz", + "integrity": "sha512-f4x70okzZbIQl/NSRLkI/+tteV/9WqL98zx+SQ69KbXxmVrmjwsNUPn/gYJJ0sHvEak24cZgHIPegRePAtA/xw==", + "dev": true, + "requires": { + "bn.js": "^4.4.0", + "brorand": "^1.0.1", + "hash.js": "^1.0.0", + "hmac-drbg": "^1.0.0", + "inherits": "^2.0.1", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.0" + } + }, + "emojis-list": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/emojis-list/-/emojis-list-2.1.0.tgz", + "integrity": "sha1-TapNnbAPmBmIDHn6RXrlsJof04k=", + "dev": true + }, + "end-of-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/end-of-stream/-/end-of-stream-1.4.1.tgz", + "integrity": "sha512-1MkrZNvWTKCaigbn+W15elq2BB/L22nqrSY5DKlo3X6+vclJm8Bb5djXJBmEX6fS3+zCh/F4VBK5Z2KxJt4s2Q==", + "dev": true, + "requires": { + "once": "^1.4.0" + } + }, + "enhanced-resolve": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/enhanced-resolve/-/enhanced-resolve-4.1.1.tgz", + "integrity": "sha512-98p2zE+rL7/g/DzMHMTF4zZlCgeVdJ7yr6xzEpJRYwFYrGi9ANdn5DnJURg6RpBkyk60XYDnWIv51VfIhfNGuA==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "memory-fs": "^0.5.0", + "tapable": "^1.0.0" + }, + "dependencies": { + "memory-fs": { + "version": "0.5.0", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.5.0.tgz", + "integrity": "sha512-jA0rdU5KoQMC0e6ppoNRtpp6vjFq6+NY7r8hywnC7V+1Xj/MtHwGIbB1QaK/dunyjWteJzmkpd7ooeWg10T7GA==", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + } + } + }, + "errno": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/errno/-/errno-0.1.7.tgz", + "integrity": "sha512-MfrRBDWzIWifgq6tJj60gkAwtLNb6sQPlcFrSOflcP1aFmmruKQ2wRnze/8V6kgyz7H3FF8Npzv78mZ7XLLflg==", + "dev": true, + "requires": { + "prr": "~1.0.1" + } + }, + "error-ex": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/error-ex/-/error-ex-1.3.2.tgz", + "integrity": "sha512-7dFHNmqeFSEt2ZBsCriorKnn3Z2pj+fd9kmI6QoWw4//DL+icEBfc0U7qJCisqrTsKTjw4fNFy2pW9OqStD84g==", + "dev": true, + "requires": { + "is-arrayish": "^0.2.1" + } + }, + "es5-ext": { + "version": "0.10.50", + "resolved": "https://registry.npmjs.org/es5-ext/-/es5-ext-0.10.50.tgz", + "integrity": "sha512-KMzZTPBkeQV/JcSQhI5/z6d9VWJ3EnQ194USTUwIYZ2ZbpN8+SGXQKt1h68EX44+qt+Fzr8DO17vnxrw7c3agw==", + "dev": true, + "requires": { + "es6-iterator": "~2.0.3", + "es6-symbol": "~3.1.1", + "next-tick": "^1.0.0" + } + }, + "es6-iterator": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/es6-iterator/-/es6-iterator-2.0.3.tgz", + "integrity": "sha1-p96IkUGgWpSwhUQDstCg+/qY87c=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.35", + "es6-symbol": "^3.1.1" + } + }, + "es6-symbol": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/es6-symbol/-/es6-symbol-3.1.1.tgz", + "integrity": "sha1-vwDvT9q2uhtG7Le2KbTH7VcVzHc=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "~0.10.14" + } + }, + "es6-weak-map": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/es6-weak-map/-/es6-weak-map-2.0.2.tgz", + "integrity": "sha1-XjqzIlH/0VOKH45f+hNXdy+S2W8=", + "dev": true, + "requires": { + "d": "1", + "es5-ext": "^0.10.14", + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "escape-string-regexp": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/escape-string-regexp/-/escape-string-regexp-1.0.5.tgz", + "integrity": "sha1-G2HAViGQqN/2rjuyzwIAyhMLhtQ=", + "dev": true + }, + "eslint-scope": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/eslint-scope/-/eslint-scope-4.0.3.tgz", + "integrity": "sha512-p7VutNr1O/QrxysMo3E45FjYDTeXBy0iTltPFNSqKAIfjDSXC+4dj+qfyuD8bfAXrW/y6lW3O76VaYNPKfpKrg==", + "dev": true, + "requires": { + "esrecurse": "^4.1.0", + "estraverse": "^4.1.1" + } + }, + "esrecurse": { + "version": "4.2.1", + "resolved": "https://registry.npmjs.org/esrecurse/-/esrecurse-4.2.1.tgz", + "integrity": "sha512-64RBB++fIOAXPw3P9cy89qfMlvZEXZkqqJkjqqXIvzP5ezRZjW+lPWjw35UX/3EhUPFYbg5ER4JYgDw4007/DQ==", + "dev": true, + "requires": { + "estraverse": "^4.1.0" + } + }, + "estraverse": { + "version": "4.3.0", + "resolved": "https://registry.npmjs.org/estraverse/-/estraverse-4.3.0.tgz", + "integrity": "sha512-39nnKffWz8xN1BU/2c79n9nB9HDzo0niYUqx6xyqUnyoAnQyyWpOTdZEeiCch8BBu515t4wp9ZmgVfVhn9EBpw==", + "dev": true + }, + "events": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/events/-/events-3.0.0.tgz", + "integrity": "sha512-Dc381HFWJzEOhQ+d8pkNon++bk9h6cdAoAj4iE6Q4y6xgTzySWXlKn05/TVNpjnfRqi/X0EpJEJohPjNI3zpVA==", + "dev": true + }, + "evp_bytestokey": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/evp_bytestokey/-/evp_bytestokey-1.0.3.tgz", + "integrity": "sha512-/f2Go4TognH/KvCISP7OUsHn85hT9nUkxxA9BEWxFn+Oj9o8ZNLm/40hdlgSLyuOimsrTKLUMEorQexp/aPQeA==", + "dev": true, + "requires": { + "md5.js": "^1.3.4", + "safe-buffer": "^5.1.1" + } + }, + "expand-brackets": { + "version": "2.1.4", + "resolved": "https://registry.npmjs.org/expand-brackets/-/expand-brackets-2.1.4.tgz", + "integrity": "sha1-t3c14xXOMPa27/D4OwQVGiJEliI=", + "dev": true, + "requires": { + "debug": "^2.3.3", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "posix-character-classes": "^0.1.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "expand-tilde": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/expand-tilde/-/expand-tilde-2.0.2.tgz", + "integrity": "sha1-l+gBqgUt8CRU3kawK/YhZCzchQI=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "extend": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend/-/extend-3.0.2.tgz", + "integrity": "sha512-fjquC59cD7CyW6urNXK0FBufkZcoiGG80wTuPujX590cB5Ttln20E2UB4S/WARVqhXffZl2LNgS+gQdPIIim/g==", + "dev": true + }, + "extend-shallow": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-3.0.2.tgz", + "integrity": "sha1-Jqcarwc7OfshJxcnRhMcJwQCjbg=", + "dev": true, + "requires": { + "assign-symbols": "^1.0.0", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "extglob": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/extglob/-/extglob-2.0.4.tgz", + "integrity": "sha512-Nmb6QXkELsuBr24CJSkilo6UHHgbekK5UiZgfE6UHD3Eb27YC6oD+bhcT+tJ6cl8dmsgdQxnWlcry8ksBIBLpw==", + "dev": true, + "requires": { + "array-unique": "^0.3.2", + "define-property": "^1.0.0", + "expand-brackets": "^2.1.4", + "extend-shallow": "^2.0.1", + "fragment-cache": "^0.2.1", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "extsprintf": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/extsprintf/-/extsprintf-1.3.0.tgz", + "integrity": "sha1-lpGEQOMEGnpBT4xS48V06zw+HgU=", + "dev": true + }, + "fancy-log": { + "version": "1.3.3", + "resolved": "https://registry.npmjs.org/fancy-log/-/fancy-log-1.3.3.tgz", + "integrity": "sha512-k9oEhlyc0FrVh25qYuSELjr8oxsCoc4/LEZfg2iJJrfEk/tZL9bCoJE47gqAvI2m/AUjluCS4+3I0eTx8n3AEw==", + "dev": true, + "requires": { + "ansi-gray": "^0.1.1", + "color-support": "^1.1.3", + "parse-node-version": "^1.0.0", + "time-stamp": "^1.0.0" + } + }, + "fast-deep-equal": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/fast-deep-equal/-/fast-deep-equal-2.0.1.tgz", + "integrity": "sha1-ewUhjd+WZ79/Nwv3/bLLFf3Qqkk=", + "dev": true + }, + "fast-json-stable-stringify": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/fast-json-stable-stringify/-/fast-json-stable-stringify-2.0.0.tgz", + "integrity": "sha1-1RQsDK7msRifh9OnYREGT4bIu/I=", + "dev": true + }, + "figgy-pudding": { + "version": "3.5.1", + "resolved": "https://registry.npmjs.org/figgy-pudding/-/figgy-pudding-3.5.1.tgz", + "integrity": "sha512-vNKxJHTEKNThjfrdJwHc7brvM6eVevuO5nTj6ez8ZQ1qbXTvGthucRF7S4vf2cr71QVnT70V34v0S1DyQsti0w==", + "dev": true + }, + "fill-range": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/fill-range/-/fill-range-4.0.0.tgz", + "integrity": "sha1-1USBHUKPmOsGpj3EAtJAPDKMOPc=", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-number": "^3.0.0", + "repeat-string": "^1.6.1", + "to-regex-range": "^2.1.0" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "find-cache-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/find-cache-dir/-/find-cache-dir-2.1.0.tgz", + "integrity": "sha512-Tq6PixE0w/VMFfCgbONnkiQIVol/JJL7nRMi20fqzA4NRs9AfeqMGeRdPi3wIhYkxjeBaWh2rxwapn5Tu3IqOQ==", + "dev": true, + "requires": { + "commondir": "^1.0.1", + "make-dir": "^2.0.0", + "pkg-dir": "^3.0.0" + } + }, + "find-up": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-1.1.2.tgz", + "integrity": "sha1-ay6YIrGizgpgq2TWEOzK1TyyTQ8=", + "dev": true, + "requires": { + "path-exists": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "findup-sync": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-3.0.0.tgz", + "integrity": "sha512-YbffarhcicEhOrm4CtrwdKBdCuz576RLdhJDsIfvNtxUuhdRet1qZcsMjqbePtAseKdAnDyM/IyXbu7PRPRLYg==", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^4.0.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "fined": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/fined/-/fined-1.2.0.tgz", + "integrity": "sha512-ZYDqPLGxDkDhDZBjZBb+oD1+j0rA4E0pXY50eplAAOPg2N/gUBSSk5IM1/QhPfyVo19lJ+CvXpqfvk+b2p/8Ng==", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "is-plain-object": "^2.0.3", + "object.defaults": "^1.1.0", + "object.pick": "^1.2.0", + "parse-filepath": "^1.0.1" + } + }, + "flagged-respawn": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/flagged-respawn/-/flagged-respawn-1.0.1.tgz", + "integrity": "sha512-lNaHNVymajmk0OJMBn8fVUAU1BtDeKIqKoVhk4xAALB57aALg6b4W0MfJ/cUE0g9YBXy5XhSlPIpYIJ7HaY/3Q==", + "dev": true + }, + "flush-write-stream": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/flush-write-stream/-/flush-write-stream-1.0.3.tgz", + "integrity": "sha512-calZMC10u0FMUqoiunI2AiGIIUtUIvifNwkHhNupZH4cbNnW1Itkoh/Nf5HFYmDrwWPjrUxpkZT0KhuCq0jmGw==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.4" + } + }, + "for-in": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/for-in/-/for-in-1.0.2.tgz", + "integrity": "sha1-gQaNKVqBQuwKxybG4iAMMPttXoA=", + "dev": true + }, + "for-own": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/for-own/-/for-own-1.0.0.tgz", + "integrity": "sha1-xjMy9BXO3EsE2/5wz4NklMU8tEs=", + "dev": true, + "requires": { + "for-in": "^1.0.1" + } + }, + "forever-agent": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/forever-agent/-/forever-agent-0.6.1.tgz", + "integrity": "sha1-+8cfDEGt6zf5bFd60e1C2P2sypE=", + "dev": true + }, + "form-data": { + "version": "2.3.3", + "resolved": "https://registry.npmjs.org/form-data/-/form-data-2.3.3.tgz", + "integrity": "sha512-1lLKB2Mu3aGP1Q/2eCOx0fNbRMe7XdwktwOruhfqqd0rIJWwN4Dh+E3hrPSlDCXnSR7UtZ1N38rVXm+6+MEhJQ==", + "dev": true, + "requires": { + "asynckit": "^0.4.0", + "combined-stream": "^1.0.6", + "mime-types": "^2.1.12" + } + }, + "fragment-cache": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/fragment-cache/-/fragment-cache-0.2.1.tgz", + "integrity": "sha1-QpD60n8T6Jvn8zeZxrxaCr//DRk=", + "dev": true, + "requires": { + "map-cache": "^0.2.2" + } + }, + "from2": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/from2/-/from2-2.3.0.tgz", + "integrity": "sha1-i/tVAr3kpNNs/e6gB/zKIdfjgq8=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "readable-stream": "^2.0.0" + } + }, + "fs-mkdirp-stream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs-mkdirp-stream/-/fs-mkdirp-stream-1.0.0.tgz", + "integrity": "sha1-C3gV/DIBxqaeFNuYzgmMFpNSWes=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "through2": "^2.0.3" + } + }, + "fs-write-stream-atomic": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/fs-write-stream-atomic/-/fs-write-stream-atomic-1.0.10.tgz", + "integrity": "sha1-tH31NJPvkR33VzHnCp3tAYnbQMk=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "iferr": "^0.1.5", + "imurmurhash": "^0.1.4", + "readable-stream": "1 || 2" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true + }, + "fsevents": { + "version": "1.2.7", + "resolved": "https://registry.npmjs.org/fsevents/-/fsevents-1.2.7.tgz", + "integrity": "sha512-Pxm6sI2MeBD7RdD12RYsqaP0nMiwx8eZBXCa6z2L+mRHm2DYrOYwihmhjpkdjUHwQhslWQjRpEgNq4XvBmaAuw==", + "dev": true, + "optional": true, + "requires": { + "nan": "^2.9.2", + "node-pre-gyp": "^0.10.0" + }, + "dependencies": { + "abbrev": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/abbrev/-/abbrev-1.1.1.tgz", + "integrity": "sha512-nne9/IiQ/hzIhY6pdDnbBtz7DjPTKrY00P/zvPSm5pOFkl6xuGrGnXn/VtTNNfNtAfZ9/1RtehkszU9qcTii0Q==", + "dev": true, + "optional": true + }, + "ansi-regex": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-2.1.1.tgz", + "integrity": "sha1-w7M6te42DYbg5ijwRorn7yfWVN8=", + "dev": true + }, + "aproba": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/aproba/-/aproba-1.2.0.tgz", + "integrity": "sha512-Y9J6ZjXtoYh8RnXVCMOU/ttDmk1aBjunq9vO0ta5x85WDQiQfUF9sIPBITdbiiIVcBo03Hi3jMxigBtsddlXRw==", + "dev": true, + "optional": true + }, + "are-we-there-yet": { + "version": "1.1.5", + "resolved": "https://registry.npmjs.org/are-we-there-yet/-/are-we-there-yet-1.1.5.tgz", + "integrity": "sha512-5hYdAkZlcG8tOLujVDTgCT+uPX0VnpAH28gWsLfzpXYm7wP6mp5Q/gYyR7YQ0cKVJcXJnl3j2kpBan13PtQf6w==", + "dev": true, + "optional": true, + "requires": { + "delegates": "^1.0.0", + "readable-stream": "^2.0.6" + } + }, + "balanced-match": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/balanced-match/-/balanced-match-1.0.0.tgz", + "integrity": "sha1-ibTRmasr7kneFk6gK4nORi1xt2c=", + "dev": true + }, + "brace-expansion": { + "version": "1.1.11", + "resolved": "https://registry.npmjs.org/brace-expansion/-/brace-expansion-1.1.11.tgz", + "integrity": "sha512-iCuPHDFgrHX7H2vEI/5xpz07zSHB00TpugqhmYtVmMO6518mCuRMoOYFldEBl0g187ufozdaHgWKcYFb61qGiA==", + "dev": true, + "requires": { + "balanced-match": "^1.0.0", + "concat-map": "0.0.1" + } + }, + "chownr": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/chownr/-/chownr-1.1.1.tgz", + "integrity": "sha512-j38EvO5+LHX84jlo6h4UzmOwi0UgW61WRyPtJz4qaadK5eY3BTS5TY/S1Stc3Uk2lIM6TPevAlULiEJwie860g==", + "dev": true, + "optional": true + }, + "code-point-at": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/code-point-at/-/code-point-at-1.1.0.tgz", + "integrity": "sha1-DQcLTQQ6W+ozovGkDi7bPZpMz3c=", + "dev": true + }, + "concat-map": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/concat-map/-/concat-map-0.0.1.tgz", + "integrity": "sha1-2Klr13/Wjfd5OnMDajug1UBdR3s=", + "dev": true + }, + "console-control-strings": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/console-control-strings/-/console-control-strings-1.1.0.tgz", + "integrity": "sha1-PXz0Rk22RG6mRL9LOVB/mFEAjo4=", + "dev": true + }, + "core-util-is": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/core-util-is/-/core-util-is-1.0.2.tgz", + "integrity": "sha1-tf1UIgqivFq1eqtxQMlAdUUDwac=", + "dev": true, + "optional": true + }, + "debug": { + "version": "2.6.9", + "resolved": "https://registry.npmjs.org/debug/-/debug-2.6.9.tgz", + "integrity": "sha512-bC7ElrdJaJnPbAP+1EotYvqZsb3ecl5wi6Bfi6BJTUcNowp6cvspg0jXznRTKDjm/E7AdgFBVeAPVMNcKGsHMA==", + "dev": true, + "optional": true, + "requires": { + "ms": "2.0.0" + } + }, + "deep-extend": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/deep-extend/-/deep-extend-0.6.0.tgz", + "integrity": "sha512-LOHxIOaPYdHlJRtCQfDIVZtfw/ufM8+rVj649RIHzcm/vGwQRXFt6OPqIFWsm2XEMrNIEtWR64sY1LEKD2vAOA==", + "dev": true, + "optional": true + }, + "delegates": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/delegates/-/delegates-1.0.0.tgz", + "integrity": "sha1-hMbhWbgZBP3KWaDvRM2HDTElD5o=", + "dev": true, + "optional": true + }, + "detect-libc": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/detect-libc/-/detect-libc-1.0.3.tgz", + "integrity": "sha1-+hN8S9aY7fVc1c0CrFWfkaTEups=", + "dev": true, + "optional": true + }, + "fs-minipass": { + "version": "1.2.5", + "resolved": "https://registry.npmjs.org/fs-minipass/-/fs-minipass-1.2.5.tgz", + "integrity": "sha512-JhBl0skXjUPCFH7x6x61gQxrKyXsxB5gcgePLZCwfyCGGsTISMoIeObbrvVeP6Xmyaudw4TT43qV2Gz+iyd2oQ==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "fs.realpath": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/fs.realpath/-/fs.realpath-1.0.0.tgz", + "integrity": "sha1-FQStJSMVjKpA20onh8sBQRmU6k8=", + "dev": true, + "optional": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "optional": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "optional": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true, + "optional": true + }, + "iconv-lite": { + "version": "0.4.24", + "resolved": "https://registry.npmjs.org/iconv-lite/-/iconv-lite-0.4.24.tgz", + "integrity": "sha512-v3MXnZAcvnywkTUEZomIActle7RXXeedOR31wwl7VlyoXO4Qi9arvSenNQWne1TcRwhCL1HwLI21bEqdpj8/rA==", + "dev": true, + "optional": true, + "requires": { + "safer-buffer": ">= 2.1.2 < 3" + } + }, + "ignore-walk": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/ignore-walk/-/ignore-walk-3.0.1.tgz", + "integrity": "sha512-DTVlMx3IYPe0/JJcYP7Gxg7ttZZu3IInhuEhbchuqneY9wWe5Ojy2mXLBaQFUQmo0AW2r3qG7m1mg86js+gnlQ==", + "dev": true, + "optional": true, + "requires": { + "minimatch": "^3.0.4" + } + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "optional": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true, + "optional": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true, + "optional": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + }, + "minipass": { + "version": "2.3.5", + "resolved": "https://registry.npmjs.org/minipass/-/minipass-2.3.5.tgz", + "integrity": "sha512-Gi1W4k059gyRbyVUZQ4mEqLm0YIUiGYfvxhF6SIlk3ui1WVxMTGfGdQ2SInh3PDrRTVvPKgULkpJtT4RH10+VA==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.2", + "yallist": "^3.0.0" + } + }, + "minizlib": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/minizlib/-/minizlib-1.2.1.tgz", + "integrity": "sha512-7+4oTUOWKg7AuL3vloEWekXY2/D20cevzsrNT2kGWm+39J9hGTCBv8VI5Pm5lXZ/o3/mdR4f8rflAPhnQb8mPA==", + "dev": true, + "optional": true, + "requires": { + "minipass": "^2.2.1" + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true, + "optional": true + }, + "needle": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/needle/-/needle-2.2.4.tgz", + "integrity": "sha512-HyoqEb4wr/rsoaIDfTH2aVL9nWtQqba2/HvMv+++m8u0dz808MaagKILxtfeSN7QU7nvbQ79zk3vYOJp9zsNEA==", + "dev": true, + "optional": true, + "requires": { + "debug": "^2.1.2", + "iconv-lite": "^0.4.4", + "sax": "^1.2.4" + } + }, + "node-pre-gyp": { + "version": "0.10.3", + "resolved": "https://registry.npmjs.org/node-pre-gyp/-/node-pre-gyp-0.10.3.tgz", + "integrity": "sha512-d1xFs+C/IPS8Id0qPTZ4bUT8wWryfR/OzzAFxweG+uLN85oPzyo2Iw6bVlLQ/JOdgNonXLCoRyqDzDWq4iw72A==", + "dev": true, + "optional": true, + "requires": { + "detect-libc": "^1.0.2", + "mkdirp": "^0.5.1", + "needle": "^2.2.1", + "nopt": "^4.0.1", + "npm-packlist": "^1.1.6", + "npmlog": "^4.0.2", + "rc": "^1.2.7", + "rimraf": "^2.6.1", + "semver": "^5.3.0", + "tar": "^4" + } + }, + "nopt": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-4.0.1.tgz", + "integrity": "sha1-0NRoWv1UFRk8jHUFYC0NF81kR00=", + "dev": true, + "optional": true, + "requires": { + "abbrev": "1", + "osenv": "^0.1.4" + } + }, + "npm-bundled": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/npm-bundled/-/npm-bundled-1.0.5.tgz", + "integrity": "sha512-m/e6jgWu8/v5niCUKQi9qQl8QdeEduFA96xHDDzFGqly0OOjI7c+60KM/2sppfnUU9JJagf+zs+yGhqSOFj71g==", + "dev": true, + "optional": true + }, + "npm-packlist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/npm-packlist/-/npm-packlist-1.2.0.tgz", + "integrity": "sha512-7Mni4Z8Xkx0/oegoqlcao/JpPCPEMtUvsmB0q7mgvlMinykJLSRTYuFqoQLYgGY8biuxIeiHO+QNJKbCfljewQ==", + "dev": true, + "optional": true, + "requires": { + "ignore-walk": "^3.0.1", + "npm-bundled": "^1.0.1" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "optional": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true, + "optional": true + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true, + "optional": true + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true, + "optional": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "optional": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true, + "optional": true + }, + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true, + "optional": true + }, + "rc": { + "version": "1.2.8", + "resolved": "https://registry.npmjs.org/rc/-/rc-1.2.8.tgz", + "integrity": "sha512-y3bGgqKj3QBdxLbLkomlohkvsA8gdAiUQlSBJnBhfn+BPxg4bc62d8TcBW15wavDfgexCgccckhcZvywyQYPOw==", + "dev": true, + "optional": true, + "requires": { + "deep-extend": "^0.6.0", + "ini": "~1.3.0", + "minimist": "^1.2.0", + "strip-json-comments": "~2.0.1" + }, + "dependencies": { + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true, + "optional": true + } + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "optional": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + } + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "optional": true, + "requires": { + "glob": "^7.1.3" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true, + "optional": true + }, + "sax": { + "version": "1.2.4", + "resolved": "https://registry.npmjs.org/sax/-/sax-1.2.4.tgz", + "integrity": "sha512-NqVDv9TpANUjFm0N8uM5GxL36UgKi9/atZw+x7YFnQ8ckwFGKrl4xX4yWtrey3UJm5nP1kUbnYgLopqWNSRhWw==", + "dev": true, + "optional": true + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true, + "optional": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true, + "optional": true + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true, + "optional": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "optional": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-json-comments": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/strip-json-comments/-/strip-json-comments-2.0.1.tgz", + "integrity": "sha1-PFMZQukIwml8DsNEhYwobHygpgo=", + "dev": true, + "optional": true + }, + "tar": { + "version": "4.4.8", + "resolved": "https://registry.npmjs.org/tar/-/tar-4.4.8.tgz", + "integrity": "sha512-LzHF64s5chPQQS0IYBn9IN5h3i98c12bo4NCO7e0sGM2llXQ3p2FGC5sdENN4cTW48O915Sh+x+EXx7XW96xYQ==", + "dev": true, + "optional": true, + "requires": { + "chownr": "^1.1.1", + "fs-minipass": "^1.2.5", + "minipass": "^2.3.4", + "minizlib": "^1.1.1", + "mkdirp": "^0.5.0", + "safe-buffer": "^5.1.2", + "yallist": "^3.0.2" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true, + "optional": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "optional": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "yallist": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-3.0.3.tgz", + "integrity": "sha512-S+Zk8DEWE6oKpV+vI3qWkaK+jSbIK86pCwe2IF/xwIpQ8jEuxpw9NyaGjmp9+BoJv5FV2piqCDcoCtStppiq2A==", + "dev": true + } + } + }, + "fstream": { + "version": "1.0.12", + "resolved": "https://registry.npmjs.org/fstream/-/fstream-1.0.12.tgz", + "integrity": "sha512-WvJ193OHa0GHPEL+AycEJgxvBEwyfRkN1vhjca23OaPVMCaLCXTd5qAu82AjTcgP1UJmytkOKb63Ypde7raDIg==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "inherits": "~2.0.0", + "mkdirp": ">=0.5 0", + "rimraf": "2" + } + }, + "function-bind": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/function-bind/-/function-bind-1.1.1.tgz", + "integrity": "sha512-yIovAzMX49sF8Yl58fSCWJ5svSLuaibPxXQJFLmBObTuCr0Mf1KiPopGM9NiFjiYBCbfaa2Fh6breQ6ANVTI0A==", + "dev": true + }, + "gauge": { + "version": "2.7.4", + "resolved": "https://registry.npmjs.org/gauge/-/gauge-2.7.4.tgz", + "integrity": "sha1-LANAXHU4w51+s3sxcCLjJfsBi/c=", + "dev": true, + "requires": { + "aproba": "^1.0.3", + "console-control-strings": "^1.0.0", + "has-unicode": "^2.0.0", + "object-assign": "^4.1.0", + "signal-exit": "^3.0.0", + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1", + "wide-align": "^1.1.0" + } + }, + "gaze": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/gaze/-/gaze-1.1.3.tgz", + "integrity": "sha512-BRdNm8hbWzFzWHERTrejLqwHDfS4GibPoq5wjTPIoJHoBtKGPg3xAFfxmM+9ztbXelxcf2hwQcaz1PtmFeue8g==", + "dev": true, + "requires": { + "globule": "^1.0.0" + } + }, + "get-caller-file": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/get-caller-file/-/get-caller-file-1.0.3.tgz", + "integrity": "sha512-3t6rVToeoZfYSGd8YoLFR2DJkiQrIiUrGcjvFX2mDw3bn6k2OtwHN0TNCLbBO+w8qTvimhDkv+LSscbJY1vE6w==", + "dev": true + }, + "get-stdin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/get-stdin/-/get-stdin-4.0.1.tgz", + "integrity": "sha1-uWjGsKBDhDJJAui/Gl3zJXmkUP4=", + "dev": true + }, + "get-value": { + "version": "2.0.6", + "resolved": "https://registry.npmjs.org/get-value/-/get-value-2.0.6.tgz", + "integrity": "sha1-3BXKHGcjh8p2vTesCjlbogQqLCg=", + "dev": true + }, + "getpass": { + "version": "0.1.7", + "resolved": "https://registry.npmjs.org/getpass/-/getpass-0.1.7.tgz", + "integrity": "sha1-Xv+OPmhNVprkyysSgmBOi6YhSfo=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0" + } + }, + "glob": { + "version": "7.1.3", + "resolved": "https://registry.npmjs.org/glob/-/glob-7.1.3.tgz", + "integrity": "sha512-vcfuiIxogLV4DlGBHIUOwI0IbrJ8HWPc4MU7HzviGeNho/UJDfi6B5p3sHeWIQ0KGIU0Jpxi5ZHxemQfLkkAwQ==", + "dev": true, + "requires": { + "fs.realpath": "^1.0.0", + "inflight": "^1.0.4", + "inherits": "2", + "minimatch": "^3.0.4", + "once": "^1.3.0", + "path-is-absolute": "^1.0.0" + } + }, + "glob-parent": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/glob-parent/-/glob-parent-3.1.0.tgz", + "integrity": "sha1-nmr2KZ2NO9K9QEMIMr0RPfkGxa4=", + "dev": true, + "requires": { + "is-glob": "^3.1.0", + "path-dirname": "^1.0.0" + }, + "dependencies": { + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "glob-stream": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/glob-stream/-/glob-stream-6.1.0.tgz", + "integrity": "sha1-cEXJlBOz65SIjYOrRtC0BMx73eQ=", + "dev": true, + "requires": { + "extend": "^3.0.0", + "glob": "^7.1.1", + "glob-parent": "^3.1.0", + "is-negated-glob": "^1.0.0", + "ordered-read-streams": "^1.0.0", + "pumpify": "^1.3.5", + "readable-stream": "^2.1.5", + "remove-trailing-separator": "^1.0.1", + "to-absolute-glob": "^2.0.0", + "unique-stream": "^2.0.2" + } + }, + "glob-watcher": { + "version": "5.0.3", + "resolved": "https://registry.npmjs.org/glob-watcher/-/glob-watcher-5.0.3.tgz", + "integrity": "sha512-8tWsULNEPHKQ2MR4zXuzSmqbdyV5PtwwCaWSGQ1WwHsJ07ilNeN1JB8ntxhckbnpSHaf9dXFUHzIWvm1I13dsg==", + "dev": true, + "requires": { + "anymatch": "^2.0.0", + "async-done": "^1.2.0", + "chokidar": "^2.0.0", + "is-negated-glob": "^1.0.0", + "just-debounce": "^1.0.0", + "object.defaults": "^1.1.0" + } + }, + "global-modules": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/global-modules/-/global-modules-1.0.0.tgz", + "integrity": "sha512-sKzpEkf11GpOFuw0Zzjzmt4B4UZwjOcG757PPvrfhxcLFbq0wpsgpOqxpxtxFiCG4DtG93M6XRVbF2oGdev7bg==", + "dev": true, + "requires": { + "global-prefix": "^1.0.1", + "is-windows": "^1.0.1", + "resolve-dir": "^1.0.0" + } + }, + "global-prefix": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/global-prefix/-/global-prefix-1.0.2.tgz", + "integrity": "sha1-2/dDxsFJklk8ZVVoy2btMsASLr4=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.2", + "homedir-polyfill": "^1.0.1", + "ini": "^1.3.4", + "is-windows": "^1.0.1", + "which": "^1.2.14" + } + }, + "globule": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/globule/-/globule-1.3.1.tgz", + "integrity": "sha512-OVyWOHgw29yosRHCHo7NncwR1hW5ew0W/UrvtwvjefVJeQ26q4/8r8FmPsSF1hJ93IgWkyv16pCTz6WblMzm/g==", + "dev": true, + "requires": { + "glob": "~7.1.1", + "lodash": "~4.17.12", + "minimatch": "~3.0.2" + } + }, + "glogg": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/glogg/-/glogg-1.0.2.tgz", + "integrity": "sha512-5mwUoSuBk44Y4EshyiqcH95ZntbDdTQqA3QYSrxmzj28Ai0vXBGMH1ApSANH14j2sIRtqCEyg6PfsuP7ElOEDA==", + "dev": true, + "requires": { + "sparkles": "^1.0.0" + } + }, + "graceful-fs": { + "version": "4.1.15", + "resolved": "https://registry.npmjs.org/graceful-fs/-/graceful-fs-4.1.15.tgz", + "integrity": "sha512-6uHUhOPEBgQ24HM+r6b/QwWfZq+yiFcipKFrOFiBEnWdy5sdzYoi+pJeQaPI5qOLRFqWmAXUPQNsielzdLoecA==", + "dev": true + }, + "gulp": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp/-/gulp-4.0.2.tgz", + "integrity": "sha512-dvEs27SCZt2ibF29xYgmnwwCYZxdxhQ/+LFWlbAW8y7jt68L/65402Lz3+CKy0Ov4rOs+NERmDq7YlZaDqUIfA==", + "dev": true, + "requires": { + "glob-watcher": "^5.0.3", + "gulp-cli": "^2.2.0", + "undertaker": "^1.2.1", + "vinyl-fs": "^3.0.0" + }, + "dependencies": { + "gulp-cli": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/gulp-cli/-/gulp-cli-2.2.0.tgz", + "integrity": "sha512-rGs3bVYHdyJpLqR0TUBnlcZ1O5O++Zs4bA0ajm+zr3WFCfiSLjGwoCBqFs18wzN+ZxahT9DkOK5nDf26iDsWjA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "archy": "^1.0.0", + "array-sort": "^1.0.0", + "color-support": "^1.1.3", + "concat-stream": "^1.6.0", + "copy-props": "^2.0.1", + "fancy-log": "^1.3.2", + "gulplog": "^1.0.0", + "interpret": "^1.1.0", + "isobject": "^3.0.1", + "liftoff": "^3.1.0", + "matchdep": "^2.0.0", + "mute-stdout": "^1.0.0", + "pretty-hrtime": "^1.0.0", + "replace-homedir": "^1.0.0", + "semver-greatest-satisfied-range": "^1.1.0", + "v8flags": "^3.0.1", + "yargs": "^7.1.0" + } + } + } + }, + "gulp-autoprefixer": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/gulp-autoprefixer/-/gulp-autoprefixer-6.1.0.tgz", + "integrity": "sha512-Ti/BUFe+ekhbDJfspZIMiOsOvw51KhI9EncsDfK7NaxjqRm+v4xS9v99kPxEoiDavpWqQWvG8Y6xT1mMlB3aXA==", + "dev": true, + "requires": { + "autoprefixer": "^9.5.1", + "fancy-log": "^1.3.2", + "plugin-error": "^1.0.1", + "postcss": "^7.0.2", + "through2": "^3.0.1", + "vinyl-sourcemaps-apply": "^0.2.1" + }, + "dependencies": { + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "requires": { + "readable-stream": "2 || 3" + } + } + } + }, + "gulp-clean-css": { + "version": "4.2.0", + "resolved": "https://registry.npmjs.org/gulp-clean-css/-/gulp-clean-css-4.2.0.tgz", + "integrity": "sha512-r4zQsSOAK2UYUL/ipkAVCTRg/2CLZ2A+oPVORopBximRksJ6qy3EX1KGrIWT4ZrHxz3Hlobb1yyJtqiut7DNjA==", + "dev": true, + "requires": { + "clean-css": "4.2.1", + "plugin-error": "1.0.1", + "through2": "3.0.1", + "vinyl-sourcemaps-apply": "0.2.1" + }, + "dependencies": { + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "requires": { + "readable-stream": "2 || 3" + } + } + } + }, + "gulp-concat": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/gulp-concat/-/gulp-concat-2.6.1.tgz", + "integrity": "sha1-Yz0WyV2IUEYorQJmVmPO5aR5M1M=", + "dev": true, + "requires": { + "concat-with-sourcemaps": "^1.0.0", + "through2": "^2.0.0", + "vinyl": "^2.0.0" + } + }, + "gulp-sass": { + "version": "4.0.2", + "resolved": "https://registry.npmjs.org/gulp-sass/-/gulp-sass-4.0.2.tgz", + "integrity": "sha512-q8psj4+aDrblJMMtRxihNBdovfzGrXJp1l4JU0Sz4b/Mhsi2DPrKFYCGDwjIWRENs04ELVHxdOJQ7Vs98OFohg==", + "dev": true, + "requires": { + "chalk": "^2.3.0", + "lodash.clonedeep": "^4.3.2", + "node-sass": "^4.8.3", + "plugin-error": "^1.0.1", + "replace-ext": "^1.0.0", + "strip-ansi": "^4.0.0", + "through2": "^2.0.0", + "vinyl-sourcemaps-apply": "^0.2.0" + }, + "dependencies": { + "ansi-regex": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/ansi-regex/-/ansi-regex-3.0.0.tgz", + "integrity": "sha1-7QMXwyIGT3lGbAKWa922Bas32Zg=", + "dev": true + }, + "strip-ansi": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-4.0.0.tgz", + "integrity": "sha1-qEeQIusaw2iocTibY1JixQXuNo8=", + "dev": true, + "requires": { + "ansi-regex": "^3.0.0" + } + } + } + }, + "gulp-typescript": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/gulp-typescript/-/gulp-typescript-5.0.1.tgz", + "integrity": "sha512-YuMMlylyJtUSHG1/wuSVTrZp60k1dMEFKYOvDf7OvbAJWrDtxxD4oZon4ancdWwzjj30ztiidhe4VXJniF0pIQ==", + "dev": true, + "requires": { + "ansi-colors": "^3.0.5", + "plugin-error": "^1.0.1", + "source-map": "^0.7.3", + "through2": "^3.0.0", + "vinyl": "^2.1.0", + "vinyl-fs": "^3.0.3" + }, + "dependencies": { + "ansi-colors": { + "version": "3.2.4", + "resolved": "https://registry.npmjs.org/ansi-colors/-/ansi-colors-3.2.4.tgz", + "integrity": "sha512-hHUXGagefjN2iRrID63xckIvotOXOojhQKWIPUZ4mNUZ9nLZW+7FMNoE1lOkEhNWYsx/7ysGIuJYCiMAA9FnrA==", + "dev": true + }, + "source-map": { + "version": "0.7.3", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.7.3.tgz", + "integrity": "sha512-CkCj6giN3S+n9qrYiBTX5gystlENnRW5jZeNLHpe6aue+SrHcG5VYwujhW9s4dY31mEGsxBDrHR6oI69fTXsaQ==", + "dev": true + }, + "through2": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/through2/-/through2-3.0.1.tgz", + "integrity": "sha512-M96dvTalPT3YbYLaKaCuwu+j06D/8Jfib0o/PxbVt6Amhv3dUAtW6rTV1jPgJSBG83I/e04Y6xkVdVhSRhi0ww==", + "dev": true, + "requires": { + "readable-stream": "2 || 3" + } + } + } + }, + "gulplog": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/gulplog/-/gulplog-1.0.0.tgz", + "integrity": "sha1-4oxNRdBey77YGDY86PnFkmIp/+U=", + "dev": true, + "requires": { + "glogg": "^1.0.0" + } + }, + "har-schema": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/har-schema/-/har-schema-2.0.0.tgz", + "integrity": "sha1-qUwiJOvKwEeCoNkDVSHyRzW37JI=", + "dev": true + }, + "har-validator": { + "version": "5.1.3", + "resolved": "https://registry.npmjs.org/har-validator/-/har-validator-5.1.3.tgz", + "integrity": "sha512-sNvOCzEQNr/qrvJgc3UG/kD4QtlHycrzwS+6mfTrrSq97BvaYcPZZI1ZSqGSPR73Cxn4LKTD4PttRwfU7jWq5g==", + "dev": true, + "requires": { + "ajv": "^6.5.5", + "har-schema": "^2.0.0" + } + }, + "has-ansi": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/has-ansi/-/has-ansi-2.0.0.tgz", + "integrity": "sha1-NPUEnOHs3ysGSa8+8k5F7TVBbZE=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "has-flag": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/has-flag/-/has-flag-3.0.0.tgz", + "integrity": "sha1-tdRU3CGZriJWmfNGfloH87lVuv0=", + "dev": true + }, + "has-symbols": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-symbols/-/has-symbols-1.0.0.tgz", + "integrity": "sha1-uhqPGvKg/DllD1yFA2dwQSIGO0Q=", + "dev": true + }, + "has-unicode": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/has-unicode/-/has-unicode-2.0.1.tgz", + "integrity": "sha1-4Ob+aijPUROIVeCG0Wkedx3iqLk=", + "dev": true + }, + "has-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-1.0.0.tgz", + "integrity": "sha1-GLKB2lhbHFxR3vJMkw7SmgvmsXc=", + "dev": true, + "requires": { + "get-value": "^2.0.6", + "has-values": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "has-values": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-1.0.0.tgz", + "integrity": "sha1-lbC2P+whRmGab+V/51Yo1aOe/k8=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "kind-of": "^4.0.0" + }, + "dependencies": { + "kind-of": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-4.0.0.tgz", + "integrity": "sha1-IIE989cSkosgc3hpGkUGb65y3Vc=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "hash-base": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/hash-base/-/hash-base-3.0.4.tgz", + "integrity": "sha1-X8hoaEfs1zSZQDMZprCj8/auSRg=", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "hash.js": { + "version": "1.1.7", + "resolved": "https://registry.npmjs.org/hash.js/-/hash.js-1.1.7.tgz", + "integrity": "sha512-taOaskGt4z4SOANNseOviYDvjEJinIkRgmp7LbKP2YTTmVxWBl87s/uzK9r+44BclBSp2X7K1hqeNfz9JbBeXA==", + "dev": true, + "requires": { + "inherits": "^2.0.3", + "minimalistic-assert": "^1.0.1" + } + }, + "hmac-drbg": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/hmac-drbg/-/hmac-drbg-1.0.1.tgz", + "integrity": "sha1-0nRXAQJabHdabFRXk+1QL8DGSaE=", + "dev": true, + "requires": { + "hash.js": "^1.0.3", + "minimalistic-assert": "^1.0.0", + "minimalistic-crypto-utils": "^1.0.1" + } + }, + "homedir-polyfill": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/homedir-polyfill/-/homedir-polyfill-1.0.3.tgz", + "integrity": "sha512-eSmmWE5bZTK2Nou4g0AI3zZ9rswp7GRKoKXS1BLUkvPviOqs4YTN1djQIqrXy9k5gEtdLPy86JjRwsNM9tnDcA==", + "dev": true, + "requires": { + "parse-passwd": "^1.0.0" + } + }, + "hosted-git-info": { + "version": "2.7.1", + "resolved": "https://registry.npmjs.org/hosted-git-info/-/hosted-git-info-2.7.1.tgz", + "integrity": "sha512-7T/BxH19zbcCTa8XkMlbK5lTo1WtgkFi3GvdWEyNuc4Vex7/9Dqbnpsf4JMydcfj9HCg4zUWFTL3Za6lapg5/w==", + "dev": true + }, + "http-signature": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/http-signature/-/http-signature-1.2.0.tgz", + "integrity": "sha1-muzZJRFHcvPZW2WmCruPfBj7rOE=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "jsprim": "^1.2.2", + "sshpk": "^1.7.0" + } + }, + "https-browserify": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/https-browserify/-/https-browserify-1.0.0.tgz", + "integrity": "sha1-7AbBDgo0wPL68Zn3/X/Hj//QPHM=", + "dev": true + }, + "ieee754": { + "version": "1.1.13", + "resolved": "https://registry.npmjs.org/ieee754/-/ieee754-1.1.13.tgz", + "integrity": "sha512-4vf7I2LYV/HaWerSo3XmlMkp5eZ83i+/CDluXi/IGTs/O1sejBNhTtnxzmRZfvOUqj7lZjqHkeTvpgSFDlWZTg==", + "dev": true + }, + "iferr": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/iferr/-/iferr-0.1.5.tgz", + "integrity": "sha1-xg7taebY/bazEEofy8ocGS3FtQE=", + "dev": true + }, + "imurmurhash": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/imurmurhash/-/imurmurhash-0.1.4.tgz", + "integrity": "sha1-khi5srkoojixPcT7a21XbyMUU+o=", + "dev": true + }, + "in-publish": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/in-publish/-/in-publish-2.0.0.tgz", + "integrity": "sha1-4g/146KvwmkDILbcVSaCqcf631E=", + "dev": true + }, + "indent-string": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/indent-string/-/indent-string-2.1.0.tgz", + "integrity": "sha1-ji1INIdCEhtKghi3oTfppSBJ3IA=", + "dev": true, + "requires": { + "repeating": "^2.0.0" + } + }, + "infer-owner": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/infer-owner/-/infer-owner-1.0.4.tgz", + "integrity": "sha512-IClj+Xz94+d7irH5qRyfJonOdfTzuDaifE6ZPWfx0N0+/ATZCbuTPq2prFl526urkQd90WyUKIh1DfBQ2hMz9A==", + "dev": true + }, + "inflight": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/inflight/-/inflight-1.0.6.tgz", + "integrity": "sha1-Sb1jMdfQLQwJvJEKEHW6gWW1bfk=", + "dev": true, + "requires": { + "once": "^1.3.0", + "wrappy": "1" + } + }, + "inherits": { + "version": "2.0.3", + "resolved": "https://registry.npmjs.org/inherits/-/inherits-2.0.3.tgz", + "integrity": "sha1-Yzwsg+PaQqUC9SRmAiSA9CCCYd4=", + "dev": true + }, + "ini": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/ini/-/ini-1.3.5.tgz", + "integrity": "sha512-RZY5huIKCMRWDUqZlEi72f/lmXKMvuszcMBduliQ3nnWbx9X/ZBQO7DijMEYS9EhHBb2qacRUMtC7svLwe0lcw==", + "dev": true + }, + "interpret": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/interpret/-/interpret-1.2.0.tgz", + "integrity": "sha512-mT34yGKMNceBQUoVn7iCDKDntA7SC6gycMAWzGx1z/CMCTV7b2AAtXlo3nRyHZ1FelRkQbQjprHSYGwzLtkVbw==", + "dev": true + }, + "invert-kv": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/invert-kv/-/invert-kv-1.0.0.tgz", + "integrity": "sha1-EEqOSqym09jNFXqO+L+rLXo//bY=", + "dev": true + }, + "is-absolute": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-absolute/-/is-absolute-1.0.0.tgz", + "integrity": "sha512-dOWoqflvcydARa360Gvv18DZ/gRuHKi2NU/wU5X1ZFzdYfH29nkiNZsF3mp4OJ3H4yo9Mx8A/uAGNzpzPN3yBA==", + "dev": true, + "requires": { + "is-relative": "^1.0.0", + "is-windows": "^1.0.1" + } + }, + "is-accessor-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-0.1.6.tgz", + "integrity": "sha1-qeEss66Nh2cn7u84Q/igiXtcmNY=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-arrayish": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-arrayish/-/is-arrayish-0.2.1.tgz", + "integrity": "sha1-d8mYQFJ6qOyxqLppe4BkWnqSap0=", + "dev": true + }, + "is-binary-path": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-binary-path/-/is-binary-path-1.0.1.tgz", + "integrity": "sha1-dfFmQrSA8YenEcgUFh/TpKdlWJg=", + "dev": true, + "requires": { + "binary-extensions": "^1.0.0" + } + }, + "is-buffer": { + "version": "1.1.6", + "resolved": "https://registry.npmjs.org/is-buffer/-/is-buffer-1.1.6.tgz", + "integrity": "sha512-NcdALwpXkTm5Zvvbk7owOUSvVvBKDgKP5/ewfXEznmQFfs4ZRmanOeKBTjRVjka3QFoN6XJ+9F3USqfHqTaU5w==", + "dev": true + }, + "is-builtin-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-builtin-module/-/is-builtin-module-1.0.0.tgz", + "integrity": "sha1-VAVy0096wxGfj3bDDLwbHgN6/74=", + "dev": true, + "requires": { + "builtin-modules": "^1.0.0" + } + }, + "is-data-descriptor": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-0.1.4.tgz", + "integrity": "sha1-C17mSDiOLIYCgueT8YVv7D8wG1Y=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-descriptor": { + "version": "0.1.6", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-0.1.6.tgz", + "integrity": "sha512-avDYr0SB3DwO9zsMov0gKCESFYqCnE4hq/4z3TdUlukEy5t9C0YRq7HLrsN52NAcqXKaepeCD0n+B0arnVG3Hg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^0.1.6", + "is-data-descriptor": "^0.1.4", + "kind-of": "^5.0.0" + }, + "dependencies": { + "kind-of": { + "version": "5.1.0", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-5.1.0.tgz", + "integrity": "sha512-NGEErnH6F2vUuXDh+OlbcKW7/wOcfdRHaZ7VWtqCztfHri/++YKmP51OdWeGPuqCOba6kk2OTe5d02VmTB80Pw==", + "dev": true + } + } + }, + "is-extendable": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-0.1.1.tgz", + "integrity": "sha1-YrEQ4omkcUGOPsNqYX1HLjAd/Ik=", + "dev": true + }, + "is-extglob": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/is-extglob/-/is-extglob-2.1.1.tgz", + "integrity": "sha1-qIwCU1eR8C7TfHahueqXc8gz+MI=", + "dev": true + }, + "is-finite": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-finite/-/is-finite-1.1.0.tgz", + "integrity": "sha512-cdyMtqX/BOqqNBBiKlIVkytNHm49MtMlYyn1zxzvJKWmFMlGzm+ry5BBfYyeY9YmNKbRSo/o7OX9w9ale0wg3w==", + "dev": true + }, + "is-fullwidth-code-point": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-fullwidth-code-point/-/is-fullwidth-code-point-1.0.0.tgz", + "integrity": "sha1-754xOG8DGn8NZDr4L95QxFfvAMs=", + "dev": true, + "requires": { + "number-is-nan": "^1.0.0" + } + }, + "is-glob": { + "version": "4.0.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-4.0.0.tgz", + "integrity": "sha1-lSHHaEXMJhCoUgPd8ICpWML/q8A=", + "dev": true, + "requires": { + "is-extglob": "^2.1.1" + } + }, + "is-negated-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-negated-glob/-/is-negated-glob-1.0.0.tgz", + "integrity": "sha1-aRC8pdqMleeEtXUbl2z1oQ/uNtI=", + "dev": true + }, + "is-number": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/is-number/-/is-number-3.0.0.tgz", + "integrity": "sha1-JP1iAaR4LPUFYcgQJ2r8fRLXEZU=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "is-plain-object": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/is-plain-object/-/is-plain-object-2.0.4.tgz", + "integrity": "sha512-h5PpgXkWitc38BBMYawTYMWJHFZJVnBquFE57xFpjB8pJFiF6gZ+bU+WyI/yqXiFR5mdLsgYNaPe8uao6Uv9Og==", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "is-relative": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-relative/-/is-relative-1.0.0.tgz", + "integrity": "sha512-Kw/ReK0iqwKeu0MITLFuj0jbPAmEiOsIwyIXvvbfa6QfmN9pkD1M+8pdk7Rl/dTKbH34/XBFMbgD4iMJhLQbGA==", + "dev": true, + "requires": { + "is-unc-path": "^1.0.0" + } + }, + "is-typedarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-typedarray/-/is-typedarray-1.0.0.tgz", + "integrity": "sha1-5HnICFjfDBsR3dppQPlgEfzaSpo=", + "dev": true + }, + "is-unc-path": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-unc-path/-/is-unc-path-1.0.0.tgz", + "integrity": "sha512-mrGpVd0fs7WWLfVsStvgF6iEJnbjDFZh9/emhRDcGWTduTfNHd9CHeUwH3gYIjdbwo4On6hunkztwOaAw0yllQ==", + "dev": true, + "requires": { + "unc-path-regex": "^0.1.2" + } + }, + "is-utf8": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/is-utf8/-/is-utf8-0.2.1.tgz", + "integrity": "sha1-Sw2hRCEE0bM2NA6AeX6GXPOffXI=", + "dev": true + }, + "is-valid-glob": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-valid-glob/-/is-valid-glob-1.0.0.tgz", + "integrity": "sha1-Kb8+/3Ab4tTTFdusw5vDn+j2Aao=", + "dev": true + }, + "is-windows": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-windows/-/is-windows-1.0.2.tgz", + "integrity": "sha512-eXK1UInq2bPmjyX6e3VHIzMLobc4J94i4AWn+Hpq3OU5KkrRC96OAcR3PRJ/pGu6m8TRnBHP9dkXQVsT/COVIA==", + "dev": true + }, + "is-wsl": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/is-wsl/-/is-wsl-1.1.0.tgz", + "integrity": "sha1-HxbkqiKwTRM2tmGIpmrzxgDDpm0=", + "dev": true + }, + "isarray": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/isarray/-/isarray-1.0.0.tgz", + "integrity": "sha1-u5NdSFgsuhaMBoNJV6VKPgcSTxE=", + "dev": true + }, + "isexe": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/isexe/-/isexe-2.0.0.tgz", + "integrity": "sha1-6PvzdNxVb/iUehDcsFctYz8s+hA=", + "dev": true + }, + "isobject": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-3.0.1.tgz", + "integrity": "sha1-TkMekrEalzFjaqH5yNHMvP2reN8=", + "dev": true + }, + "isstream": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/isstream/-/isstream-0.1.2.tgz", + "integrity": "sha1-R+Y/evVa+m+S4VAOaQ64uFKcCZo=", + "dev": true + }, + "js-base64": { + "version": "2.5.2", + "resolved": "https://registry.npmjs.org/js-base64/-/js-base64-2.5.2.tgz", + "integrity": "sha512-Vg8czh0Q7sFBSUMWWArX/miJeBWYBPpdU/3M/DKSaekLMqrqVPaedp+5mZhie/r0lgrcaYBfwXatEew6gwgiQQ==", + "dev": true + }, + "jsbn": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/jsbn/-/jsbn-0.1.1.tgz", + "integrity": "sha1-peZUwuWi3rXyAdls77yoDA7y9RM=", + "dev": true + }, + "json-parse-better-errors": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/json-parse-better-errors/-/json-parse-better-errors-1.0.2.tgz", + "integrity": "sha512-mrqyZKfX5EhL7hvqcV6WG1yYjnjeuYDzDhhcAAUrq8Po85NBQBJP+ZDUT75qZQ98IkUoBqdkExkukOU7Ts2wrw==", + "dev": true + }, + "json-schema": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/json-schema/-/json-schema-0.2.3.tgz", + "integrity": "sha1-tIDIkuWaLwWVTOcnvT8qTogvnhM=", + "dev": true + }, + "json-schema-traverse": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/json-schema-traverse/-/json-schema-traverse-0.4.1.tgz", + "integrity": "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg==", + "dev": true + }, + "json-stable-stringify-without-jsonify": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json-stable-stringify-without-jsonify/-/json-stable-stringify-without-jsonify-1.0.1.tgz", + "integrity": "sha1-nbe1lJatPzz+8wp1FC0tkwrXJlE=", + "dev": true + }, + "json-stringify-safe": { + "version": "5.0.1", + "resolved": "https://registry.npmjs.org/json-stringify-safe/-/json-stringify-safe-5.0.1.tgz", + "integrity": "sha1-Epai1Y/UXxmg9s4B1lcB4sc1tus=", + "dev": true + }, + "json5": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/json5/-/json5-1.0.1.tgz", + "integrity": "sha512-aKS4WQjPenRxiQsC93MNfjx+nbF4PAdYzmd/1JIj8HYzqfbu86beTuNgXDzPknWk0n0uARlyewZo4s++ES36Ow==", + "dev": true, + "requires": { + "minimist": "^1.2.0" + } + }, + "jsprim": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/jsprim/-/jsprim-1.4.1.tgz", + "integrity": "sha1-MT5mvB5cwG5Di8G3SZwuXFastqI=", + "dev": true, + "requires": { + "assert-plus": "1.0.0", + "extsprintf": "1.3.0", + "json-schema": "0.2.3", + "verror": "1.10.0" + } + }, + "just-debounce": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/just-debounce/-/just-debounce-1.0.0.tgz", + "integrity": "sha1-h/zPrv/AtozRnVX2cilD+SnqNeo=", + "dev": true + }, + "kind-of": { + "version": "6.0.3", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-6.0.3.tgz", + "integrity": "sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw==", + "dev": true + }, + "last-run": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/last-run/-/last-run-1.1.1.tgz", + "integrity": "sha1-RblpQsF7HHnHchmCWbqUO+v4yls=", + "dev": true, + "requires": { + "default-resolution": "^2.0.0", + "es6-weak-map": "^2.0.1" + } + }, + "lazystream": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lazystream/-/lazystream-1.0.0.tgz", + "integrity": "sha1-9plf4PggOS9hOWvolGJAe7dxaOQ=", + "dev": true, + "requires": { + "readable-stream": "^2.0.5" + } + }, + "lcid": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lcid/-/lcid-1.0.0.tgz", + "integrity": "sha1-MIrMr6C8SDo4Z7S28rlQYlHRuDU=", + "dev": true, + "requires": { + "invert-kv": "^1.0.0" + } + }, + "lead": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/lead/-/lead-1.0.0.tgz", + "integrity": "sha1-bxT5mje+Op3XhPVJVpDlkDRm7kI=", + "dev": true, + "requires": { + "flush-write-stream": "^1.0.2" + } + }, + "liftoff": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/liftoff/-/liftoff-3.1.0.tgz", + "integrity": "sha512-DlIPlJUkCV0Ips2zf2pJP0unEoT1kwYhiiPUGF3s/jtxTCjziNLoiVVh+jqWOWeFi6mmwQ5fNxvAUyPad4Dfog==", + "dev": true, + "requires": { + "extend": "^3.0.0", + "findup-sync": "^3.0.0", + "fined": "^1.0.1", + "flagged-respawn": "^1.0.0", + "is-plain-object": "^2.0.4", + "object.map": "^1.0.0", + "rechoir": "^0.6.2", + "resolve": "^1.1.7" + } + }, + "load-json-file": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/load-json-file/-/load-json-file-1.1.0.tgz", + "integrity": "sha1-lWkFcI1YtLq0wiYbBPWfMcmTdMA=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "parse-json": "^2.2.0", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0", + "strip-bom": "^2.0.0" + } + }, + "loader-runner": { + "version": "2.4.0", + "resolved": "https://registry.npmjs.org/loader-runner/-/loader-runner-2.4.0.tgz", + "integrity": "sha512-Jsmr89RcXGIwivFY21FcRrisYZfvLMTWx5kOLc+JTxtpBOG6xML0vzbc6SEQG2FO9/4Fc3wW4LVcB5DmGflaRw==", + "dev": true + }, + "loader-utils": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/loader-utils/-/loader-utils-1.2.3.tgz", + "integrity": "sha512-fkpz8ejdnEMG3s37wGL07iSBDg99O9D5yflE9RGNH3hRdx9SOwYfnGYdZOUIZitN8E+E2vkq3MUMYMvPYl5ZZA==", + "dev": true, + "requires": { + "big.js": "^5.2.2", + "emojis-list": "^2.0.0", + "json5": "^1.0.1" + } + }, + "locate-path": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/locate-path/-/locate-path-3.0.0.tgz", + "integrity": "sha512-7AO748wWnIhNqAuaty2ZWHkQHRSNfPVIsPIfwEOWO22AmaoVrWavlOcMR5nzTLNYvp36X220/maaRsrec1G65A==", + "dev": true, + "requires": { + "p-locate": "^3.0.0", + "path-exists": "^3.0.0" + }, + "dependencies": { + "path-exists": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-3.0.0.tgz", + "integrity": "sha1-zg6+ql94yxiSXqfYENe1mwEP1RU=", + "dev": true + } + } + }, + "lodash": { + "version": "4.17.15", + "resolved": "https://registry.npmjs.org/lodash/-/lodash-4.17.15.tgz", + "integrity": "sha512-8xOcRHvCjnocdS5cpwXQXVzmmh5e5+saE2QGoeQmbKmRS6J3VQppPOIt0MnmE+4xlZoumy0GPG0D0MVIQbNA1A==", + "dev": true + }, + "lodash.clone": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clone/-/lodash.clone-4.5.0.tgz", + "integrity": "sha1-GVhwRQ9aExkkeN9Lw9I9LeoZB7Y=", + "dev": true + }, + "lodash.clonedeep": { + "version": "4.5.0", + "resolved": "https://registry.npmjs.org/lodash.clonedeep/-/lodash.clonedeep-4.5.0.tgz", + "integrity": "sha1-4j8/nE+Pvd6HJSnBBxhXoIblzO8=", + "dev": true + }, + "lodash.debounce": { + "version": "4.0.8", + "resolved": "https://registry.npmjs.org/lodash.debounce/-/lodash.debounce-4.0.8.tgz", + "integrity": "sha1-gteb/zCmfEAF/9XiUVMArZyk168=", + "dev": true + }, + "lodash.some": { + "version": "4.6.0", + "resolved": "https://registry.npmjs.org/lodash.some/-/lodash.some-4.6.0.tgz", + "integrity": "sha1-G7nzFO9ri63tE7VJFpsqlF62jk0=", + "dev": true + }, + "loud-rejection": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/loud-rejection/-/loud-rejection-1.6.0.tgz", + "integrity": "sha1-W0b4AUft7leIcPCG0Eghz5mOVR8=", + "dev": true, + "requires": { + "currently-unhandled": "^0.4.1", + "signal-exit": "^3.0.0" + } + }, + "lru-cache": { + "version": "4.1.5", + "resolved": "https://registry.npmjs.org/lru-cache/-/lru-cache-4.1.5.tgz", + "integrity": "sha512-sWZlbEP2OsHNkXrMl5GYk/jKk70MBng6UU4YI/qGDYbgf6YbP4EvmqISbXCoJiRKs+1bSpFHVgQxvJ17F2li5g==", + "dev": true, + "requires": { + "pseudomap": "^1.0.2", + "yallist": "^2.1.2" + } + }, + "make-dir": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/make-dir/-/make-dir-2.1.0.tgz", + "integrity": "sha512-LS9X+dc8KLxXCb8dni79fLIIUA5VyZoyjSMCwTluaXA0o27cCK0bhXkpgw+sTXVpPy/lSO57ilRixqk0vDmtRA==", + "dev": true, + "requires": { + "pify": "^4.0.1", + "semver": "^5.6.0" + }, + "dependencies": { + "pify": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/pify/-/pify-4.0.1.tgz", + "integrity": "sha512-uB80kBFb/tfd68bVleG9T5GGsGPjJrLAUpR5PZIrhBnIaRTQRjqdJSsIKkOP6OAIFbj7GOrcudc5pNjZ+geV2g==", + "dev": true + } + } + }, + "make-iterator": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/make-iterator/-/make-iterator-1.0.1.tgz", + "integrity": "sha512-pxiuXh0iVEq7VM7KMIhs5gxsfxCux2URptUQaXo4iZZJxBAzTPOLE2BumO5dbfVYq/hBJFBR/a1mFDmOx5AGmw==", + "dev": true, + "requires": { + "kind-of": "^6.0.2" + } + }, + "mamacro": { + "version": "0.0.3", + "resolved": "https://registry.npmjs.org/mamacro/-/mamacro-0.0.3.tgz", + "integrity": "sha512-qMEwh+UujcQ+kbz3T6V+wAmO2U8veoq2w+3wY8MquqwVA3jChfwY+Tk52GZKDfACEPjuZ7r2oJLejwpt8jtwTA==", + "dev": true + }, + "map-cache": { + "version": "0.2.2", + "resolved": "https://registry.npmjs.org/map-cache/-/map-cache-0.2.2.tgz", + "integrity": "sha1-wyq9C9ZSXZsFFkW7TyasXcmKDb8=", + "dev": true + }, + "map-obj": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/map-obj/-/map-obj-1.0.1.tgz", + "integrity": "sha1-2TPOuSBdgr3PSIb2dCvcK03qFG0=", + "dev": true + }, + "map-visit": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/map-visit/-/map-visit-1.0.0.tgz", + "integrity": "sha1-7Nyo8TFE5mDxtb1B8S80edmN+48=", + "dev": true, + "requires": { + "object-visit": "^1.0.0" + } + }, + "matchdep": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/matchdep/-/matchdep-2.0.0.tgz", + "integrity": "sha1-xvNINKDY28OzfCfui7yyfHd1WC4=", + "dev": true, + "requires": { + "findup-sync": "^2.0.0", + "micromatch": "^3.0.4", + "resolve": "^1.4.0", + "stack-trace": "0.0.10" + }, + "dependencies": { + "findup-sync": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/findup-sync/-/findup-sync-2.0.0.tgz", + "integrity": "sha1-kyaxSIwi0aYIhlCoaQGy2akKLLw=", + "dev": true, + "requires": { + "detect-file": "^1.0.0", + "is-glob": "^3.1.0", + "micromatch": "^3.0.4", + "resolve-dir": "^1.0.1" + } + }, + "is-glob": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/is-glob/-/is-glob-3.1.0.tgz", + "integrity": "sha1-e6WuJCF4BKxwcHuWkiVnSGzD6Eo=", + "dev": true, + "requires": { + "is-extglob": "^2.1.0" + } + } + } + }, + "md5.js": { + "version": "1.3.5", + "resolved": "https://registry.npmjs.org/md5.js/-/md5.js-1.3.5.tgz", + "integrity": "sha512-xitP+WxNPcTTOgnTJcrhM0xvdPepipPSf3I8EIpGKeFLjt3PlJLIDG3u8EX53ZIubkb+5U2+3rELYpEhHhzdkg==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "memory-fs": { + "version": "0.4.1", + "resolved": "https://registry.npmjs.org/memory-fs/-/memory-fs-0.4.1.tgz", + "integrity": "sha1-OpoguEYlI+RHz7x+i7gO1me/xVI=", + "dev": true, + "requires": { + "errno": "^0.1.3", + "readable-stream": "^2.0.1" + } + }, + "meow": { + "version": "3.7.0", + "resolved": "https://registry.npmjs.org/meow/-/meow-3.7.0.tgz", + "integrity": "sha1-cstmi0JSKCkKu/qFaJJYcwioAfs=", + "dev": true, + "requires": { + "camelcase-keys": "^2.0.0", + "decamelize": "^1.1.2", + "loud-rejection": "^1.0.0", + "map-obj": "^1.0.1", + "minimist": "^1.1.3", + "normalize-package-data": "^2.3.4", + "object-assign": "^4.0.1", + "read-pkg-up": "^1.0.1", + "redent": "^1.0.0", + "trim-newlines": "^1.0.0" + } + }, + "micromatch": { + "version": "3.1.10", + "resolved": "https://registry.npmjs.org/micromatch/-/micromatch-3.1.10.tgz", + "integrity": "sha512-MWikgl9n9M3w+bpsY3He8L+w9eF9338xRl8IAO5viDizwSzziFEyUzo2xrrloB64ADbTf8uA8vRqqttDTOmccg==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "braces": "^2.3.1", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "extglob": "^2.0.4", + "fragment-cache": "^0.2.1", + "kind-of": "^6.0.2", + "nanomatch": "^1.2.9", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.2" + } + }, + "miller-rabin": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/miller-rabin/-/miller-rabin-4.0.1.tgz", + "integrity": "sha512-115fLhvZVqWwHPbClyntxEVfVDfl9DLLTuJvq3g2O/Oxi8AiNouAHvDSzHS0viUJc+V5vm3eq91Xwqn9dp4jRA==", + "dev": true, + "requires": { + "bn.js": "^4.0.0", + "brorand": "^1.0.1" + } + }, + "mime-db": { + "version": "1.43.0", + "resolved": "https://registry.npmjs.org/mime-db/-/mime-db-1.43.0.tgz", + "integrity": "sha512-+5dsGEEovYbT8UY9yD7eE4XTc4UwJ1jBYlgaQQF38ENsKR3wj/8q8RFZrF9WIZpB2V1ArTVFUva8sAul1NzRzQ==", + "dev": true + }, + "mime-types": { + "version": "2.1.26", + "resolved": "https://registry.npmjs.org/mime-types/-/mime-types-2.1.26.tgz", + "integrity": "sha512-01paPWYgLrkqAyrlDorC1uDwl2p3qZT7yl806vW7DvDoxwXi46jsjFbg+WdwotBIk6/MbEhO/dh5aZ5sNj/dWQ==", + "dev": true, + "requires": { + "mime-db": "1.43.0" + } + }, + "minimalistic-assert": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-assert/-/minimalistic-assert-1.0.1.tgz", + "integrity": "sha512-UtJcAD4yEaGtjPezWuO9wC4nwUnVH/8/Im3yEHQP4b67cXlD/Qr9hdITCU1xDbSEXg2XKNaP8jsReV7vQd00/A==", + "dev": true + }, + "minimalistic-crypto-utils": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/minimalistic-crypto-utils/-/minimalistic-crypto-utils-1.0.1.tgz", + "integrity": "sha1-9sAMHAsIIkblxNmd+4x8CDsrWCo=", + "dev": true + }, + "minimatch": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/minimatch/-/minimatch-3.0.4.tgz", + "integrity": "sha512-yJHVQEhyqPLUTgt9B83PXu6W3rx4MvvHvSUvToogpwoGDOUQ+yDrR0HRot+yOCdCO7u4hX3pWft6kWBBcqh0UA==", + "dev": true, + "requires": { + "brace-expansion": "^1.1.7" + } + }, + "minimist": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-1.2.0.tgz", + "integrity": "sha1-o1AIsg9BOD7sH7kU9M1d95omQoQ=", + "dev": true + }, + "mississippi": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/mississippi/-/mississippi-3.0.0.tgz", + "integrity": "sha512-x471SsVjUtBRtcvd4BzKE9kFC+/2TeWgKCgw0bZcw1b9l2X3QX5vCWgF+KaZaYm87Ss//rHnWryupDrgLvmSkA==", + "dev": true, + "requires": { + "concat-stream": "^1.5.0", + "duplexify": "^3.4.2", + "end-of-stream": "^1.1.0", + "flush-write-stream": "^1.0.0", + "from2": "^2.1.0", + "parallel-transform": "^1.1.0", + "pump": "^3.0.0", + "pumpify": "^1.3.3", + "stream-each": "^1.1.0", + "through2": "^2.0.0" + }, + "dependencies": { + "pump": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pump/-/pump-3.0.0.tgz", + "integrity": "sha512-LwZy+p3SFs1Pytd/jYct4wpv49HiYCqd9Rlc5ZVdk0V+8Yzv6jR5Blk3TRmPL1ft69TxP0IMZGJ+WPFU2BFhww==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + } + } + }, + "mixin-deep": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/mixin-deep/-/mixin-deep-1.3.2.tgz", + "integrity": "sha512-WRoDn//mXBiJ1H40rqa3vH0toePwSsGb45iInWlTySa+Uu4k3tYUSxa2v1KqAiLtvlrSzaExqS1gtk96A9zvEA==", + "dev": true, + "requires": { + "for-in": "^1.0.2", + "is-extendable": "^1.0.1" + }, + "dependencies": { + "is-extendable": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/is-extendable/-/is-extendable-1.0.1.tgz", + "integrity": "sha512-arnXMxT1hhoKo9k1LZdmlNyJdDDfy2v0fXjFlmok4+i8ul/6WlbVge9bhM74OpNPQPMGUToDtz+KXa1PneJxOA==", + "dev": true, + "requires": { + "is-plain-object": "^2.0.4" + } + } + } + }, + "mkdirp": { + "version": "0.5.1", + "resolved": "https://registry.npmjs.org/mkdirp/-/mkdirp-0.5.1.tgz", + "integrity": "sha1-MAV0OOrGz3+MR2fzhkjWaX11yQM=", + "dev": true, + "requires": { + "minimist": "0.0.8" + }, + "dependencies": { + "minimist": { + "version": "0.0.8", + "resolved": "https://registry.npmjs.org/minimist/-/minimist-0.0.8.tgz", + "integrity": "sha1-hX/Kv8M5fSYluCKCYuhqp6ARsF0=", + "dev": true + } + } + }, + "move-concurrently": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/move-concurrently/-/move-concurrently-1.0.1.tgz", + "integrity": "sha1-viwAX9oy4LKa8fBdfEszIUxwH5I=", + "dev": true, + "requires": { + "aproba": "^1.1.1", + "copy-concurrently": "^1.0.0", + "fs-write-stream-atomic": "^1.0.8", + "mkdirp": "^0.5.1", + "rimraf": "^2.5.4", + "run-queue": "^1.0.3" + } + }, + "ms": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/ms/-/ms-2.0.0.tgz", + "integrity": "sha1-VgiurfwAvmwpAd9fmGF4jeDVl8g=", + "dev": true + }, + "mute-stdout": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/mute-stdout/-/mute-stdout-1.0.1.tgz", + "integrity": "sha512-kDcwXR4PS7caBpuRYYBUz9iVixUk3anO3f5OYFiIPwK/20vCzKCHyKoulbiDY1S53zD2bxUpxN/IJ+TnXjfvxg==", + "dev": true + }, + "nan": { + "version": "2.12.1", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.12.1.tgz", + "integrity": "sha512-JY7V6lRkStKcKTvHO5NVSQRv+RV+FIL5pvDoLiAtSL9pKlC5x9PKQcZDsq7m4FO4d57mkhC6Z+QhAh3Jdk5JFw==", + "dev": true, + "optional": true + }, + "nanomatch": { + "version": "1.2.13", + "resolved": "https://registry.npmjs.org/nanomatch/-/nanomatch-1.2.13.tgz", + "integrity": "sha512-fpoe2T0RbHwBTBUOftAfBPaDEi06ufaUai0mE6Yn1kacc3SnTErfb/h+X94VXzI64rKFHYImXSvdwGGCmwOqCA==", + "dev": true, + "requires": { + "arr-diff": "^4.0.0", + "array-unique": "^0.3.2", + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "fragment-cache": "^0.2.1", + "is-windows": "^1.0.2", + "kind-of": "^6.0.2", + "object.pick": "^1.3.0", + "regex-not": "^1.0.0", + "snapdragon": "^0.8.1", + "to-regex": "^3.0.1" + } + }, + "neo-async": { + "version": "2.6.1", + "resolved": "https://registry.npmjs.org/neo-async/-/neo-async-2.6.1.tgz", + "integrity": "sha512-iyam8fBuCUpWeKPGpaNMetEocMt364qkCsfL9JuhjXX6dRnguRVOfk2GZaDpPjcOKiiXCPINZC1GczQ7iTq3Zw==", + "dev": true + }, + "next-tick": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/next-tick/-/next-tick-1.0.0.tgz", + "integrity": "sha1-yobR/ogoFpsBICCOPchCS524NCw=", + "dev": true + }, + "node-gyp": { + "version": "3.8.0", + "resolved": "https://registry.npmjs.org/node-gyp/-/node-gyp-3.8.0.tgz", + "integrity": "sha512-3g8lYefrRRzvGeSowdJKAKyks8oUpLEd/DyPV4eMhVlhJ0aNaZqIrNUIPuEWWTAoPqyFkfGrM67MC69baqn6vA==", + "dev": true, + "requires": { + "fstream": "^1.0.0", + "glob": "^7.0.3", + "graceful-fs": "^4.1.2", + "mkdirp": "^0.5.0", + "nopt": "2 || 3", + "npmlog": "0 || 1 || 2 || 3 || 4", + "osenv": "0", + "request": "^2.87.0", + "rimraf": "2", + "semver": "~5.3.0", + "tar": "^2.0.0", + "which": "1" + }, + "dependencies": { + "semver": { + "version": "5.3.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.3.0.tgz", + "integrity": "sha1-myzl094C0XxgEq0yaqa00M9U+U8=", + "dev": true + } + } + }, + "node-libs-browser": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/node-libs-browser/-/node-libs-browser-2.2.1.tgz", + "integrity": "sha512-h/zcD8H9kaDZ9ALUWwlBUDo6TKF8a7qBSCSEGfjTVIYeqsioSKaAX+BN7NgiMGp6iSIXZ3PxgCu8KS3b71YK5Q==", + "dev": true, + "requires": { + "assert": "^1.1.1", + "browserify-zlib": "^0.2.0", + "buffer": "^4.3.0", + "console-browserify": "^1.1.0", + "constants-browserify": "^1.0.0", + "crypto-browserify": "^3.11.0", + "domain-browser": "^1.1.1", + "events": "^3.0.0", + "https-browserify": "^1.0.0", + "os-browserify": "^0.3.0", + "path-browserify": "0.0.1", + "process": "^0.11.10", + "punycode": "^1.2.4", + "querystring-es3": "^0.2.0", + "readable-stream": "^2.3.3", + "stream-browserify": "^2.0.1", + "stream-http": "^2.7.2", + "string_decoder": "^1.0.0", + "timers-browserify": "^2.0.4", + "tty-browserify": "0.0.0", + "url": "^0.11.0", + "util": "^0.11.0", + "vm-browserify": "^1.0.1" + }, + "dependencies": { + "punycode": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.4.1.tgz", + "integrity": "sha1-wNWmOycYgArY4esPpSachN1BhF4=", + "dev": true + } + } + }, + "node-releases": { + "version": "1.1.21", + "resolved": "https://registry.npmjs.org/node-releases/-/node-releases-1.1.21.tgz", + "integrity": "sha512-TwnURTCjc8a+ElJUjmDqU6+12jhli1Q61xOQmdZ7ECZVBZuQpN/1UnembiIHDM1wCcfLvh5wrWXUF5H6ufX64Q==", + "dev": true, + "requires": { + "semver": "^5.3.0" + } + }, + "node-sass": { + "version": "4.13.1", + "resolved": "https://registry.npmjs.org/node-sass/-/node-sass-4.13.1.tgz", + "integrity": "sha512-TTWFx+ZhyDx1Biiez2nB0L3YrCZ/8oHagaDalbuBSlqXgUPsdkUSzJsVxeDO9LtPB49+Fh3WQl3slABo6AotNw==", + "dev": true, + "requires": { + "async-foreach": "^0.1.3", + "chalk": "^1.1.1", + "cross-spawn": "^3.0.0", + "gaze": "^1.0.0", + "get-stdin": "^4.0.1", + "glob": "^7.0.3", + "in-publish": "^2.0.0", + "lodash": "^4.17.15", + "meow": "^3.7.0", + "mkdirp": "^0.5.1", + "nan": "^2.13.2", + "node-gyp": "^3.8.0", + "npmlog": "^4.0.0", + "request": "^2.88.0", + "sass-graph": "^2.2.4", + "stdout-stream": "^1.4.0", + "true-case-path": "^1.0.2" + }, + "dependencies": { + "ansi-styles": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/ansi-styles/-/ansi-styles-2.2.1.tgz", + "integrity": "sha1-tDLdM1i2NM914eRmQ2gkBTPB3b4=", + "dev": true + }, + "chalk": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/chalk/-/chalk-1.1.3.tgz", + "integrity": "sha1-qBFcVeSnAv5NFQq9OHKCKn4J/Jg=", + "dev": true, + "requires": { + "ansi-styles": "^2.2.1", + "escape-string-regexp": "^1.0.2", + "has-ansi": "^2.0.0", + "strip-ansi": "^3.0.0", + "supports-color": "^2.0.0" + } + }, + "nan": { + "version": "2.14.0", + "resolved": "https://registry.npmjs.org/nan/-/nan-2.14.0.tgz", + "integrity": "sha512-INOFj37C7k3AfaNTtX8RhsTw7qRy7eLET14cROi9+5HAVbbHuIWUHEauBv5qT4Av2tWasiTY1Jw6puUNqRJXQg==", + "dev": true + }, + "supports-color": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-2.0.0.tgz", + "integrity": "sha1-U10EXOa2Nj+kARcIRimZXp3zJMc=", + "dev": true + } + } + }, + "nopt": { + "version": "3.0.6", + "resolved": "https://registry.npmjs.org/nopt/-/nopt-3.0.6.tgz", + "integrity": "sha1-xkZdvwirzU2zWTF/eaxopkayj/k=", + "dev": true, + "requires": { + "abbrev": "1" + } + }, + "normalize-package-data": { + "version": "2.4.2", + "resolved": "https://registry.npmjs.org/normalize-package-data/-/normalize-package-data-2.4.2.tgz", + "integrity": "sha512-YcMnjqeoUckXTPKZSAsPjUPLxH85XotbpqK3w4RyCwdFQSU5FxxBys8buehkSfg0j9fKvV1hn7O0+8reEgkAiw==", + "dev": true, + "requires": { + "hosted-git-info": "^2.1.4", + "is-builtin-module": "^1.0.0", + "semver": "2 || 3 || 4 || 5", + "validate-npm-package-license": "^3.0.1" + } + }, + "normalize-path": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/normalize-path/-/normalize-path-2.1.1.tgz", + "integrity": "sha1-GrKLVW4Zg2Oowab35vogE3/mrtk=", + "dev": true, + "requires": { + "remove-trailing-separator": "^1.0.1" + } + }, + "normalize-range": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/normalize-range/-/normalize-range-0.1.2.tgz", + "integrity": "sha1-LRDAa9/TEuqXd2laTShDlFa3WUI=", + "dev": true + }, + "now-and-later": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/now-and-later/-/now-and-later-2.0.1.tgz", + "integrity": "sha512-KGvQ0cB70AQfg107Xvs/Fbu+dGmZoTRJp2TaPwcwQm3/7PteUyN2BCgk8KBMPGBUXZdVwyWS8fDCGFygBm19UQ==", + "dev": true, + "requires": { + "once": "^1.3.2" + } + }, + "npmlog": { + "version": "4.1.2", + "resolved": "https://registry.npmjs.org/npmlog/-/npmlog-4.1.2.tgz", + "integrity": "sha512-2uUqazuKlTaSI/dC8AzicUck7+IrEaOnN/e0jd3Xtt1KcGpwx30v50mL7oPyr/h9bL3E4aZccVwpwP+5W9Vjkg==", + "dev": true, + "requires": { + "are-we-there-yet": "~1.1.2", + "console-control-strings": "~1.1.0", + "gauge": "~2.7.3", + "set-blocking": "~2.0.0" + } + }, + "num2fraction": { + "version": "1.2.2", + "resolved": "https://registry.npmjs.org/num2fraction/-/num2fraction-1.2.2.tgz", + "integrity": "sha1-b2gragJ6Tp3fpFZM0lidHU5mnt4=", + "dev": true + }, + "number-is-nan": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/number-is-nan/-/number-is-nan-1.0.1.tgz", + "integrity": "sha1-CXtgK1NCKlIsGvuHkDGDNpQaAR0=", + "dev": true + }, + "oauth-sign": { + "version": "0.9.0", + "resolved": "https://registry.npmjs.org/oauth-sign/-/oauth-sign-0.9.0.tgz", + "integrity": "sha512-fexhUFFPTGV8ybAtSIGbV6gOkSv8UtRbDBnAyLQw4QPKkgNlsH2ByPGtMUqdWkos6YCRmAqViwgZrJc/mRDzZQ==", + "dev": true + }, + "object-assign": { + "version": "4.1.1", + "resolved": "https://registry.npmjs.org/object-assign/-/object-assign-4.1.1.tgz", + "integrity": "sha1-IQmtx5ZYh8/AXLvUQsrIv7s2CGM=", + "dev": true + }, + "object-copy": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/object-copy/-/object-copy-0.1.0.tgz", + "integrity": "sha1-fn2Fi3gb18mRpBupde04EnVOmYw=", + "dev": true, + "requires": { + "copy-descriptor": "^0.1.0", + "define-property": "^0.2.5", + "kind-of": "^3.0.3" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "object-keys": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/object-keys/-/object-keys-1.1.1.tgz", + "integrity": "sha512-NuAESUOUMrlIXOfHKzD6bpPu3tYt3xvjNdRIQ+FeT0lNb4K8WR70CaDxhuNguS2XG+GjkyMwOzsN5ZktImfhLA==", + "dev": true + }, + "object-visit": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object-visit/-/object-visit-1.0.1.tgz", + "integrity": "sha1-95xEk68MU3e1n+OdOV5BBC3QRbs=", + "dev": true, + "requires": { + "isobject": "^3.0.0" + } + }, + "object.assign": { + "version": "4.1.0", + "resolved": "https://registry.npmjs.org/object.assign/-/object.assign-4.1.0.tgz", + "integrity": "sha512-exHJeq6kBKj58mqGyTQ9DFvrZC/eR6OwxzoM9YRoGBqrXYonaFyGiFMuc9VZrXf7DarreEwMpurG3dd+CNyW5w==", + "dev": true, + "requires": { + "define-properties": "^1.1.2", + "function-bind": "^1.1.1", + "has-symbols": "^1.0.0", + "object-keys": "^1.0.11" + } + }, + "object.defaults": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/object.defaults/-/object.defaults-1.1.0.tgz", + "integrity": "sha1-On+GgzS0B96gbaFtiNXNKeQ1/s8=", + "dev": true, + "requires": { + "array-each": "^1.0.1", + "array-slice": "^1.0.0", + "for-own": "^1.0.0", + "isobject": "^3.0.0" + } + }, + "object.map": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.map/-/object.map-1.0.1.tgz", + "integrity": "sha1-z4Plncj8wK1fQlDh94s7gb2AHTc=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "object.pick": { + "version": "1.3.0", + "resolved": "https://registry.npmjs.org/object.pick/-/object.pick-1.3.0.tgz", + "integrity": "sha1-h6EKxMFpS9Lhy/U1kaZhQftd10c=", + "dev": true, + "requires": { + "isobject": "^3.0.1" + } + }, + "object.reduce": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/object.reduce/-/object.reduce-1.0.1.tgz", + "integrity": "sha1-b+NI8qx/oPlcpiEiZZkJaCW7A60=", + "dev": true, + "requires": { + "for-own": "^1.0.0", + "make-iterator": "^1.0.0" + } + }, + "once": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/once/-/once-1.4.0.tgz", + "integrity": "sha1-WDsap3WWHUsROsF9nFC6753Xa9E=", + "dev": true, + "requires": { + "wrappy": "1" + } + }, + "ordered-read-streams": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/ordered-read-streams/-/ordered-read-streams-1.0.1.tgz", + "integrity": "sha1-d8DLN8QVJdZBZtmQ/61+xqDhNj4=", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "os-browserify": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/os-browserify/-/os-browserify-0.3.0.tgz", + "integrity": "sha1-hUNzx/XCMVkU/Jv8a9gjj92h7Cc=", + "dev": true + }, + "os-homedir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-homedir/-/os-homedir-1.0.2.tgz", + "integrity": "sha1-/7xJiDNuDoM94MFox+8VISGqf7M=", + "dev": true + }, + "os-locale": { + "version": "1.4.0", + "resolved": "https://registry.npmjs.org/os-locale/-/os-locale-1.4.0.tgz", + "integrity": "sha1-IPnxeuKe00XoveWDsT0gCYA8FNk=", + "dev": true, + "requires": { + "lcid": "^1.0.0" + } + }, + "os-tmpdir": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/os-tmpdir/-/os-tmpdir-1.0.2.tgz", + "integrity": "sha1-u+Z0BseaqFxc/sdm/lc0VV36EnQ=", + "dev": true + }, + "osenv": { + "version": "0.1.5", + "resolved": "https://registry.npmjs.org/osenv/-/osenv-0.1.5.tgz", + "integrity": "sha512-0CWcCECdMVc2Rw3U5w9ZjqX6ga6ubk1xDVKxtBQPK7wis/0F2r9T6k4ydGYhecl7YUBxBVxhL5oisPsNxAPe2g==", + "dev": true, + "requires": { + "os-homedir": "^1.0.0", + "os-tmpdir": "^1.0.0" + } + }, + "p-limit": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/p-limit/-/p-limit-2.2.1.tgz", + "integrity": "sha512-85Tk+90UCVWvbDavCLKPOLC9vvY8OwEX/RtKF+/1OADJMVlFfEHOiMTPVyxg7mk/dKa+ipdHm0OUkTvCpMTuwg==", + "dev": true, + "requires": { + "p-try": "^2.0.0" + } + }, + "p-locate": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/p-locate/-/p-locate-3.0.0.tgz", + "integrity": "sha512-x+12w/To+4GFfgJhBEpiDcLozRJGegY+Ei7/z0tSLkMmxGZNybVMSfWj9aJn8Z5Fc7dBUNJOOVgPv2H7IwulSQ==", + "dev": true, + "requires": { + "p-limit": "^2.0.0" + } + }, + "p-try": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/p-try/-/p-try-2.2.0.tgz", + "integrity": "sha512-R4nPAVTAU0B9D35/Gk3uJf/7XYbQcyohSKdvAxIRSNghFl4e71hVoGnBNQz9cWaXxO2I10KTC+3jMdvvoKw6dQ==", + "dev": true + }, + "pako": { + "version": "1.0.10", + "resolved": "https://registry.npmjs.org/pako/-/pako-1.0.10.tgz", + "integrity": "sha512-0DTvPVU3ed8+HNXOu5Bs+o//Mbdj9VNQMUOe9oKCwh8l0GNwpTDMKCWbRjgtD291AWnkAgkqA/LOnQS8AmS1tw==", + "dev": true + }, + "parallel-transform": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/parallel-transform/-/parallel-transform-1.2.0.tgz", + "integrity": "sha512-P2vSmIu38uIlvdcU7fDkyrxj33gTUy/ABO5ZUbGowxNCopBq/OoD42bP4UmMrJoPyk4Uqf0mu3mtWBhHCZD8yg==", + "dev": true, + "requires": { + "cyclist": "^1.0.1", + "inherits": "^2.0.3", + "readable-stream": "^2.1.5" + } + }, + "parse-asn1": { + "version": "5.1.5", + "resolved": "https://registry.npmjs.org/parse-asn1/-/parse-asn1-5.1.5.tgz", + "integrity": "sha512-jkMYn1dcJqF6d5CpU689bq7w/b5ALS9ROVSpQDPrZsqqesUJii9qutvoT5ltGedNXMO2e16YUWIghG9KxaViTQ==", + "dev": true, + "requires": { + "asn1.js": "^4.0.0", + "browserify-aes": "^1.0.0", + "create-hash": "^1.1.0", + "evp_bytestokey": "^1.0.0", + "pbkdf2": "^3.0.3", + "safe-buffer": "^5.1.1" + } + }, + "parse-filepath": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/parse-filepath/-/parse-filepath-1.0.2.tgz", + "integrity": "sha1-pjISf1Oq89FYdvWHLz/6x2PWyJE=", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "map-cache": "^0.2.0", + "path-root": "^0.1.1" + } + }, + "parse-json": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/parse-json/-/parse-json-2.2.0.tgz", + "integrity": "sha1-9ID0BDTvgHQfhGkJn43qGPVaTck=", + "dev": true, + "requires": { + "error-ex": "^1.2.0" + } + }, + "parse-node-version": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/parse-node-version/-/parse-node-version-1.0.1.tgz", + "integrity": "sha512-3YHlOa/JgH6Mnpr05jP9eDG254US9ek25LyIxZlDItp2iJtwyaXQb57lBYLdT3MowkUFYEV2XXNAYIPlESvJlA==", + "dev": true + }, + "parse-passwd": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/parse-passwd/-/parse-passwd-1.0.0.tgz", + "integrity": "sha1-bVuTSkVpk7I9N/QKOC1vFmao5cY=", + "dev": true + }, + "pascalcase": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/pascalcase/-/pascalcase-0.1.1.tgz", + "integrity": "sha1-s2PlXoAGym/iF4TS2yK9FdeRfxQ=", + "dev": true + }, + "path-browserify": { + "version": "0.0.1", + "resolved": "https://registry.npmjs.org/path-browserify/-/path-browserify-0.0.1.tgz", + "integrity": "sha512-BapA40NHICOS+USX9SN4tyhq+A2RrN/Ws5F0Z5aMHDp98Fl86lX8Oti8B7uN93L4Ifv4fHOEA+pQw87gmMO/lQ==", + "dev": true + }, + "path-dirname": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/path-dirname/-/path-dirname-1.0.2.tgz", + "integrity": "sha1-zDPSTVJeCZpTiMAzbG4yuRYGCeA=", + "dev": true + }, + "path-exists": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/path-exists/-/path-exists-2.1.0.tgz", + "integrity": "sha1-D+tsZPD8UY2adU3V77YscCJ2H0s=", + "dev": true, + "requires": { + "pinkie-promise": "^2.0.0" + } + }, + "path-is-absolute": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/path-is-absolute/-/path-is-absolute-1.0.1.tgz", + "integrity": "sha1-F0uSaHNVNP+8es5r9TpanhtcX18=", + "dev": true + }, + "path-parse": { + "version": "1.0.6", + "resolved": "https://registry.npmjs.org/path-parse/-/path-parse-1.0.6.tgz", + "integrity": "sha512-GSmOT2EbHrINBf9SR7CDELwlJ8AENk3Qn7OikK4nFYAu3Ote2+JYNVvkpAEQm3/TLNEJFD/xZJjzyxg3KBWOzw==", + "dev": true + }, + "path-root": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/path-root/-/path-root-0.1.1.tgz", + "integrity": "sha1-mkpoFMrBwM1zNgqV8yCDyOpHRbc=", + "dev": true, + "requires": { + "path-root-regex": "^0.1.0" + } + }, + "path-root-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/path-root-regex/-/path-root-regex-0.1.2.tgz", + "integrity": "sha1-v8zcjfWxLcUsi0PsONGNcsBLqW0=", + "dev": true + }, + "path-type": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/path-type/-/path-type-1.1.0.tgz", + "integrity": "sha1-WcRPfuSR2nBNpBXaWkBwuk+P5EE=", + "dev": true, + "requires": { + "graceful-fs": "^4.1.2", + "pify": "^2.0.0", + "pinkie-promise": "^2.0.0" + } + }, + "pbkdf2": { + "version": "3.0.17", + "resolved": "https://registry.npmjs.org/pbkdf2/-/pbkdf2-3.0.17.tgz", + "integrity": "sha512-U/il5MsrZp7mGg3mSQfn742na2T+1/vHDCG5/iTI3X9MKUuYUZVLQhyRsg06mCgDBTd57TxzgZt7P+fYfjRLtA==", + "dev": true, + "requires": { + "create-hash": "^1.1.2", + "create-hmac": "^1.1.4", + "ripemd160": "^2.0.1", + "safe-buffer": "^5.0.1", + "sha.js": "^2.4.8" + } + }, + "performance-now": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/performance-now/-/performance-now-2.1.0.tgz", + "integrity": "sha1-Ywn04OX6kT7BxpMHrjZLSzd8nns=", + "dev": true + }, + "pify": { + "version": "2.3.0", + "resolved": "https://registry.npmjs.org/pify/-/pify-2.3.0.tgz", + "integrity": "sha1-7RQaasBDqEnqWISY59yosVMw6Qw=", + "dev": true + }, + "pinkie": { + "version": "2.0.4", + "resolved": "https://registry.npmjs.org/pinkie/-/pinkie-2.0.4.tgz", + "integrity": "sha1-clVrgM+g1IqXToDnckjoDtT3+HA=", + "dev": true + }, + "pinkie-promise": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pinkie-promise/-/pinkie-promise-2.0.1.tgz", + "integrity": "sha1-ITXW36ejWMBprJsXh3YogihFD/o=", + "dev": true, + "requires": { + "pinkie": "^2.0.0" + } + }, + "pkg-dir": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/pkg-dir/-/pkg-dir-3.0.0.tgz", + "integrity": "sha512-/E57AYkoeQ25qkxMj5PBOVgF8Kiu/h7cYS30Z5+R7WaiCCBfLq58ZI/dSeaEKb9WVJV5n/03QwrN3IeWIFllvw==", + "dev": true, + "requires": { + "find-up": "^3.0.0" + }, + "dependencies": { + "find-up": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/find-up/-/find-up-3.0.0.tgz", + "integrity": "sha512-1yD6RmLI1XBfxugvORwlck6f75tYL+iR0jqwsOrOxMZyGYqUuDhJ0l4AXdO1iX/FTs9cBAMEk1gWSEx1kSbylg==", + "dev": true, + "requires": { + "locate-path": "^3.0.0" + } + } + } + }, + "plugin-error": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/plugin-error/-/plugin-error-1.0.1.tgz", + "integrity": "sha512-L1zP0dk7vGweZME2i+EeakvUNqSrdiI3F91TwEoYiGrAfUXmVv6fJIq4g82PAXxNsWOp0J7ZqQy/3Szz0ajTxA==", + "dev": true, + "requires": { + "ansi-colors": "^1.0.1", + "arr-diff": "^4.0.0", + "arr-union": "^3.1.0", + "extend-shallow": "^3.0.2" + } + }, + "posix-character-classes": { + "version": "0.1.1", + "resolved": "https://registry.npmjs.org/posix-character-classes/-/posix-character-classes-0.1.1.tgz", + "integrity": "sha1-AerA/jta9xoqbAL+q7jB/vfgDqs=", + "dev": true + }, + "postcss": { + "version": "7.0.16", + "resolved": "https://registry.npmjs.org/postcss/-/postcss-7.0.16.tgz", + "integrity": "sha512-MOo8zNSlIqh22Uaa3drkdIAgUGEL+AD1ESiSdmElLUmE2uVDo1QloiT/IfW9qRw8Gw+Y/w69UVMGwbufMSftxA==", + "dev": true, + "requires": { + "chalk": "^2.4.2", + "source-map": "^0.6.1", + "supports-color": "^6.1.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "postcss-value-parser": { + "version": "3.3.1", + "resolved": "https://registry.npmjs.org/postcss-value-parser/-/postcss-value-parser-3.3.1.tgz", + "integrity": "sha512-pISE66AbVkp4fDQ7VHBwRNXzAAKJjw4Vw7nWI/+Q3vuly7SNfgYXvm6i5IgFylHGK5sP/xHAbB7N49OS4gWNyQ==", + "dev": true + }, + "pretty-hrtime": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/pretty-hrtime/-/pretty-hrtime-1.0.3.tgz", + "integrity": "sha1-t+PqQkNaTJsnWdmeDyAesZWALuE=", + "dev": true + }, + "process": { + "version": "0.11.10", + "resolved": "https://registry.npmjs.org/process/-/process-0.11.10.tgz", + "integrity": "sha1-czIwDoQBYb2j5podHZGn1LwW8YI=", + "dev": true + }, + "process-nextick-args": { + "version": "1.0.7", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-1.0.7.tgz", + "integrity": "sha1-FQ4gt1ZZCtP5EJPyWk8q2L/zC6M=", + "dev": true + }, + "promise-inflight": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/promise-inflight/-/promise-inflight-1.0.1.tgz", + "integrity": "sha1-mEcocL8igTL8vdhoEputEsPAKeM=", + "dev": true + }, + "prr": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/prr/-/prr-1.0.1.tgz", + "integrity": "sha1-0/wRS6BplaRexok/SEzrHXj19HY=", + "dev": true + }, + "pseudomap": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/pseudomap/-/pseudomap-1.0.2.tgz", + "integrity": "sha1-8FKijacOYYkX7wqKw0wa5aaChrM=", + "dev": true + }, + "psl": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/psl/-/psl-1.7.0.tgz", + "integrity": "sha512-5NsSEDv8zY70ScRnOTn7bK7eanl2MvFrOrS/R6x+dBt5g1ghnj9Zv90kO8GwT8gxcu2ANyFprnFYB85IogIJOQ==", + "dev": true + }, + "public-encrypt": { + "version": "4.0.3", + "resolved": "https://registry.npmjs.org/public-encrypt/-/public-encrypt-4.0.3.tgz", + "integrity": "sha512-zVpa8oKZSz5bTMTFClc1fQOnyyEzpl5ozpi1B5YcvBrdohMjH2rfsBtyXcuNuwjsDIXmBYlF2N5FlJYhR29t8Q==", + "dev": true, + "requires": { + "bn.js": "^4.1.0", + "browserify-rsa": "^4.0.0", + "create-hash": "^1.1.0", + "parse-asn1": "^5.0.0", + "randombytes": "^2.0.1", + "safe-buffer": "^5.1.2" + } + }, + "pump": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/pump/-/pump-2.0.1.tgz", + "integrity": "sha512-ruPMNRkN3MHP1cWJc9OWr+T/xDP0jhXYCLfJcBuX54hhfIBnaQmAUMfDcG4DM5UMWByBbJY69QSphm3jtDKIkA==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "once": "^1.3.1" + } + }, + "pumpify": { + "version": "1.5.1", + "resolved": "https://registry.npmjs.org/pumpify/-/pumpify-1.5.1.tgz", + "integrity": "sha512-oClZI37HvuUJJxSKKrC17bZ9Cu0ZYhEAGPsPUy9KlMUmv9dKX2o77RUmq7f3XjIxbwyGwYzbzQ1L2Ks8sIradQ==", + "dev": true, + "requires": { + "duplexify": "^3.6.0", + "inherits": "^2.0.3", + "pump": "^2.0.0" + } + }, + "punycode": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-2.1.1.tgz", + "integrity": "sha512-XRsRjdf+j5ml+y/6GKHPZbrF/8p2Yga0JPtdqTIY2Xe5ohJPD9saDJJLPvp9+NSBprVvevdXZybnj2cv8OEd0A==", + "dev": true + }, + "qs": { + "version": "6.5.2", + "resolved": "https://registry.npmjs.org/qs/-/qs-6.5.2.tgz", + "integrity": "sha512-N5ZAX4/LxJmF+7wN74pUD6qAh9/wnvdQcjq9TZjevvXzSUo7bfmw91saqMjzGS2xq91/odN2dW/WOl7qQHNDGA==", + "dev": true + }, + "querystring": { + "version": "0.2.0", + "resolved": "https://registry.npmjs.org/querystring/-/querystring-0.2.0.tgz", + "integrity": "sha1-sgmEkgO7Jd+CDadW50cAWHhSFiA=", + "dev": true + }, + "querystring-es3": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/querystring-es3/-/querystring-es3-0.2.1.tgz", + "integrity": "sha1-nsYfeQSYdXB9aUFFlv2Qek1xHnM=", + "dev": true + }, + "randombytes": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/randombytes/-/randombytes-2.1.0.tgz", + "integrity": "sha512-vYl3iOX+4CKUWuxGi9Ukhie6fsqXqS9FE2Zaic4tNFD2N2QQaXOMFbuKK4QmDHC0JO6B1Zp41J0LpT0oR68amQ==", + "dev": true, + "requires": { + "safe-buffer": "^5.1.0" + } + }, + "randomfill": { + "version": "1.0.4", + "resolved": "https://registry.npmjs.org/randomfill/-/randomfill-1.0.4.tgz", + "integrity": "sha512-87lcbR8+MhcWcUiQ+9e+Rwx8MyR2P7qnt15ynUlbm3TU/fjbgz4GsvfSUDTemtCCtVCqb4ZcEFlyPNTh9bBTLw==", + "dev": true, + "requires": { + "randombytes": "^2.0.5", + "safe-buffer": "^5.1.0" + } + }, + "read-pkg": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/read-pkg/-/read-pkg-1.1.0.tgz", + "integrity": "sha1-9f+qXs0pyzHAR0vKfXVra7KePyg=", + "dev": true, + "requires": { + "load-json-file": "^1.0.0", + "normalize-package-data": "^2.3.2", + "path-type": "^1.0.0" + } + }, + "read-pkg-up": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/read-pkg-up/-/read-pkg-up-1.0.1.tgz", + "integrity": "sha1-nWPBMnbAZZGNV/ACpX9AobZD+wI=", + "dev": true, + "requires": { + "find-up": "^1.0.0", + "read-pkg": "^1.0.0" + } + }, + "readable-stream": { + "version": "2.3.6", + "resolved": "https://registry.npmjs.org/readable-stream/-/readable-stream-2.3.6.tgz", + "integrity": "sha512-tQtKA9WIAhBF3+VLAseyMqZeBjW0AHJoxOtYqSUZNJxauErmLbVm2FW1y+J/YA9dUrAC39ITejlZWhVIwawkKw==", + "dev": true, + "requires": { + "core-util-is": "~1.0.0", + "inherits": "~2.0.3", + "isarray": "~1.0.0", + "process-nextick-args": "~2.0.0", + "safe-buffer": "~5.1.1", + "string_decoder": "~1.1.1", + "util-deprecate": "~1.0.1" + }, + "dependencies": { + "process-nextick-args": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/process-nextick-args/-/process-nextick-args-2.0.0.tgz", + "integrity": "sha512-MtEC1TqN0EU5nephaJ4rAtThHtC86dNN9qCuEhtshvpVBkAW5ZO7BASN9REnF9eoXGcRub+pFuKEpOHE+HbEMw==", + "dev": true + } + } + }, + "readdirp": { + "version": "2.2.1", + "resolved": "https://registry.npmjs.org/readdirp/-/readdirp-2.2.1.tgz", + "integrity": "sha512-1JU/8q+VgFZyxwrJ+SVIOsh+KywWGpds3NTqikiKpDMZWScmAYyKIgqkO+ARvNWJfXeXR1zxz7aHF4u4CyH6vQ==", + "dev": true, + "requires": { + "graceful-fs": "^4.1.11", + "micromatch": "^3.1.10", + "readable-stream": "^2.0.2" + } + }, + "rechoir": { + "version": "0.6.2", + "resolved": "https://registry.npmjs.org/rechoir/-/rechoir-0.6.2.tgz", + "integrity": "sha1-hSBLVNuoLVdC4oyWdW70OvUOM4Q=", + "dev": true, + "requires": { + "resolve": "^1.1.6" + } + }, + "redent": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/redent/-/redent-1.0.0.tgz", + "integrity": "sha1-z5Fqsf1fHxbfsggi3W7H9zDCr94=", + "dev": true, + "requires": { + "indent-string": "^2.1.0", + "strip-indent": "^1.0.1" + } + }, + "regex-not": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/regex-not/-/regex-not-1.0.2.tgz", + "integrity": "sha512-J6SDjUgDxQj5NusnOtdFxDwN/+HWykR8GELwctJ7mdqhcyy1xEc4SRFHUXvxTp661YaVKAjfRLZ9cCqS6tn32A==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.2", + "safe-regex": "^1.1.0" + } + }, + "remove-bom-buffer": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/remove-bom-buffer/-/remove-bom-buffer-3.0.0.tgz", + "integrity": "sha512-8v2rWhaakv18qcvNeli2mZ/TMTL2nEyAKRvzo1WtnZBl15SHyEhrCu2/xKlJyUFKHiHgfXIyuY6g2dObJJycXQ==", + "dev": true, + "requires": { + "is-buffer": "^1.1.5", + "is-utf8": "^0.2.1" + } + }, + "remove-bom-stream": { + "version": "1.2.0", + "resolved": "https://registry.npmjs.org/remove-bom-stream/-/remove-bom-stream-1.2.0.tgz", + "integrity": "sha1-BfGlk/FuQuH7kOv1nejlaVJflSM=", + "dev": true, + "requires": { + "remove-bom-buffer": "^3.0.0", + "safe-buffer": "^5.1.0", + "through2": "^2.0.3" + } + }, + "remove-trailing-separator": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/remove-trailing-separator/-/remove-trailing-separator-1.1.0.tgz", + "integrity": "sha1-wkvOKig62tW8P1jg1IJJuSN52O8=", + "dev": true + }, + "repeat-element": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/repeat-element/-/repeat-element-1.1.3.tgz", + "integrity": "sha512-ahGq0ZnV5m5XtZLMb+vP76kcAM5nkLqk0lpqAuojSKGgQtn4eRi4ZZGm2olo2zKFH+sMsWaqOCW1dqAnOru72g==", + "dev": true + }, + "repeat-string": { + "version": "1.6.1", + "resolved": "https://registry.npmjs.org/repeat-string/-/repeat-string-1.6.1.tgz", + "integrity": "sha1-jcrkcOHIirwtYA//Sndihtp15jc=", + "dev": true + }, + "repeating": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/repeating/-/repeating-2.0.1.tgz", + "integrity": "sha1-UhTFOpJtNVJwdSf7q0FdvAjQbdo=", + "dev": true, + "requires": { + "is-finite": "^1.0.0" + } + }, + "replace-ext": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-ext/-/replace-ext-1.0.0.tgz", + "integrity": "sha1-3mMSg3P8v3w8z6TeWkgMRaZ5WOs=", + "dev": true + }, + "replace-homedir": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/replace-homedir/-/replace-homedir-1.0.0.tgz", + "integrity": "sha1-6H9tUTuSjd6AgmDBK+f+xv9ueYw=", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1", + "is-absolute": "^1.0.0", + "remove-trailing-separator": "^1.1.0" + } + }, + "request": { + "version": "2.88.2", + "resolved": "https://registry.npmjs.org/request/-/request-2.88.2.tgz", + "integrity": "sha512-MsvtOrfG9ZcrOwAW+Qi+F6HbD0CWXEh9ou77uOb7FM2WPhwT7smM833PzanhJLsgXjN89Ir6V2PczXNnMpwKhw==", + "dev": true, + "requires": { + "aws-sign2": "~0.7.0", + "aws4": "^1.8.0", + "caseless": "~0.12.0", + "combined-stream": "~1.0.6", + "extend": "~3.0.2", + "forever-agent": "~0.6.1", + "form-data": "~2.3.2", + "har-validator": "~5.1.3", + "http-signature": "~1.2.0", + "is-typedarray": "~1.0.0", + "isstream": "~0.1.2", + "json-stringify-safe": "~5.0.1", + "mime-types": "~2.1.19", + "oauth-sign": "~0.9.0", + "performance-now": "^2.1.0", + "qs": "~6.5.2", + "safe-buffer": "^5.1.2", + "tough-cookie": "~2.5.0", + "tunnel-agent": "^0.6.0", + "uuid": "^3.3.2" + } + }, + "require-directory": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/require-directory/-/require-directory-2.1.1.tgz", + "integrity": "sha1-jGStX9MNqxyXbiNE/+f3kqam30I=", + "dev": true + }, + "require-main-filename": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/require-main-filename/-/require-main-filename-1.0.1.tgz", + "integrity": "sha1-l/cXtp1IeE9fUmpsWqj/3aBVpNE=", + "dev": true + }, + "resolve": { + "version": "1.11.0", + "resolved": "https://registry.npmjs.org/resolve/-/resolve-1.11.0.tgz", + "integrity": "sha512-WL2pBDjqT6pGUNSUzMw00o4T7If+z4H2x3Gz893WoUQ5KW8Vr9txp00ykiP16VBaZF5+j/OcXJHZ9+PCvdiDKw==", + "dev": true, + "requires": { + "path-parse": "^1.0.6" + } + }, + "resolve-dir": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/resolve-dir/-/resolve-dir-1.0.1.tgz", + "integrity": "sha1-eaQGRMNivoLybv/nOcm7U4IEb0M=", + "dev": true, + "requires": { + "expand-tilde": "^2.0.0", + "global-modules": "^1.0.0" + } + }, + "resolve-options": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/resolve-options/-/resolve-options-1.1.0.tgz", + "integrity": "sha1-MrueOcBtZzONyTeMDW1gdFZq0TE=", + "dev": true, + "requires": { + "value-or-function": "^3.0.0" + } + }, + "resolve-url": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/resolve-url/-/resolve-url-0.2.1.tgz", + "integrity": "sha1-LGN/53yJOv0qZj/iGqkIAGjiBSo=", + "dev": true + }, + "ret": { + "version": "0.1.15", + "resolved": "https://registry.npmjs.org/ret/-/ret-0.1.15.tgz", + "integrity": "sha512-TTlYpa+OL+vMMNG24xSlQGEJ3B/RzEfUlLct7b5G/ytav+wPrplCpVMFuwzXbkecJrb6IYo1iFb0S9v37754mg==", + "dev": true + }, + "rimraf": { + "version": "2.6.3", + "resolved": "https://registry.npmjs.org/rimraf/-/rimraf-2.6.3.tgz", + "integrity": "sha512-mwqeW5XsA2qAejG46gYdENaxXjx9onRNCfn7L0duuP4hCuTIi/QO7PDK07KJfp1d+izWPrzEJDcSqBa0OZQriA==", + "dev": true, + "requires": { + "glob": "^7.1.3" + } + }, + "ripemd160": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/ripemd160/-/ripemd160-2.0.2.tgz", + "integrity": "sha512-ii4iagi25WusVoiC4B4lq7pbXfAp3D9v5CwfkY33vffw2+pkDjY1D8GaN7spsxvCSx8dkPqOZCEZyfxcmJG2IA==", + "dev": true, + "requires": { + "hash-base": "^3.0.0", + "inherits": "^2.0.1" + } + }, + "run-queue": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/run-queue/-/run-queue-1.0.3.tgz", + "integrity": "sha1-6Eg5bwV9Ij8kOGkkYY4laUFh7Ec=", + "dev": true, + "requires": { + "aproba": "^1.1.1" + } + }, + "safe-buffer": { + "version": "5.1.2", + "resolved": "https://registry.npmjs.org/safe-buffer/-/safe-buffer-5.1.2.tgz", + "integrity": "sha512-Gd2UZBJDkXlY7GbJxfsE8/nvKkUEU1G38c1siN6QP6a9PT9MmHB8GnpscSmMJSoF8LOIrt8ud/wPtojys4G6+g==", + "dev": true + }, + "safe-regex": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/safe-regex/-/safe-regex-1.1.0.tgz", + "integrity": "sha1-QKNmnzsHfR6UPURinhV91IAjvy4=", + "dev": true, + "requires": { + "ret": "~0.1.10" + } + }, + "safer-buffer": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/safer-buffer/-/safer-buffer-2.1.2.tgz", + "integrity": "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg==", + "dev": true + }, + "sass-graph": { + "version": "2.2.4", + "resolved": "https://registry.npmjs.org/sass-graph/-/sass-graph-2.2.4.tgz", + "integrity": "sha1-E/vWPNHK8JCLn9k0dq1DpR0eC0k=", + "dev": true, + "requires": { + "glob": "^7.0.0", + "lodash": "^4.0.0", + "scss-tokenizer": "^0.2.3", + "yargs": "^7.0.0" + } + }, + "schema-utils": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/schema-utils/-/schema-utils-1.0.0.tgz", + "integrity": "sha512-i27Mic4KovM/lnGsy8whRCHhc7VicJajAjTrYg11K9zfZXnYIt4k5F+kZkwjnrhKzLic/HLU4j11mjsz2G/75g==", + "dev": true, + "requires": { + "ajv": "^6.1.0", + "ajv-errors": "^1.0.0", + "ajv-keywords": "^3.1.0" + } + }, + "scss-tokenizer": { + "version": "0.2.3", + "resolved": "https://registry.npmjs.org/scss-tokenizer/-/scss-tokenizer-0.2.3.tgz", + "integrity": "sha1-jrBtualyMzOCTT9VMGQRSYR85dE=", + "dev": true, + "requires": { + "js-base64": "^2.1.8", + "source-map": "^0.4.2" + }, + "dependencies": { + "source-map": { + "version": "0.4.4", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.4.4.tgz", + "integrity": "sha1-66T12pwNyZneaAMti092FzZSA2s=", + "dev": true, + "requires": { + "amdefine": ">=0.0.4" + } + } + } + }, + "semver": { + "version": "5.6.0", + "resolved": "https://registry.npmjs.org/semver/-/semver-5.6.0.tgz", + "integrity": "sha512-RS9R6R35NYgQn++fkDWaOmqGoj4Ek9gGs+DPxNUZKuwE183xjJroKvyo1IzVFeXvUrvmALy6FWD5xrdJT25gMg==", + "dev": true + }, + "semver-greatest-satisfied-range": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/semver-greatest-satisfied-range/-/semver-greatest-satisfied-range-1.1.0.tgz", + "integrity": "sha1-E+jCZYq5aRywzXEJMkAoDTb3els=", + "dev": true, + "requires": { + "sver-compat": "^1.5.0" + } + }, + "serialize-javascript": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/serialize-javascript/-/serialize-javascript-2.1.2.tgz", + "integrity": "sha512-rs9OggEUF0V4jUSecXazOYsLfu7OGK2qIn3c7IPBiffz32XniEp/TX9Xmc9LQfK2nQ2QKHvZ2oygKUGU0lG4jQ==", + "dev": true + }, + "set-blocking": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/set-blocking/-/set-blocking-2.0.0.tgz", + "integrity": "sha1-BF+XgtARrppoA93TgrJDkrPYkPc=", + "dev": true + }, + "set-value": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/set-value/-/set-value-2.0.1.tgz", + "integrity": "sha512-JxHc1weCN68wRY0fhCoXpyK55m/XPHafOmK4UWD7m2CI14GMcFypt4w/0+NV5f/ZMby2F6S2wwA7fgynh9gWSw==", + "dev": true, + "requires": { + "extend-shallow": "^2.0.1", + "is-extendable": "^0.1.1", + "is-plain-object": "^2.0.3", + "split-string": "^3.0.1" + }, + "dependencies": { + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "setimmediate": { + "version": "1.0.5", + "resolved": "https://registry.npmjs.org/setimmediate/-/setimmediate-1.0.5.tgz", + "integrity": "sha1-KQy7Iy4waULX1+qbg3Mqt4VvgoU=", + "dev": true + }, + "sha.js": { + "version": "2.4.11", + "resolved": "https://registry.npmjs.org/sha.js/-/sha.js-2.4.11.tgz", + "integrity": "sha512-QMEp5B7cftE7APOjk5Y6xgrbWu+WkLVQwk8JNjZ8nKRciZaByEW6MubieAiToS7+dwvrjGhH8jRXz3MVd0AYqQ==", + "dev": true, + "requires": { + "inherits": "^2.0.1", + "safe-buffer": "^5.0.1" + } + }, + "signal-exit": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/signal-exit/-/signal-exit-3.0.2.tgz", + "integrity": "sha1-tf3AjxKH6hF4Yo5BXiUTK3NkbG0=", + "dev": true + }, + "snapdragon": { + "version": "0.8.2", + "resolved": "https://registry.npmjs.org/snapdragon/-/snapdragon-0.8.2.tgz", + "integrity": "sha512-FtyOnWN/wCHTVXOMwvSv26d+ko5vWlIDD6zoUJ7LW8vh+ZBC8QdljveRP+crNrtBwioEUWy/4dMtbBjA4ioNlg==", + "dev": true, + "requires": { + "base": "^0.11.1", + "debug": "^2.2.0", + "define-property": "^0.2.5", + "extend-shallow": "^2.0.1", + "map-cache": "^0.2.2", + "source-map": "^0.5.6", + "source-map-resolve": "^0.5.0", + "use": "^3.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + }, + "extend-shallow": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/extend-shallow/-/extend-shallow-2.0.1.tgz", + "integrity": "sha1-Ua99YUrZqfYQ6huvu5idaxxWiQ8=", + "dev": true, + "requires": { + "is-extendable": "^0.1.0" + } + } + } + }, + "snapdragon-node": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/snapdragon-node/-/snapdragon-node-2.1.1.tgz", + "integrity": "sha512-O27l4xaMYt/RSQ5TR3vpWCAB5Kb/czIcqUFOM/C4fYcLnbZUc1PkjTAMjof2pBWaSTwOUd6qUHcFGVGj7aIwnw==", + "dev": true, + "requires": { + "define-property": "^1.0.0", + "isobject": "^3.0.0", + "snapdragon-util": "^3.0.1" + }, + "dependencies": { + "define-property": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-1.0.0.tgz", + "integrity": "sha1-dp66rz9KY6rTr56NMEybvnm/sOY=", + "dev": true, + "requires": { + "is-descriptor": "^1.0.0" + } + }, + "is-accessor-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-accessor-descriptor/-/is-accessor-descriptor-1.0.0.tgz", + "integrity": "sha512-m5hnHTkcVsPfqx3AKlyttIPb7J+XykHvJP2B9bZDjlhLIoEq4XoK64Vg7boZlVWYK6LUY94dYPEE7Lh0ZkZKcQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-data-descriptor": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/is-data-descriptor/-/is-data-descriptor-1.0.0.tgz", + "integrity": "sha512-jbRXy1FmtAoCjQkVmIVYwuuqDFUbaOeDjmed1tOGPrsMhtJA4rD9tkgA0F1qJ3gRFRXcHYVkdeaP50Q5rE/jLQ==", + "dev": true, + "requires": { + "kind-of": "^6.0.0" + } + }, + "is-descriptor": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/is-descriptor/-/is-descriptor-1.0.2.tgz", + "integrity": "sha512-2eis5WqQGV7peooDyLmNEPUrps9+SXX5c9pL3xEB+4e9HnGuDa7mB7kHxHw4CbqS9k1T2hOH3miL8n8WtiYVtg==", + "dev": true, + "requires": { + "is-accessor-descriptor": "^1.0.0", + "is-data-descriptor": "^1.0.0", + "kind-of": "^6.0.2" + } + } + } + }, + "snapdragon-util": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/snapdragon-util/-/snapdragon-util-3.0.1.tgz", + "integrity": "sha512-mbKkMdQKsjX4BAL4bRYTj21edOf8cN7XHdYUJEe+Zn99hVEYcMvKPct1IqNe7+AZPirn8BCDOQBHQZknqmKlZQ==", + "dev": true, + "requires": { + "kind-of": "^3.2.0" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "source-list-map": { + "version": "2.0.1", + "resolved": "https://registry.npmjs.org/source-list-map/-/source-list-map-2.0.1.tgz", + "integrity": "sha512-qnQ7gVMxGNxsiL4lEuJwe/To8UnK7fAnmbGEEH8RpLouuKbeEm0lhbQVFIrNSuB+G7tVrAlVsZgETT5nljf+Iw==", + "dev": true + }, + "source-map": { + "version": "0.5.7", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.5.7.tgz", + "integrity": "sha1-igOdLRAh0i0eoUyA2OpGi6LvP8w=", + "dev": true + }, + "source-map-resolve": { + "version": "0.5.2", + "resolved": "https://registry.npmjs.org/source-map-resolve/-/source-map-resolve-0.5.2.tgz", + "integrity": "sha512-MjqsvNwyz1s0k81Goz/9vRBe9SZdB09Bdw+/zYyO+3CuPk6fouTaxscHkgtE8jKvf01kVfl8riHzERQ/kefaSA==", + "dev": true, + "requires": { + "atob": "^2.1.1", + "decode-uri-component": "^0.2.0", + "resolve-url": "^0.2.1", + "source-map-url": "^0.4.0", + "urix": "^0.1.0" + } + }, + "source-map-support": { + "version": "0.5.16", + "resolved": "https://registry.npmjs.org/source-map-support/-/source-map-support-0.5.16.tgz", + "integrity": "sha512-efyLRJDr68D9hBBNIPWFjhpFzURh+KJykQwvMyW5UiZzYwoF6l4YMMDIJJEyFWxWCqfyxLzz6tSfUFR+kXXsVQ==", + "dev": true, + "requires": { + "buffer-from": "^1.0.0", + "source-map": "^0.6.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "source-map-url": { + "version": "0.4.0", + "resolved": "https://registry.npmjs.org/source-map-url/-/source-map-url-0.4.0.tgz", + "integrity": "sha1-PpNdfd1zYxuXZZlW1VEo6HtQhKM=", + "dev": true + }, + "sparkles": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/sparkles/-/sparkles-1.0.1.tgz", + "integrity": "sha512-dSO0DDYUahUt/0/pD/Is3VIm5TGJjludZ0HVymmhYF6eNA53PVLhnUk0znSYbH8IYBuJdCE+1luR22jNLMaQdw==", + "dev": true + }, + "spdx-correct": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/spdx-correct/-/spdx-correct-3.1.0.tgz", + "integrity": "sha512-lr2EZCctC2BNR7j7WzJ2FpDznxky1sjfxvvYEyzxNyb6lZXHODmEoJeFu4JupYlkfha1KZpJyoqiJ7pgA1qq8Q==", + "dev": true, + "requires": { + "spdx-expression-parse": "^3.0.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-exceptions": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/spdx-exceptions/-/spdx-exceptions-2.2.0.tgz", + "integrity": "sha512-2XQACfElKi9SlVb1CYadKDXvoajPgBVPn/gOQLrTvHdElaVhr7ZEbqJaRnJLVNeaI4cMEAgVCeBMKF6MWRDCRA==", + "dev": true + }, + "spdx-expression-parse": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/spdx-expression-parse/-/spdx-expression-parse-3.0.0.tgz", + "integrity": "sha512-Yg6D3XpRD4kkOmTpdgbUiEJFKghJH03fiC1OPll5h/0sO6neh2jqRDVHOQ4o/LMea0tgCkbMgea5ip/e+MkWyg==", + "dev": true, + "requires": { + "spdx-exceptions": "^2.1.0", + "spdx-license-ids": "^3.0.0" + } + }, + "spdx-license-ids": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/spdx-license-ids/-/spdx-license-ids-3.0.3.tgz", + "integrity": "sha512-uBIcIl3Ih6Phe3XHK1NqboJLdGfwr1UN3k6wSD1dZpmPsIkb8AGNbZYJ1fOBk834+Gxy8rpfDxrS6XLEMZMY2g==", + "dev": true + }, + "split-string": { + "version": "3.1.0", + "resolved": "https://registry.npmjs.org/split-string/-/split-string-3.1.0.tgz", + "integrity": "sha512-NzNVhJDYpwceVVii8/Hu6DKfD2G+NrQHlS/V/qgv763EYudVwEcMQNxd2lh+0VrUByXN/oJkl5grOhYWvQUYiw==", + "dev": true, + "requires": { + "extend-shallow": "^3.0.0" + } + }, + "sshpk": { + "version": "1.16.1", + "resolved": "https://registry.npmjs.org/sshpk/-/sshpk-1.16.1.tgz", + "integrity": "sha512-HXXqVUq7+pcKeLqqZj6mHFUMvXtOJt1uoUx09pFW6011inTMxqI8BA8PM95myrIyyKwdnzjdFjLiE6KBPVtJIg==", + "dev": true, + "requires": { + "asn1": "~0.2.3", + "assert-plus": "^1.0.0", + "bcrypt-pbkdf": "^1.0.0", + "dashdash": "^1.12.0", + "ecc-jsbn": "~0.1.1", + "getpass": "^0.1.1", + "jsbn": "~0.1.0", + "safer-buffer": "^2.0.2", + "tweetnacl": "~0.14.0" + } + }, + "ssri": { + "version": "6.0.1", + "resolved": "https://registry.npmjs.org/ssri/-/ssri-6.0.1.tgz", + "integrity": "sha512-3Wge10hNcT1Kur4PDFwEieXSCMCJs/7WvSACcrMYrNp+b8kDL1/0wJch5Ni2WrtwEa2IO8OsVfeKIciKCDx/QA==", + "dev": true, + "requires": { + "figgy-pudding": "^3.5.1" + } + }, + "stack-trace": { + "version": "0.0.10", + "resolved": "https://registry.npmjs.org/stack-trace/-/stack-trace-0.0.10.tgz", + "integrity": "sha1-VHxws0fo0ytOEI6hoqFZ5f3eGcA=", + "dev": true + }, + "static-extend": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/static-extend/-/static-extend-0.1.2.tgz", + "integrity": "sha1-YICcOcv/VTNyJv1eC1IPNB8ftcY=", + "dev": true, + "requires": { + "define-property": "^0.2.5", + "object-copy": "^0.1.0" + }, + "dependencies": { + "define-property": { + "version": "0.2.5", + "resolved": "https://registry.npmjs.org/define-property/-/define-property-0.2.5.tgz", + "integrity": "sha1-w1se+RjsPJkPmlvFe+BKrOxcgRY=", + "dev": true, + "requires": { + "is-descriptor": "^0.1.0" + } + } + } + }, + "stdout-stream": { + "version": "1.4.1", + "resolved": "https://registry.npmjs.org/stdout-stream/-/stdout-stream-1.4.1.tgz", + "integrity": "sha512-j4emi03KXqJWcIeF8eIXkjMFN1Cmb8gUlDYGeBALLPo5qdyTfA9bOtl8m33lRoC+vFMkP3gl0WsDr6+gzxbbTA==", + "dev": true, + "requires": { + "readable-stream": "^2.0.1" + } + }, + "stream-browserify": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/stream-browserify/-/stream-browserify-2.0.2.tgz", + "integrity": "sha512-nX6hmklHs/gr2FuxYDltq8fJA1GDlxKQCz8O/IM4atRqBH8OORmBNgfvW5gG10GT/qQ9u0CzIvr2X5Pkt6ntqg==", + "dev": true, + "requires": { + "inherits": "~2.0.1", + "readable-stream": "^2.0.2" + } + }, + "stream-each": { + "version": "1.2.3", + "resolved": "https://registry.npmjs.org/stream-each/-/stream-each-1.2.3.tgz", + "integrity": "sha512-vlMC2f8I2u/bZGqkdfLQW/13Zihpej/7PmSiMQsbYddxuTsJp8vRe2x2FvVExZg7FaOds43ROAuFJwPR4MTZLw==", + "dev": true, + "requires": { + "end-of-stream": "^1.1.0", + "stream-shift": "^1.0.0" + } + }, + "stream-exhaust": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/stream-exhaust/-/stream-exhaust-1.0.2.tgz", + "integrity": "sha512-b/qaq/GlBK5xaq1yrK9/zFcyRSTNxmcZwFLGSTG0mXgZl/4Z6GgiyYOXOvY7N3eEvFRAG1bkDRz5EPGSvPYQlw==", + "dev": true + }, + "stream-http": { + "version": "2.8.3", + "resolved": "https://registry.npmjs.org/stream-http/-/stream-http-2.8.3.tgz", + "integrity": "sha512-+TSkfINHDo4J+ZobQLWiMouQYB+UVYFttRA94FpEzzJ7ZdqcL4uUUQ7WkdkI4DSozGmgBUE/a47L+38PenXhUw==", + "dev": true, + "requires": { + "builtin-status-codes": "^3.0.0", + "inherits": "^2.0.1", + "readable-stream": "^2.3.6", + "to-arraybuffer": "^1.0.0", + "xtend": "^4.0.0" + } + }, + "stream-shift": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/stream-shift/-/stream-shift-1.0.0.tgz", + "integrity": "sha1-1cdSgl5TZ+eG944Y5EXqIjoVWVI=", + "dev": true + }, + "string-width": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/string-width/-/string-width-1.0.2.tgz", + "integrity": "sha1-EYvfW4zcUaKn5w0hHgfisLmxB9M=", + "dev": true, + "requires": { + "code-point-at": "^1.0.0", + "is-fullwidth-code-point": "^1.0.0", + "strip-ansi": "^3.0.0" + } + }, + "string_decoder": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/string_decoder/-/string_decoder-1.1.1.tgz", + "integrity": "sha512-n/ShnvDi6FHbbVfviro+WojiFzv+s8MPMHBczVePfUpDJLwoLT0ht1l4YwBCbi8pJAveEEdnkHyPyTP/mzRfwg==", + "dev": true, + "requires": { + "safe-buffer": "~5.1.0" + } + }, + "strip-ansi": { + "version": "3.0.1", + "resolved": "https://registry.npmjs.org/strip-ansi/-/strip-ansi-3.0.1.tgz", + "integrity": "sha1-ajhfuIU9lS1f8F0Oiq+UJ43GPc8=", + "dev": true, + "requires": { + "ansi-regex": "^2.0.0" + } + }, + "strip-bom": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/strip-bom/-/strip-bom-2.0.0.tgz", + "integrity": "sha1-YhmoVhZSBJHzV4i9vxRHqZx+aw4=", + "dev": true, + "requires": { + "is-utf8": "^0.2.0" + } + }, + "strip-indent": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/strip-indent/-/strip-indent-1.0.1.tgz", + "integrity": "sha1-DHlipq3vp7vUrDZkYKY4VSrhoKI=", + "dev": true, + "requires": { + "get-stdin": "^4.0.1" + } + }, + "supports-color": { + "version": "6.1.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-6.1.0.tgz", + "integrity": "sha512-qe1jfm1Mg7Nq/NSh6XE24gPXROEVsWHxC1LIx//XNlD9iw7YZQGjZNjYN7xGaEG6iKdA8EtNFW6R0gjnVXp+wQ==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + }, + "sver-compat": { + "version": "1.5.0", + "resolved": "https://registry.npmjs.org/sver-compat/-/sver-compat-1.5.0.tgz", + "integrity": "sha1-PPh9/rTQe0o/FIJ7wYaz/QxkXNg=", + "dev": true, + "requires": { + "es6-iterator": "^2.0.1", + "es6-symbol": "^3.1.1" + } + }, + "tapable": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/tapable/-/tapable-1.1.3.tgz", + "integrity": "sha512-4WK/bYZmj8xLr+HUCODHGF1ZFzsYffasLUgEiMBY4fgtltdO6B4WJtlSbPaDTLpYTcGVwM2qLnFTICEcNxs3kA==", + "dev": true + }, + "tar": { + "version": "2.2.2", + "resolved": "https://registry.npmjs.org/tar/-/tar-2.2.2.tgz", + "integrity": "sha512-FCEhQ/4rE1zYv9rYXJw/msRqsnmlje5jHP6huWeBZ704jUTy02c5AZyWujpMR1ax6mVw9NyJMfuK2CMDWVIfgA==", + "dev": true, + "requires": { + "block-stream": "*", + "fstream": "^1.0.12", + "inherits": "2" + } + }, + "terser": { + "version": "4.4.2", + "resolved": "https://registry.npmjs.org/terser/-/terser-4.4.2.tgz", + "integrity": "sha512-Uufrsvhj9O1ikwgITGsZ5EZS6qPokUOkCegS7fYOdGTv+OA90vndUbU6PEjr5ePqHfNUbGyMO7xyIZv2MhsALQ==", + "dev": true, + "requires": { + "commander": "^2.20.0", + "source-map": "~0.6.1", + "source-map-support": "~0.5.12" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "terser-webpack-plugin": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/terser-webpack-plugin/-/terser-webpack-plugin-1.4.3.tgz", + "integrity": "sha512-QMxecFz/gHQwteWwSo5nTc6UaICqN1bMedC5sMtUc7y3Ha3Q8y6ZO0iCR8pq4RJC8Hjf0FEPEHZqcMB/+DFCrA==", + "dev": true, + "requires": { + "cacache": "^12.0.2", + "find-cache-dir": "^2.1.0", + "is-wsl": "^1.1.0", + "schema-utils": "^1.0.0", + "serialize-javascript": "^2.1.2", + "source-map": "^0.6.1", + "terser": "^4.1.2", + "webpack-sources": "^1.4.0", + "worker-farm": "^1.7.0" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "through": { + "version": "2.3.8", + "resolved": "https://registry.npmjs.org/through/-/through-2.3.8.tgz", + "integrity": "sha1-DdTJ/6q8NXlgsbckEV1+Doai4fU=", + "dev": true + }, + "through2": { + "version": "2.0.5", + "resolved": "https://registry.npmjs.org/through2/-/through2-2.0.5.tgz", + "integrity": "sha512-/mrRod8xqpA+IHSLyGCQ2s8SPHiCDEeQJSep1jqLYeEUClOFG2Qsh+4FU6G9VeqpZnGW/Su8LQGc4YKni5rYSQ==", + "dev": true, + "requires": { + "readable-stream": "~2.3.6", + "xtend": "~4.0.1" + } + }, + "through2-filter": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/through2-filter/-/through2-filter-3.0.0.tgz", + "integrity": "sha512-jaRjI2WxN3W1V8/FMZ9HKIBXixtiqs3SQSX4/YGIiP3gL6djW48VoZq9tDqeCWs3MT8YY5wb/zli8VW8snY1CA==", + "dev": true, + "requires": { + "through2": "~2.0.0", + "xtend": "~4.0.0" + } + }, + "time-stamp": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/time-stamp/-/time-stamp-1.1.0.tgz", + "integrity": "sha1-dkpaEa9QVhkhsTPztE5hhofg9cM=", + "dev": true + }, + "timers-browserify": { + "version": "2.0.11", + "resolved": "https://registry.npmjs.org/timers-browserify/-/timers-browserify-2.0.11.tgz", + "integrity": "sha512-60aV6sgJ5YEbzUdn9c8kYGIqOubPoUdqQCul3SBAsRCZ40s6Y5cMcrW4dt3/k/EsbLVJNl9n6Vz3fTc+k2GeKQ==", + "dev": true, + "requires": { + "setimmediate": "^1.0.4" + } + }, + "to-absolute-glob": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/to-absolute-glob/-/to-absolute-glob-2.0.2.tgz", + "integrity": "sha1-GGX0PZ50sIItufFFt4z/fQ98hJs=", + "dev": true, + "requires": { + "is-absolute": "^1.0.0", + "is-negated-glob": "^1.0.0" + } + }, + "to-arraybuffer": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/to-arraybuffer/-/to-arraybuffer-1.0.1.tgz", + "integrity": "sha1-fSKbH8xjfkZsoIEYCDanqr/4P0M=", + "dev": true + }, + "to-object-path": { + "version": "0.3.0", + "resolved": "https://registry.npmjs.org/to-object-path/-/to-object-path-0.3.0.tgz", + "integrity": "sha1-KXWIt7Dn4KwI4E5nL4XB9JmeF68=", + "dev": true, + "requires": { + "kind-of": "^3.0.2" + }, + "dependencies": { + "kind-of": { + "version": "3.2.2", + "resolved": "https://registry.npmjs.org/kind-of/-/kind-of-3.2.2.tgz", + "integrity": "sha1-MeohpzS6ubuw8yRm2JOupR5KPGQ=", + "dev": true, + "requires": { + "is-buffer": "^1.1.5" + } + } + } + }, + "to-regex": { + "version": "3.0.2", + "resolved": "https://registry.npmjs.org/to-regex/-/to-regex-3.0.2.tgz", + "integrity": "sha512-FWtleNAtZ/Ki2qtqej2CXTOayOH9bHDQF+Q48VpWyDXjbYxA4Yz8iDB31zXOBUlOHHKidDbqGVrTUvQMPmBGBw==", + "dev": true, + "requires": { + "define-property": "^2.0.2", + "extend-shallow": "^3.0.2", + "regex-not": "^1.0.2", + "safe-regex": "^1.1.0" + } + }, + "to-regex-range": { + "version": "2.1.1", + "resolved": "https://registry.npmjs.org/to-regex-range/-/to-regex-range-2.1.1.tgz", + "integrity": "sha1-fIDBe53+vlmeJzZ+DU3VWQFB2zg=", + "dev": true, + "requires": { + "is-number": "^3.0.0", + "repeat-string": "^1.6.1" + } + }, + "to-through": { + "version": "2.0.0", + "resolved": "https://registry.npmjs.org/to-through/-/to-through-2.0.0.tgz", + "integrity": "sha1-/JKtq6ByZHvAtn1rA2ZKoZUJOvY=", + "dev": true, + "requires": { + "through2": "^2.0.3" + } + }, + "tough-cookie": { + "version": "2.5.0", + "resolved": "https://registry.npmjs.org/tough-cookie/-/tough-cookie-2.5.0.tgz", + "integrity": "sha512-nlLsUzgm1kfLXSXfRZMc1KLAugd4hqJHDTvc2hDIwS3mZAfMEuMbc03SujMF+GEcpaX/qboeycw6iO8JwVv2+g==", + "dev": true, + "requires": { + "psl": "^1.1.28", + "punycode": "^2.1.1" + } + }, + "trim-newlines": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/trim-newlines/-/trim-newlines-1.0.0.tgz", + "integrity": "sha1-WIeWa7WCpFA6QetST301ARgVphM=", + "dev": true + }, + "true-case-path": { + "version": "1.0.3", + "resolved": "https://registry.npmjs.org/true-case-path/-/true-case-path-1.0.3.tgz", + "integrity": "sha512-m6s2OdQe5wgpFMC+pAJ+q9djG82O2jcHPOI6RNg1yy9rCYR+WD6Nbpl32fDpfC56nirdRy+opFa/Vk7HYhqaew==", + "dev": true, + "requires": { + "glob": "^7.1.2" + } + }, + "tslib": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/tslib/-/tslib-1.10.0.tgz", + "integrity": "sha512-qOebF53frne81cf0S9B41ByenJ3/IuH8yJKngAX35CmiZySA0khhkovshKK+jGCaMnVomla7gVlIcc3EvKPbTQ==", + "dev": true + }, + "tty-browserify": { + "version": "0.0.0", + "resolved": "https://registry.npmjs.org/tty-browserify/-/tty-browserify-0.0.0.tgz", + "integrity": "sha1-oVe6QC2iTpv5V/mqadUk7tQpAaY=", + "dev": true + }, + "tunnel-agent": { + "version": "0.6.0", + "resolved": "https://registry.npmjs.org/tunnel-agent/-/tunnel-agent-0.6.0.tgz", + "integrity": "sha1-J6XeoGs2sEoKmWZ3SykIaPD8QP0=", + "dev": true, + "requires": { + "safe-buffer": "^5.0.1" + } + }, + "tweetnacl": { + "version": "0.14.5", + "resolved": "https://registry.npmjs.org/tweetnacl/-/tweetnacl-0.14.5.tgz", + "integrity": "sha1-WuaBd/GS1EViadEIr6k/+HQ/T2Q=", + "dev": true + }, + "typedarray": { + "version": "0.0.6", + "resolved": "https://registry.npmjs.org/typedarray/-/typedarray-0.0.6.tgz", + "integrity": "sha1-hnrHTjhkGHsdPUfZlqeOxciDB3c=", + "dev": true + }, + "typescript": { + "version": "3.4.5", + "resolved": "https://registry.npmjs.org/typescript/-/typescript-3.4.5.tgz", + "integrity": "sha512-YycBxUb49UUhdNMU5aJ7z5Ej2XGmaIBL0x34vZ82fn3hGvD+bgrMrVDpatgz2f7YxUMJxMkbWxJZeAvDxVe7Vw==", + "dev": true + }, + "unc-path-regex": { + "version": "0.1.2", + "resolved": "https://registry.npmjs.org/unc-path-regex/-/unc-path-regex-0.1.2.tgz", + "integrity": "sha1-5z3T17DXxe2G+6xrCufYxqadUPo=", + "dev": true + }, + "undertaker": { + "version": "1.2.1", + "resolved": "https://registry.npmjs.org/undertaker/-/undertaker-1.2.1.tgz", + "integrity": "sha512-71WxIzDkgYk9ZS+spIB8iZXchFhAdEo2YU8xYqBYJ39DIUIqziK78ftm26eecoIY49X0J2MLhG4hr18Yp6/CMA==", + "dev": true, + "requires": { + "arr-flatten": "^1.0.1", + "arr-map": "^2.0.0", + "bach": "^1.0.0", + "collection-map": "^1.0.0", + "es6-weak-map": "^2.0.1", + "last-run": "^1.1.0", + "object.defaults": "^1.0.0", + "object.reduce": "^1.0.0", + "undertaker-registry": "^1.0.0" + } + }, + "undertaker-registry": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/undertaker-registry/-/undertaker-registry-1.0.1.tgz", + "integrity": "sha1-XkvaMI5KiirlhPm5pDWaSZglzFA=", + "dev": true + }, + "union-value": { + "version": "1.0.1", + "resolved": "https://registry.npmjs.org/union-value/-/union-value-1.0.1.tgz", + "integrity": "sha512-tJfXmxMeWYnczCVs7XAEvIV7ieppALdyepWMkHkwciRpZraG/xwT+s2JN8+pr1+8jCRf80FFzvr+MpQeeoF4Xg==", + "dev": true, + "requires": { + "arr-union": "^3.1.0", + "get-value": "^2.0.6", + "is-extendable": "^0.1.1", + "set-value": "^2.0.1" + } + }, + "unique-filename": { + "version": "1.1.1", + "resolved": "https://registry.npmjs.org/unique-filename/-/unique-filename-1.1.1.tgz", + "integrity": "sha512-Vmp0jIp2ln35UTXuryvjzkjGdRyf9b2lTXuSYUiPmzRcl3FDtYqAwOnTJkAngD9SWhnoJzDbTKwaOrZ+STtxNQ==", + "dev": true, + "requires": { + "unique-slug": "^2.0.0" + } + }, + "unique-slug": { + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/unique-slug/-/unique-slug-2.0.2.tgz", + "integrity": "sha512-zoWr9ObaxALD3DOPfjPSqxt4fnZiWblxHIgeWqW8x7UqDzEtHEQLzji2cuJYQFCU6KmoJikOYAZlrTHHebjx2w==", + "dev": true, + "requires": { + "imurmurhash": "^0.1.4" + } + }, + "unique-stream": { + "version": "2.3.1", + "resolved": "https://registry.npmjs.org/unique-stream/-/unique-stream-2.3.1.tgz", + "integrity": "sha512-2nY4TnBE70yoxHkDli7DMazpWiP7xMdCYqU2nBRO0UB+ZpEkGsSija7MvmvnZFUeC+mrgiUfcHSr3LmRFIg4+A==", + "dev": true, + "requires": { + "json-stable-stringify-without-jsonify": "^1.0.1", + "through2-filter": "^3.0.0" + } + }, + "unset-value": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/unset-value/-/unset-value-1.0.0.tgz", + "integrity": "sha1-g3aHP30jNRef+x5vw6jtDfyKtVk=", + "dev": true, + "requires": { + "has-value": "^0.3.1", + "isobject": "^3.0.0" + }, + "dependencies": { + "has-value": { + "version": "0.3.1", + "resolved": "https://registry.npmjs.org/has-value/-/has-value-0.3.1.tgz", + "integrity": "sha1-ex9YutpiyoJ+wKIHgCVlSEWZXh8=", + "dev": true, + "requires": { + "get-value": "^2.0.3", + "has-values": "^0.1.4", + "isobject": "^2.0.0" + }, + "dependencies": { + "isobject": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/isobject/-/isobject-2.1.0.tgz", + "integrity": "sha1-8GVWEJaj8dou9GJy+BXIQNh+DIk=", + "dev": true, + "requires": { + "isarray": "1.0.0" + } + } + } + }, + "has-values": { + "version": "0.1.4", + "resolved": "https://registry.npmjs.org/has-values/-/has-values-0.1.4.tgz", + "integrity": "sha1-bWHeldkd/Km5oCCJrThL/49it3E=", + "dev": true + } + } + }, + "upath": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/upath/-/upath-1.1.0.tgz", + "integrity": "sha512-bzpH/oBhoS/QI/YtbkqCg6VEiPYjSZtrHQM6/QnJS6OL9pKUFLqb3aFh4Scvwm45+7iAgiMkLhSbaZxUqmrprw==", + "dev": true + }, + "uri-js": { + "version": "4.2.2", + "resolved": "https://registry.npmjs.org/uri-js/-/uri-js-4.2.2.tgz", + "integrity": "sha512-KY9Frmirql91X2Qgjry0Wd4Y+YTdrdZheS8TFwvkbLWf/G5KNJDCh6pKL5OZctEW4+0Baa5idK2ZQuELRwPznQ==", + "dev": true, + "requires": { + "punycode": "^2.1.0" + } + }, + "urix": { + "version": "0.1.0", + "resolved": "https://registry.npmjs.org/urix/-/urix-0.1.0.tgz", + "integrity": "sha1-2pN/emLiH+wf0Y1Js1wpNQZ6bHI=", + "dev": true + }, + "url": { + "version": "0.11.0", + "resolved": "https://registry.npmjs.org/url/-/url-0.11.0.tgz", + "integrity": "sha1-ODjpfPxgUh63PFJajlW/3Z4uKPE=", + "dev": true, + "requires": { + "punycode": "1.3.2", + "querystring": "0.2.0" + }, + "dependencies": { + "punycode": { + "version": "1.3.2", + "resolved": "https://registry.npmjs.org/punycode/-/punycode-1.3.2.tgz", + "integrity": "sha1-llOgNvt8HuQjQvIyXM7v6jkmxI0=", + "dev": true + } + } + }, + "use": { + "version": "3.1.1", + "resolved": "https://registry.npmjs.org/use/-/use-3.1.1.tgz", + "integrity": "sha512-cwESVXlO3url9YWlFW/TA9cshCEhtu7IKJ/p5soJ/gGpj7vbvFrAY/eIioQ6Dw23KjZhYgiIo8HOs1nQ2vr/oQ==", + "dev": true + }, + "util": { + "version": "0.11.1", + "resolved": "https://registry.npmjs.org/util/-/util-0.11.1.tgz", + "integrity": "sha512-HShAsny+zS2TZfaXxD9tYj4HQGlBezXZMZuM/S5PKLLoZkShZiGk9o5CzukI1LVHZvjdvZ2Sj1aW/Ndn2NB/HQ==", + "dev": true, + "requires": { + "inherits": "2.0.3" + } + }, + "util-deprecate": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/util-deprecate/-/util-deprecate-1.0.2.tgz", + "integrity": "sha1-RQ1Nyfpw3nMnYvvS1KKJgUGaDM8=", + "dev": true + }, + "uuid": { + "version": "3.4.0", + "resolved": "https://registry.npmjs.org/uuid/-/uuid-3.4.0.tgz", + "integrity": "sha512-HjSDRw6gZE5JMggctHBcjVak08+KEVhSIiDzFnT9S9aegmp85S/bReBVTb4QTFaRNptJ9kuYaNhnbNEOkbKb/A==", + "dev": true + }, + "v8flags": { + "version": "3.1.3", + "resolved": "https://registry.npmjs.org/v8flags/-/v8flags-3.1.3.tgz", + "integrity": "sha512-amh9CCg3ZxkzQ48Mhcb8iX7xpAfYJgePHxWMQCBWECpOSqJUXgY26ncA61UTV0BkPqfhcy6mzwCIoP4ygxpW8w==", + "dev": true, + "requires": { + "homedir-polyfill": "^1.0.1" + } + }, + "validate-npm-package-license": { + "version": "3.0.4", + "resolved": "https://registry.npmjs.org/validate-npm-package-license/-/validate-npm-package-license-3.0.4.tgz", + "integrity": "sha512-DpKm2Ui/xN7/HQKCtpZxoRWBhZ9Z0kqtygG8XCgNQ8ZlDnxuQmWhj566j8fN4Cu3/JmbhsDo7fcAJq4s9h27Ew==", + "dev": true, + "requires": { + "spdx-correct": "^3.0.0", + "spdx-expression-parse": "^3.0.0" + } + }, + "value-or-function": { + "version": "3.0.0", + "resolved": "https://registry.npmjs.org/value-or-function/-/value-or-function-3.0.0.tgz", + "integrity": "sha1-HCQ6ULWVwb5Up1S/7OhWO5/42BM=", + "dev": true + }, + "verror": { + "version": "1.10.0", + "resolved": "https://registry.npmjs.org/verror/-/verror-1.10.0.tgz", + "integrity": "sha1-OhBcoXBTr1XW4nDB+CiGguGNpAA=", + "dev": true, + "requires": { + "assert-plus": "^1.0.0", + "core-util-is": "1.0.2", + "extsprintf": "^1.2.0" + } + }, + "vinyl": { + "version": "2.2.0", + "resolved": "https://registry.npmjs.org/vinyl/-/vinyl-2.2.0.tgz", + "integrity": "sha512-MBH+yP0kC/GQ5GwBqrTPTzEfiiLjta7hTtvQtbxBgTeSXsmKQRQecjibMbxIXzVT3Y9KJK+drOz1/k+vsu8Nkg==", + "dev": true, + "requires": { + "clone": "^2.1.1", + "clone-buffer": "^1.0.0", + "clone-stats": "^1.0.0", + "cloneable-readable": "^1.0.0", + "remove-trailing-separator": "^1.0.1", + "replace-ext": "^1.0.0" + } + }, + "vinyl-fs": { + "version": "3.0.3", + "resolved": "https://registry.npmjs.org/vinyl-fs/-/vinyl-fs-3.0.3.tgz", + "integrity": "sha512-vIu34EkyNyJxmP0jscNzWBSygh7VWhqun6RmqVfXePrOwi9lhvRs//dOaGOTRUQr4tx7/zd26Tk5WeSVZitgng==", + "dev": true, + "requires": { + "fs-mkdirp-stream": "^1.0.0", + "glob-stream": "^6.1.0", + "graceful-fs": "^4.0.0", + "is-valid-glob": "^1.0.0", + "lazystream": "^1.0.0", + "lead": "^1.0.0", + "object.assign": "^4.0.4", + "pumpify": "^1.3.5", + "readable-stream": "^2.3.3", + "remove-bom-buffer": "^3.0.0", + "remove-bom-stream": "^1.2.0", + "resolve-options": "^1.1.0", + "through2": "^2.0.0", + "to-through": "^2.0.0", + "value-or-function": "^3.0.0", + "vinyl": "^2.0.0", + "vinyl-sourcemap": "^1.1.0" + } + }, + "vinyl-sourcemap": { + "version": "1.1.0", + "resolved": "https://registry.npmjs.org/vinyl-sourcemap/-/vinyl-sourcemap-1.1.0.tgz", + "integrity": "sha1-kqgAWTo4cDqM2xHYswCtS+Y7PhY=", + "dev": true, + "requires": { + "append-buffer": "^1.0.2", + "convert-source-map": "^1.5.0", + "graceful-fs": "^4.1.6", + "normalize-path": "^2.1.1", + "now-and-later": "^2.0.0", + "remove-bom-buffer": "^3.0.0", + "vinyl": "^2.0.0" + } + }, + "vinyl-sourcemaps-apply": { + "version": "0.2.1", + "resolved": "https://registry.npmjs.org/vinyl-sourcemaps-apply/-/vinyl-sourcemaps-apply-0.2.1.tgz", + "integrity": "sha1-q2VJ1h0XLCsbh75cUI0jnI74dwU=", + "dev": true, + "requires": { + "source-map": "^0.5.1" + } + }, + "vm-browserify": { + "version": "1.1.2", + "resolved": "https://registry.npmjs.org/vm-browserify/-/vm-browserify-1.1.2.tgz", + "integrity": "sha512-2ham8XPWTONajOR0ohOKOHXkm3+gaBmGut3SRuu75xLd/RRaY6vqgh8NBYYk7+RW3u5AtzPQZG8F10LHkl0lAQ==", + "dev": true + }, + "watchpack": { + "version": "1.6.0", + "resolved": "https://registry.npmjs.org/watchpack/-/watchpack-1.6.0.tgz", + "integrity": "sha512-i6dHe3EyLjMmDlU1/bGQpEw25XSjkJULPuAVKCbNRefQVq48yXKUpwg538F7AZTf9kyr57zj++pQFltUa5H7yA==", + "dev": true, + "requires": { + "chokidar": "^2.0.2", + "graceful-fs": "^4.1.2", + "neo-async": "^2.5.0" + } + }, + "webpack": { + "version": "4.41.2", + "resolved": "https://registry.npmjs.org/webpack/-/webpack-4.41.2.tgz", + "integrity": "sha512-Zhw69edTGfbz9/8JJoyRQ/pq8FYUoY0diOXqW0T6yhgdhCv6wr0hra5DwwWexNRns2Z2+gsnrNcbe9hbGBgk/A==", + "dev": true, + "requires": { + "@webassemblyjs/ast": "1.8.5", + "@webassemblyjs/helper-module-context": "1.8.5", + "@webassemblyjs/wasm-edit": "1.8.5", + "@webassemblyjs/wasm-parser": "1.8.5", + "acorn": "^6.2.1", + "ajv": "^6.10.2", + "ajv-keywords": "^3.4.1", + "chrome-trace-event": "^1.0.2", + "enhanced-resolve": "^4.1.0", + "eslint-scope": "^4.0.3", + "json-parse-better-errors": "^1.0.2", + "loader-runner": "^2.4.0", + "loader-utils": "^1.2.3", + "memory-fs": "^0.4.1", + "micromatch": "^3.1.10", + "mkdirp": "^0.5.1", + "neo-async": "^2.6.1", + "node-libs-browser": "^2.2.1", + "schema-utils": "^1.0.0", + "tapable": "^1.1.3", + "terser-webpack-plugin": "^1.4.1", + "watchpack": "^1.6.0", + "webpack-sources": "^1.4.1" + }, + "dependencies": { + "ajv": { + "version": "6.10.2", + "resolved": "https://registry.npmjs.org/ajv/-/ajv-6.10.2.tgz", + "integrity": "sha512-TXtUUEYHuaTEbLZWIKUr5pmBuhDLy+8KYtPYdcV8qC+pOZL+NKqYwvWSRrVXHn+ZmRRAu8vJTAznH7Oag6RVRw==", + "dev": true, + "requires": { + "fast-deep-equal": "^2.0.1", + "fast-json-stable-stringify": "^2.0.0", + "json-schema-traverse": "^0.4.1", + "uri-js": "^4.2.2" + } + } + } + }, + "webpack-sources": { + "version": "1.4.3", + "resolved": "https://registry.npmjs.org/webpack-sources/-/webpack-sources-1.4.3.tgz", + "integrity": "sha512-lgTS3Xhv1lCOKo7SA5TjKXMjpSM4sBjNV5+q2bqesbSPs5FjGmU6jjtBSkX9b4qW87vDIsCIlUPOEhbZrMdjeQ==", + "dev": true, + "requires": { + "source-list-map": "^2.0.0", + "source-map": "~0.6.1" + }, + "dependencies": { + "source-map": { + "version": "0.6.1", + "resolved": "https://registry.npmjs.org/source-map/-/source-map-0.6.1.tgz", + "integrity": "sha512-UjgapumWlbMhkBgzT7Ykc5YXUT46F0iKu8SGXq0bcwP5dz/h0Plj6enJqjz1Zbq2l5WaqYnrVbwWOWMyF3F47g==", + "dev": true + } + } + }, + "webpack-stream": { + "version": "5.2.1", + "resolved": "https://registry.npmjs.org/webpack-stream/-/webpack-stream-5.2.1.tgz", + "integrity": "sha512-WvyVU0K1/VB1NZ7JfsaemVdG0PXAQUqbjUNW4A58th4pULvKMQxG+y33HXTL02JvD56ko2Cub+E2NyPwrLBT/A==", + "dev": true, + "requires": { + "fancy-log": "^1.3.3", + "lodash.clone": "^4.3.2", + "lodash.some": "^4.2.2", + "memory-fs": "^0.4.1", + "plugin-error": "^1.0.1", + "supports-color": "^5.5.0", + "through": "^2.3.8", + "vinyl": "^2.1.0", + "webpack": "^4.26.1" + }, + "dependencies": { + "supports-color": { + "version": "5.5.0", + "resolved": "https://registry.npmjs.org/supports-color/-/supports-color-5.5.0.tgz", + "integrity": "sha512-QjVjwdXIt408MIiAqCX4oUKsgU2EqAGzs2Ppkm4aQYbjm+ZEWEcW4SfFNTr4uMNZma0ey4f5lgLrkB0aX0QMow==", + "dev": true, + "requires": { + "has-flag": "^3.0.0" + } + } + } + }, + "which": { + "version": "1.3.1", + "resolved": "https://registry.npmjs.org/which/-/which-1.3.1.tgz", + "integrity": "sha512-HxJdYWq1MTIQbJ3nw0cqssHoTNU267KlrDuGZ1WYlxDStUtKUhOaJmh112/TZmHxxUfuJqPXSOm7tDyas0OSIQ==", + "dev": true, + "requires": { + "isexe": "^2.0.0" + } + }, + "which-module": { + "version": "1.0.0", + "resolved": "https://registry.npmjs.org/which-module/-/which-module-1.0.0.tgz", + "integrity": "sha1-u6Y8qGGUiZT/MHc2CJ47lgJsKk8=", + "dev": true + }, + "wide-align": { + "version": "1.1.3", + "resolved": "https://registry.npmjs.org/wide-align/-/wide-align-1.1.3.tgz", + "integrity": "sha512-QGkOQc8XL6Bt5PwnsExKBPuMKBxnGxWWW3fU55Xt4feHozMUhdUMaBCk290qpm/wG5u/RSKzwdAC4i51YigihA==", + "dev": true, + "requires": { + "string-width": "^1.0.2 || 2" + } + }, + "worker-farm": { + "version": "1.7.0", + "resolved": "https://registry.npmjs.org/worker-farm/-/worker-farm-1.7.0.tgz", + "integrity": "sha512-rvw3QTZc8lAxyVrqcSGVm5yP/IJ2UcB3U0graE3LCFoZ0Yn2x4EoVSqJKdB/T5M+FLcRPjz4TDacRf3OCfNUzw==", + "dev": true, + "requires": { + "errno": "~0.1.7" + } + }, + "wrap-ansi": { + "version": "2.1.0", + "resolved": "https://registry.npmjs.org/wrap-ansi/-/wrap-ansi-2.1.0.tgz", + "integrity": "sha1-2Pw9KE3QV5T+hJc8rs3Rz4JP3YU=", + "dev": true, + "requires": { + "string-width": "^1.0.1", + "strip-ansi": "^3.0.1" + } + }, + "wrappy": { + "version": "1.0.2", + "resolved": "https://registry.npmjs.org/wrappy/-/wrappy-1.0.2.tgz", + "integrity": "sha1-tSQ9jz7BqjXxNkYFvA0QNuMKtp8=", + "dev": true + }, + "xtend": { + "version": "4.0.1", + "resolved": "https://registry.npmjs.org/xtend/-/xtend-4.0.1.tgz", + "integrity": "sha1-pcbVMr5lbiPbgg77lDofBJmNY68=", + "dev": true + }, + "y18n": { + "version": "3.2.1", + "resolved": "https://registry.npmjs.org/y18n/-/y18n-3.2.1.tgz", + "integrity": "sha1-bRX7qITAhnnA136I53WegR4H+kE=", + "dev": true + }, + "yallist": { + "version": "2.1.2", + "resolved": "https://registry.npmjs.org/yallist/-/yallist-2.1.2.tgz", + "integrity": "sha1-HBH5IY8HYImkfdUS+TxmmaaoHVI=", + "dev": true + }, + "yargs": { + "version": "7.1.0", + "resolved": "https://registry.npmjs.org/yargs/-/yargs-7.1.0.tgz", + "integrity": "sha1-a6MY6xaWFyf10oT46gA+jWFU0Mg=", + "dev": true, + "requires": { + "camelcase": "^3.0.0", + "cliui": "^3.2.0", + "decamelize": "^1.1.1", + "get-caller-file": "^1.0.1", + "os-locale": "^1.4.0", + "read-pkg-up": "^1.0.1", + "require-directory": "^2.1.1", + "require-main-filename": "^1.0.1", + "set-blocking": "^2.0.0", + "string-width": "^1.0.2", + "which-module": "^1.0.0", + "y18n": "^3.2.1", + "yargs-parser": "^5.0.0" + } + }, + "yargs-parser": { + "version": "5.0.0", + "resolved": "https://registry.npmjs.org/yargs-parser/-/yargs-parser-5.0.0.tgz", + "integrity": "sha1-J17PDX/+Bcd+ZOfIbkzZS/DhIoo=", + "dev": true, + "requires": { + "camelcase": "^3.0.0" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 0000000..b6b3b06 --- /dev/null +++ b/package.json @@ -0,0 +1,41 @@ +{ + "name": "mmenu-js", + "version": "8.5.3", + "main": "dist/mmenu.js", + "module": "src/mmenu.js", + "author": "Fred Heusschen ", + "license": "CC-BY-NC-4.0", + "repository": { + "type": "git", + "url": "https://github.com/FrDH/mmenu-js.git" + }, + "description": "The best javascript plugin for app look-alike on- and off-canvas menus with sliding submenus for your website and webapp.", + "keywords": [ + "app", + "list", + "listview", + "megamenu", + "menu", + "mmenu", + "mobile", + "navigation", + "off-canvas", + "on-canvas", + "curtain", + "panels", + "submenu" + ], + "scripts": { + "build": "gulp default" + }, + "devDependencies": { + "gulp": "^4.0.2", + "gulp-autoprefixer": "^6.1.0", + "gulp-clean-css": "^4.2.0", + "gulp-concat": "^2.6.1", + "gulp-sass": "^4.0.2", + "gulp-typescript": "^5.0.1", + "typescript": "^3.4.5", + "webpack-stream": "^5.2.1" + } +} diff --git a/src/_includes.scss b/src/_includes.scss new file mode 100644 index 0000000..448d33c --- /dev/null +++ b/src/_includes.scss @@ -0,0 +1,93 @@ +$mm_include_rtl: true !default; +$mm_include_vertical: true !default; + +$mm_IE11Fallbacks: true !default; + +$mm_include_offcanvas: true !default; +$mm_include_offcanvas_blocker: $mm_include_offcanvas !default; + +$mm_include_screenreader: true !default; + +$mm_include_autoheight: true !default; + +$mm_include_columns: true !default; + +$mm_include_counters: true !default; + +$mm_include_dividers: true !default; + +$mm_include_drag: true !default; + +$mm_include_dropdown: true !default; +$mm_include_dropdown_tip: $mm_include_dropdown !default; + +$mm_include_iconbar: true !default; +$mm_include_iconbar_tabs: $mm_include_iconbar !default; + +$mm_include_iconpanels: true !default; +$mm_include_iconpanels_blocker: $mm_include_iconpanels !default; + +$mm_include_keyboardnavigation: true !default; + +$mm_include_navbars: true !default; +$mm_include_navbars_top: $mm_include_navbars !default; +$mm_include_navbars_bottom: $mm_include_navbars !default; +$mm_include_navbars_breadcrumbs: $mm_include_navbars !default; +$mm_include_navbars_searchfield: $mm_include_navbars !default; +$mm_include_navbars_tabs: $mm_include_navbars !default; + +$mm_include_searchfield: true !default; +$mm_include_searchfield_btn: $mm_include_searchfield !default; +$mm_include_searchfield_searchpanel: $mm_include_searchfield !default; + +$mm_include_sectionindexer: true !default; + +$mm_include_setselected: true !default; + +$mm_include_sidebar: true !default; +$mm_include_sidebar_collapsed: $mm_include_sidebar !default; +$mm_include_sidebar_expanded: $mm_include_sidebar !default; +$mm_include_sidebar_blocker: $mm_include_sidebar !default; + +$mm_include_toggles: true !default; +$mm_include_checks: true !default; + +$mm_include_borderstyle: true !default; +$mm_include_borderstyle_none: $mm_include_borderstyle !default; +$mm_include_borderstyle_full: $mm_include_borderstyle !default; + +$mm_include_effects: true !default; +$mm_include_effects_menuslide: $mm_include_effects !default; +$mm_include_effects_panelsnone: $mm_include_effects !default; +$mm_include_effects_panelsslide: $mm_include_effects !default; + +$mm_include_fullscreen: true !default; + +$mm_include_listview: true !default; +$mm_include_listview_justify: $mm_include_listview !default; +$mm_include_listview_inset: $mm_include_listview !default; + +$mm_include_multiline: true !default; + +$mm_include_pagedim: true !default; +$mm_include_pagedim_default: $mm_include_pagedim !default; +$mm_include_pagedim_black: $mm_include_pagedim !default; +$mm_include_pagedim_white: $mm_include_pagedim !default; + +$mm_include_popup: true !default; + +$mm_include_positioning: true !default; +$mm_include_positioning_right: $mm_include_positioning !default; +$mm_include_positioning_top: $mm_include_positioning !default; +$mm_include_positioning_bottom: $mm_include_positioning !default; +$mm_include_positioning_front: $mm_include_positioning !default; + +$mm_include_shadows: true !default; +$mm_include_shadows_page: $mm_include_shadows !default; +$mm_include_shadows_menu: $mm_include_shadows !default; +$mm_include_shadows_panels: $mm_include_shadows !default; + +$mm_include_themes: true !default; +$mm_include_themes_white: $mm_include_themes !default; +$mm_include_themes_dark: $mm_include_themes !default; +$mm_include_themes_black: $mm_include_themes !default; diff --git a/src/_mixins.scss b/src/_mixins.scss new file mode 100644 index 0000000..04bee42 --- /dev/null +++ b/src/_mixins.scss @@ -0,0 +1,183 @@ +// Arrow buttons +@mixin mm_btn_arrow_prev { + transform: rotate( -45deg ); + left: $mm_listitemIndent + 3; + right: auto; +} + +@mixin mm_btn_arrow_next { + transform: rotate( 135deg ); + right: $mm_listitemIndent + 3; + left: auto; +} + + +// Misc +@mixin mm_ellipsis() { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +@mixin mm_clearfix() { + &:after { + content: ''; + display: block; + clear: both; + } +} +@mixin mm_offcanvas_size( $cls: ".mm-menu_offcanvas", + $width: $mm_menuWidth, $minWidth: $mm_menuMinWidth, $maxWidth: $mm_menuMaxWidth +) { + #{$cls} { + width: percentage( $width ); + min-width: $minWidth; + max-width: $maxWidth; + } + + .mm-wrapper_opening { + #{$cls} ~ .mm-slideout { + transform: translate3d( #{$width * 100}vw, 0, 0 ); + } + } + + // adjust for min- and max-width + @media all and ( max-width: $minWidth / $width ) { + .mm-wrapper_opening { + #{$cls} ~ .mm-slideout { + transform: translate3d( $minWidth, 0, 0 ); + } + } + } + + @media all and ( min-width: $maxWidth / $width ) { + .mm-wrapper_opening { + #{$cls} ~ .mm-slideout { + transform: translate3d( $maxWidth, 0, 0 ); + } + } + } +} + +@mixin mm_columns_size($nr) { + [class*='mm-menu_columns-'] .mm-panels > .mm-panel_columns-#{$nr} { + transform: translate3d($nr * 100%, 0, 0); + } + + .mm-menu_columns-#{$nr} .mm-panels > .mm-panel { + z-index: $nr; + + @if ($nr > 0) { + width: ceil(100% / $nr * 100) / 100; + } + else { + width: 100%; + } + + &:not(.mm-panel_opened):not(.mm-panel_opened-parent) { + transform: translate3d(($nr + 1) * 100%, 0, 0); + } + } + + @include mm_offcanvas_size( + '.mm-menu_columns-#{$nr}', + $mm_menuWidth, + $mm_menuMinWidth, + $mm_menuMaxWidth * $nr + ); + @include mm_position_right( + '.mm-menu_columns-#{$nr}', + $mm_menuWidth, + $mm_menuMinWidth, + $mm_menuMaxWidth * $nr + ); +} + +@mixin mm_iconpanel_size($nr) { + .mm-panel_iconpanel-#{$nr} { + @if ($mm_IE11Fallbacks) { + width: calc(100% - #{$mm_iconpanelSize * $nr}); + } + + width: calc(100% - (var(--mm-iconpanel-size) * #{$nr})); + } +} + +@mixin mm_navbar_tabs_borders( $top, $bottom, $last, $first ) { + .mm-navbars_#{$top} { + .mm-navbar_tabs:not( :#{$last}-child ) { + border-#{$bottom}-width: 1px; + border-#{$bottom}-style: solid; + } + .mm-navbar__tab_selected { + border-#{$bottom}: none; + margin-#{$bottom}: -1px; + } + .mm-navbar_tabs:#{$first}-child .mm-navbar__tab_selected { + border-#{$top}: none; + } + } +} + +@mixin mm_effect_listitem_delay( $i ) { + &:nth-child( #{$i} ) { + transition-delay: ( $i * 50ms ); + } +} +// Position right +@mixin mm_position_right( + $cls: '', + $width: $mm_menuWidth, + $minWidth: $mm_menuMinWidth, + $maxWidth: $mm_menuMaxWidth +) { + .mm-wrapper_opening { + #{$cls}.mm-menu_position-right.mm-menu_opened ~ .mm-slideout { + transform: translate3d(#{-$width * 100}vw, 0, 0); + } + } + + // adjust for min- and max-width + @media all and (max-width: $minWidth / $width) { + .mm-wrapper_opening { + #{$cls}.mm-menu_position-right.mm-menu_opened ~ .mm-slideout { + transform: translate3d(-$minWidth, 0, 0); + } + } + } + @media all and (min-width: $maxWidth / $width) { + .mm-wrapper_opening { + #{$cls}.mm-menu_position-right.mm-menu_opened ~ .mm-slideout { + transform: translate3d(-$maxWidth, 0, 0); + } + } + } +} + +// Position top +@mixin mm_position_top( + $cls: '', + $height: $mm_menuHeight, + $minHeight: $mm_menuMinHeight, + $maxHeight: $mm_menuMaxHeight +) { + #{$cls}.mm-menu_position-top { + height: #{$height * 100}vh; + min-height: $minHeight; + max-height: $maxHeight; + } +} + +// Position bottom +@mixin mm_position_bottom( + $cls: '', + $height: $mm_menuHeight, + $minHeight: $mm_menuMinHeight, + $maxHeight: $mm_menuMaxHeight +) { + #{$cls}.mm-menu_position-bottom { + height: #{$height * 100}vh; + min-height: $minHeight; + max-height: $maxHeight; + } +} diff --git a/src/_modules/dom.ts b/src/_modules/dom.ts new file mode 100644 index 0000000..5b1207f --- /dev/null +++ b/src/_modules/dom.ts @@ -0,0 +1,158 @@ +/** + * Create an element with classname. + * + * @param {string} selector The nodeName and classnames for the element to create. + * @return {HTMLElement} The created element. + */ +export function create(selector: string): HTMLElement { + var args = selector.split('.'); + var elem = document.createElement(args.shift()); + + // IE11: + args.forEach(classname => { + elem.classList.add(classname); + }); + + // Better browsers: + // elem.classList.add(...args); + + return elem; +} + +/** + * Find all elements matching the selector. + * Basically the same as element.querySelectorAll() but it returns an actuall array. + * + * @param {HTMLElement} element Element to search in. + * @param {string} filter The filter to match. + * @return {array} Array of elements that match the filter. + */ +export function find( + element: HTMLElement | Document, + filter: string +): HTMLElement[] { + return Array.prototype.slice.call(element.querySelectorAll(filter)); +} + +/** + * Find all child elements matching the (optional) selector. + * + * @param {HTMLElement} element Element to search in. + * @param {string} filter The filter to match. + * @return {array} Array of child elements that match the filter. + */ +export function children(element: HTMLElement, filter?: string): HTMLElement[] { + var children: HTMLElement[] = Array.prototype.slice.call(element.children); + return filter ? children.filter(child => child.matches(filter)) : children; +} + +/** + * Find text excluding text from within child elements. + * @param {HTMLElement} element Element to search in. + * @return {string} The text. + */ +export function text(element: HTMLElement): string { + return Array.prototype.slice + .call(element.childNodes) + .filter(child => child.nodeType == 3) + .map(child => child.textContent) + .join(' '); +} + +/** + * Find all preceding elements matching the selector. + * + * @param {HTMLElement} element Element to start searching from. + * @param {string} filter The filter to match. + * @return {array} Array of preceding elements that match the selector. + */ +export function parents(element: HTMLElement, filter?: string): HTMLElement[] { + /** Array of preceding elements that match the selector. */ + var parents: HTMLElement[] = []; + + /** Array of preceding elements that match the selector. */ + var parent = element.parentElement; + while (parent) { + parents.push(parent); + parent = parent.parentElement; + } + + return filter ? parents.filter(parent => parent.matches(filter)) : parents; +} + +/** + * Find all previous siblings matching the selecotr. + * + * @param {HTMLElement} element Element to start searching from. + * @param {string} filter The filter to match. + * @return {array} Array of previous siblings that match the selector. + */ +export function prevAll(element: HTMLElement, filter?: string): HTMLElement[] { + /** Array of previous siblings that match the selector. */ + var previous: HTMLElement[] = []; + + /** Current element in the loop */ + var current = element.previousElementSibling as HTMLElement; + + while (current) { + if (!filter || current.matches(filter)) { + previous.push(current); + } + current = current.previousElementSibling as HTMLElement; + } + + return previous; +} + +/** + * Get an element offset relative to the document. + * + * @param {HTMLElement} element Element to start measuring from. + * @param {string} [direction=top] Offset top or left. + * @return {number} The element offset relative to the document. + */ +export function offset(element: HTMLElement, direction?: string): number { + return ( + element.getBoundingClientRect()[direction] + + document.body[direction === 'left' ? 'scrollLeft' : 'scrollTop'] + ); +} + +/** + * Filter out non-listitem listitems. + * @param {array} listitems Elements to filter. + * @return {array} The filtered set of listitems. + */ +export function filterLI(listitems: HTMLElement[]): HTMLElement[] { + return listitems.filter(listitem => !listitem.matches('.mm-hidden')); +} + +/** + * Find anchors in listitems (excluding anchor that open a sub-panel). + * @param {array} listitems Elements to filter. + * @return {array} The found set of anchors. + */ +export function filterLIA(listitems: HTMLElement[]): HTMLElement[] { + var anchors = []; + filterLI(listitems).forEach(listitem => { + anchors.push(...children(listitem, 'a.mm-listitem__text')); + }); + return anchors.filter(anchor => !anchor.matches('.mm-btn_next')); +} + +/** + * Refactor a classname on multiple elements. + * @param {HTMLElement} element Element to refactor. + * @param {string} oldClass Classname to remove. + * @param {string} newClass Classname to add. + */ +export function reClass( + element: HTMLElement, + oldClass: string, + newClass: string +) { + if (element.matches('.' + oldClass)) { + element.classList.remove(oldClass); + element.classList.add(newClass); + } +} diff --git a/src/_modules/dragevents/_defaults.ts b/src/_modules/dragevents/_defaults.ts new file mode 100644 index 0000000..07afab3 --- /dev/null +++ b/src/_modules/dragevents/_defaults.ts @@ -0,0 +1,13 @@ +/** How far from the sides the gesture can start. */ +export const area: dragArea = { + top: 0, + right: 0, + bottom: 0, + left: 0 +}; + +/** Tresholds for gestures. */ +export const treshold: dragTreshold = { + start: 15, + swipe: 15 +}; diff --git a/src/_modules/dragevents/_helpers.ts b/src/_modules/dragevents/_helpers.ts new file mode 100644 index 0000000..0b541ff --- /dev/null +++ b/src/_modules/dragevents/_helpers.ts @@ -0,0 +1,15 @@ +/** + * Calculate a distance from a percentage. + * @param {string|number} position The percentage (e.g. "75%"). + * @param {number} size The available width or height in pixels. + * @return {number} The calculated distance. + */ +export const percentage2number = (position: string | number, size: number) => { + if (typeof position == 'string') { + if (position.slice(-1) == '%') { + position = parseInt(position.slice(0, -1), 10); + position = size * (position / 100); + } + } + return position; +}; diff --git a/src/_modules/dragevents/_settings.ts b/src/_modules/dragevents/_settings.ts new file mode 100644 index 0000000..bc2d981 --- /dev/null +++ b/src/_modules/dragevents/_settings.ts @@ -0,0 +1,12 @@ +/** Names of the possible directions. */ +export const directionNames = { + x: ['Right', 'Left'], + y: ['Down', 'Up'] +}; + +/** States for the gesture. */ +export const state = { + inactive: 0, + watching: 1, + dragging: 2 +}; diff --git a/src/_modules/dragevents/_support.ts b/src/_modules/dragevents/_support.ts new file mode 100644 index 0000000..24c13b7 --- /dev/null +++ b/src/_modules/dragevents/_support.ts @@ -0,0 +1,5 @@ +/** Whether or not touch gestures are supported by the browser. */ +export const touch = + 'ontouchstart' in window || + (navigator.msMaxTouchPoints ? true : false) || + false; diff --git a/src/_modules/dragevents/_typings.d.ts b/src/_modules/dragevents/_typings.d.ts new file mode 100644 index 0000000..4e665c9 --- /dev/null +++ b/src/_modules/dragevents/_typings.d.ts @@ -0,0 +1,24 @@ +/** Options for the drag engine. */ +interface dragOption { + area: dragArea; +} + +/** How far from the sides the gesture can start. */ +interface dragArea { + top?: number | string; + right?: number | string; + bottom?: number | string; + left?: number | string; +} + +/** Tresholds for gestures. */ +interface dragTreshold { + start?: number; + swipe?: number; +} + +/** Set of x and y positions. */ +interface dragCoordinates { + x: number; + y: number; +} diff --git a/src/_modules/dragevents/index.ts b/src/_modules/dragevents/index.ts new file mode 100644 index 0000000..e163ce3 --- /dev/null +++ b/src/_modules/dragevents/index.ts @@ -0,0 +1,298 @@ +import * as support from './_support'; +import * as options from './_defaults'; +import * as settings from './_settings'; +import { percentage2number } from './_helpers'; +import { extend } from '../helpers'; + +export default class DragEvents { + /** The draggable area. */ + surface: HTMLElement; + + /** How far from the sides the gesture can start. */ + area: dragArea; + + /** Tresholds for gestures. */ + treshold: dragTreshold; + + /** Where the gesture started. */ + startPosition: dragCoordinates; + + /** The last measured x- and y- position. */ + currentPosition: dragCoordinates; + + /** The dragged x- and y-distances since the start. */ + distance: dragCoordinates; + + /** The dragged x- and y-distances since the last event. */ + movement: dragCoordinates; + + /** The axis of the gesture. */ + axis: 'x' | 'y'; + + /** The state of the gesture. */ + state: number; + + /** + * Create the gestures. + * @param {HTMLElement} surface The surface for the gesture. + * @param {object} area Restriction where on the surface the gesture can be started. + * @param {object} treshold Treshold for the gestures. + */ + constructor( + surface: HTMLElement, + area?: dragArea, + treshold?: dragTreshold + ) { + this.surface = surface; + this.area = extend(area, options.area); + this.treshold = extend(treshold, options.treshold); + + // Set the mouse/touch events. + if (!this.surface['mmHasDragEvents']) { + this.surface.addEventListener( + support.touch ? 'touchstart' : 'mousedown', + this.start.bind(this) + ); + this.surface.addEventListener( + support.touch ? 'touchend' : 'mouseup', + this.stop.bind(this) + ); + this.surface.addEventListener( + support.touch ? 'touchleave' : 'mouseleave', + this.stop.bind(this) + ); + this.surface.addEventListener( + support.touch ? 'touchmove' : 'mousemove', + this.move.bind(this) + ); + } + + this.surface['mmHasDragEvents'] = true; + } + + /** + * Starting the touch gesture. + * @param {Event} event The touch event. + */ + start(event) { + this.currentPosition = { + x: event.touches ? event.touches[0].pageX : event.pageX || 0, + y: event.touches ? event.touches[0].pageY : event.pageY || 0 + }; + + /** The widht of the surface. */ + var width = this.surface.clientWidth; + + /** The height of the surface. */ + var height = this.surface.clientHeight; + + // Check if the gesture started below the area.top. + var top = percentage2number(this.area.top, height); + if (typeof top == 'number') { + if (this.currentPosition.y < top) { + return; + } + } + + // Check if the gesture started before the area.right. + var right = percentage2number(this.area.right, width); + if (typeof right == 'number') { + right = width - right; + if (this.currentPosition.x > right) { + return; + } + } + + // Check if the gesture started above the area.bottom. + var bottom = percentage2number(this.area.bottom, height); + if (typeof bottom == 'number') { + bottom = height - bottom; + if (this.currentPosition.y > bottom) { + return; + } + } + + // Check if the gesture started after the area.left. + var left = percentage2number(this.area.left, width); + if (typeof left == 'number') { + if (this.currentPosition.x < left) { + return; + } + } + + // Store the start x- and y-position. + this.startPosition = { + x: this.currentPosition.x, + y: this.currentPosition.y + }; + + // Set the state of the gesture to "watching". + this.state = settings.state.watching; + } + + /** + * Stopping the touch gesture. + * @param {Event} event The touch event. + */ + stop(event) { + // Dispatch the "dragEnd" events. + if (this.state == settings.state.dragging) { + /** The direction. */ + const dragDirection = this._dragDirection(); + + /** The event information. */ + const detail = this._eventDetail(dragDirection); + + this._dispatchEvents('drag*End', detail); + + // Dispatch the "swipe" events. + if (Math.abs(this.movement[this.axis]) > this.treshold.swipe) { + /** The direction. */ + const swipeDirection = this._swipeDirection(); + detail.direction = swipeDirection; + + this._dispatchEvents('swipe*', detail); + } + } + + // Set the state of the gesture to "inactive". + this.state = settings.state.inactive; + } + + /** + * Doing the touch gesture. + * @param {Event} event The touch event. + */ + move(event) { + switch (this.state) { + case settings.state.watching: + case settings.state.dragging: + var position = { + x: event.changedTouches + ? event.touches[0].pageX + : event.pageX || 0, + y: event.changedTouches + ? event.touches[0].pageY + : event.pageY || 0 + }; + + this.movement = { + x: position.x - this.currentPosition.x, + y: position.y - this.currentPosition.y + }; + + this.distance = { + x: position.x - this.startPosition.x, + y: position.y - this.startPosition.y + }; + + this.currentPosition = { + x: position.x, + y: position.y + }; + + this.axis = + Math.abs(this.distance.x) > Math.abs(this.distance.y) + ? 'x' + : 'y'; + + /** The direction. */ + const dragDirection = this._dragDirection(); + + /** The event information. */ + const detail = this._eventDetail(dragDirection); + + // Watching for the gesture to go past the treshold. + if (this.state == settings.state.watching) { + if ( + Math.abs(this.distance[this.axis]) > this.treshold.start + ) { + this._dispatchEvents('drag*Start', detail); + + // Set the state of the gesture to "inactive". + this.state = settings.state.dragging; + } + } + + // Dispatch the "drag" events. + if (this.state == settings.state.dragging) { + this._dispatchEvents('drag*Move', detail); + } + break; + } + } + + /** + * Get the event details. + * @param {string} direction Direction for the event (up, right, down, left). + * @return {object} The event details. + */ + _eventDetail(direction: string) { + var distX = this.distance.x; + var distY = this.distance.y; + + if (this.axis == 'x') { + distX -= distX > 0 ? this.treshold.start : 0 - this.treshold.start; + } + + if (this.axis == 'y') { + distY -= distY > 0 ? this.treshold.start : 0 - this.treshold.start; + } + + return { + axis: this.axis, + direction: direction, + movementX: this.movement.x, + movementY: this.movement.y, + distanceX: distX, + distanceY: distY + }; + } + + /** + * Dispatch the events + * @param {string} eventName The name for the events to dispatch. + * @param {object} detail The event details. + */ + _dispatchEvents(eventName: string, detail) { + /** General event, e.g. "drag" */ + var event = new CustomEvent(eventName.replace('*', ''), { detail }); + this.surface.dispatchEvent(event); + + /** Axis event, e.g. "dragX" */ + var axis = new CustomEvent( + eventName.replace('*', this.axis.toUpperCase()), + { detail } + ); + this.surface.dispatchEvent(axis); + + /** Direction event, e.g. "dragLeft" */ + var direction = new CustomEvent( + eventName.replace('*', detail.direction), + { + detail + } + ); + this.surface.dispatchEvent(direction); + } + + /** + * Get the dragging direction. + * @return {string} The direction in which the user is dragging. + */ + _dragDirection() { + return settings.directionNames[this.axis][ + this.distance[this.axis] > 0 ? 0 : 1 + ]; + } + + /** + * Get the dragging direction. + * @return {string} The direction in which the user is dragging. + */ + _swipeDirection() { + return settings.directionNames[this.axis][ + this.movement[this.axis] > 0 ? 0 : 1 + ]; + } +} diff --git a/src/_modules/eventlisteners.ts b/src/_modules/eventlisteners.ts new file mode 100644 index 0000000..05eca58 --- /dev/null +++ b/src/_modules/eventlisteners.ts @@ -0,0 +1,64 @@ +/** + * Make the first letter in a word uppercase. + * @param {string} word The word. + */ +function ucFirst(word) { + if (!word) { + return ''; + } + return word.charAt(0).toUpperCase() + word.slice(1); +} + +/** + * Bind an event listener to an element. + * @param {HTMLElement} element The element to bind the event listener to. + * @param {string} evnt The event to listen to. + * @param {funcion} handler The function to invoke. + */ +export function on( + element: HTMLElement | Window, + evnt: string, + handler: EventListenerOrEventListenerObject +) { + // Extract the event name and space from the event (the event can include a namespace (click.foo)). + var evntParts = evnt.split('.'); + evnt = 'mmEvent' + ucFirst(evntParts[0]) + ucFirst(evntParts[1]); + + element[evnt] = element[evnt] || []; + element[evnt].push(handler); + element.addEventListener(evntParts[0], handler); +} + +/** + * Remove an event listener from an element. + * @param {HTMLElement} element The element to remove the event listeners from. + * @param {string} evnt The event to remove. + */ +export function off(element: HTMLElement | Window, evnt: string) { + // Extract the event name and space from the event (the event can include a namespace (click.foo)). + var evntParts = evnt.split('.'); + evnt = 'mmEvent' + ucFirst(evntParts[0]) + ucFirst(evntParts[1]); + + (element[evnt] || []).forEach(handler => { + element.removeEventListener(evntParts[0], handler); + }); +} + +/** + * Trigger the bound event listeners on an element. + * @param {HTMLElement} element The element of which to trigger the event listeners from. + * @param {string} evnt The event to trigger. + * @param {object} [options] Options to pass to the handler. + */ +export function trigger( + element: HTMLElement | Window, + evnt: string, + options?: mmLooseObject +) { + var evntParts = evnt.split('.'); + evnt = 'mmEvent' + ucFirst(evntParts[0]) + ucFirst(evntParts[1]); + + (element[evnt] || []).forEach(handler => { + handler(options || {}); + }); +} diff --git a/src/_modules/helpers.ts b/src/_modules/helpers.ts new file mode 100644 index 0000000..cf1d9a8 --- /dev/null +++ b/src/_modules/helpers.ts @@ -0,0 +1,147 @@ +/** + * Deep extend an object with the given defaults. + * Note that the extended object is not a clone, meaning the original object will also be updated. + * + * @param {object} orignl The object to extend to. + * @param {object} dfault The object to extend from. + * @return {object} The extended "orignl" object. + */ +export function extend(orignl: mmLooseObject, dfault: mmLooseObject) { + if (type(orignl) != 'object') { + orignl = {}; + } + if (type(dfault) != 'object') { + dfault = {}; + } + + for (let k in dfault) { + if (!dfault.hasOwnProperty(k)) { + continue; + } + + if (typeof orignl[k] == 'undefined') { + orignl[k] = dfault[k]; + } else if (type(orignl[k]) == 'object') { + extend(orignl[k], dfault[k]); + } + } + return orignl; +} + +/** + * Detect the touch / dragging direction on a touch device. + * + * @param {HTMLElement} surface The element to monitor for touch events. + * @return {object} Object with "get" function. + */ +export function touchDirection(surface) { + var direction = ''; + + surface.addEventListener('touchmove', evnt => { + direction = ''; + + if (evnt.movementY > 0) { + direction = 'down'; + } else if (evnt.movementY < 0) { + direction = 'up'; + } + }); + + return { + get: () => direction + }; +} + +/** + * Get the type of any given variable. Improvement of "typeof". + * + * @param {any} variable The variable. + * @return {string} The type of the variable in lowercase. + */ +export function type(variable: any): string { + return {}.toString + .call(variable) + .match(/\s([a-zA-Z]+)/)[1] + .toLowerCase(); +} + +/** + * Find the value from an option or function. + * @param {HTMLElement} element Scope for the function. + * @param {any} [option] Value or function. + * @param {any} [dfault] Default fallback value. + * @return {any} The given evaluation of the given option, or the default fallback value. + */ +export function valueOrFn( + element: HTMLElement, + option?: any, + dfault?: any +): any { + if (typeof option == 'function') { + var value = option.call(element); + if (typeof value != 'undefined') { + return value; + } + } + if ( + (option === null || + typeof option == 'function' || + typeof option == 'undefined') && + typeof dfault != 'undefined' + ) { + return dfault; + } + return option; +} + +/** + * Set and invoke a (single) transition-end function with fallback. + * + * @param {HTMLElement} element Scope for the function. + * @param {function} func Function to invoke. + * @param {number} duration The duration of the animation (for the fallback). + */ +export function transitionend( + element: HTMLElement, + func: Function, + duration: number +) { + var _ended = false, + _fn = function(evnt) { + if (typeof evnt !== 'undefined') { + if (evnt.target !== element) { + return; + } + } + + if (!_ended) { + element.removeEventListener('transitionend', _fn); + element.removeEventListener('webkitTransitionEnd', _fn); + func.call(element); + } + _ended = true; + }; + + element.addEventListener('transitionend', _fn); + element.addEventListener('webkitTransitionEnd', _fn); + setTimeout(_fn, duration * 1.1); +} + +/** + * Get a (page wide) unique ID. + */ +export function uniqueId() { + return 'mm-' + __id++; +} +var __id = 0; + +/** + * Get the original ID from a possibly prefixed ID. + * @param id The possibly prefixed ID. + */ +export function originalId(id) { + if (id.slice(0, 3) == 'mm-') { + return id.slice(3); + } + return id; +} diff --git a/src/_modules/i18n.ts b/src/_modules/i18n.ts new file mode 100644 index 0000000..86e5b3f --- /dev/null +++ b/src/_modules/i18n.ts @@ -0,0 +1,39 @@ +import { extend } from './helpers'; +var translations = {}; + +/** + * Add translations to a language. + * @param {object} text Object of key/value translations. + * @param {string} language The translated language. + */ +export function add(text: object, language: string) { + if (typeof translations[language] == 'undefined') { + translations[language] = {}; + } + extend(translations[language], text as object); +} + +/** + * Find a translated text in a language. + * @param {string} text The text to find the translation for. + * @param {string} language The language to search in. + * @return {string} The translated text. + */ +export function get(text: string, language?: string): string { + if ( + typeof language == 'string' && + typeof translations[language] != 'undefined' + ) { + return translations[language][text] || text; + } + return text; +} + +/** + * Get all translated text in a language. + * @param {string} language The language to search for. + * @return {object} The translations. + */ +export function all(language: string): object { + return translations; +} diff --git a/src/_modules/matchmedia.ts b/src/_modules/matchmedia.ts new file mode 100644 index 0000000..c8758ab --- /dev/null +++ b/src/_modules/matchmedia.ts @@ -0,0 +1,44 @@ +/** Collection of callback functions for media querys. */ +var listeners = {}; + +/** + * Bind functions to a matchMedia listener (subscriber). + * + * @param {string|number} query Media query to match or number for min-width. + * @param {function} yes Function to invoke when the media query matches. + * @param {function} no Function to invoke when the media query doesn't match. + */ +export function add(query: string | number, yes: Function, no: Function) { + if (typeof query == 'number') { + query = '(min-width: ' + query + 'px)'; + } + listeners[query] = listeners[query] || []; + listeners[query].push({ yes, no }); +} + +/** + * Initialize the matchMedia listener. + */ +export function watch() { + for (let query in listeners) { + let mqlist = window.matchMedia(query); + + fire(query, mqlist); + mqlist.onchange = evnt => { + fire(query, mqlist); + }; + } +} + +/** + * Invoke the "yes" or "no" function for a matchMedia listener (publisher). + * + * @param {string} query Media query to check for. + * @param {MediaQueryList} mqlist Media query list to check with. + */ +export function fire(query: string, mqlist: MediaQueryList) { + var fn = mqlist.matches ? 'yes' : 'no'; + for (let m = 0; m < listeners[query].length; m++) { + listeners[query][m][fn](); + } +} diff --git a/src/_modules/support.ts b/src/_modules/support.ts new file mode 100644 index 0000000..24c13b7 --- /dev/null +++ b/src/_modules/support.ts @@ -0,0 +1,5 @@ +/** Whether or not touch gestures are supported by the browser. */ +export const touch = + 'ontouchstart' in window || + (navigator.msMaxTouchPoints ? true : false) || + false; diff --git a/src/_polyfills/api.closest.js b/src/_polyfills/api.closest.js new file mode 100644 index 0000000..9b43a98 --- /dev/null +++ b/src/_polyfills/api.closest.js @@ -0,0 +1,18 @@ +// Source: https://developer.mozilla.org/en-US/docs/Web/API/Element/closest +if (!Element.prototype.matches) { + Element.prototype.matches = + Element.prototype.msMatchesSelector || + Element.prototype.webkitMatchesSelector; +} + +if (!Element.prototype.closest) { + Element.prototype.closest = function(s) { + var el = this; + + do { + if (el.matches(s)) return el; + el = el.parentElement || el.parentNode; + } while (el !== null && el.nodeType === 1); + return null; + }; +} diff --git a/src/_polyfills/api.foreach.js b/src/_polyfills/api.foreach.js new file mode 100644 index 0000000..3a5bca7 --- /dev/null +++ b/src/_polyfills/api.foreach.js @@ -0,0 +1,9 @@ +// Source: https://developer.mozilla.org/en-US/docs/Web/API/NodeList/forEach +if (window.NodeList && !NodeList.prototype.forEach) { + NodeList.prototype.forEach = function(callback, thisArg) { + thisArg = thisArg || window; + for (var i = 0; i < this.length; i++) { + callback.call(thisArg, this[i], i, this); + } + }; +} diff --git a/src/_polyfills/api.matches.js b/src/_polyfills/api.matches.js new file mode 100644 index 0000000..b4629d5 --- /dev/null +++ b/src/_polyfills/api.matches.js @@ -0,0 +1,17 @@ +// Source: https://developer.mozilla.org/en-US/docs/Web/API/Element/matches +if (!Element.prototype.matches) { + Element.prototype.matches = + Element.prototype.matchesSelector || + Element.prototype.mozMatchesSelector || + Element.prototype.msMatchesSelector || + Element.prototype.oMatchesSelector || + Element.prototype.webkitMatchesSelector || + function(s) { + var matches = ( + this.document || this.ownerDocument + ).querySelectorAll(s), + i = matches.length; + while (--i >= 0 && matches.item(i) !== this) {} + return i > -1; + }; +} diff --git a/src/_polyfills/dom.append.js b/src/_polyfills/dom.append.js new file mode 100644 index 0000000..925bab7 --- /dev/null +++ b/src/_polyfills/dom.append.js @@ -0,0 +1,28 @@ +// Source: https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/append()/append().md +(function(arr) { + arr.forEach(function(item) { + if (item.hasOwnProperty('append')) { + return; + } + Object.defineProperty(item, 'append', { + configurable: true, + enumerable: true, + writable: true, + value: function append() { + var argArr = Array.prototype.slice.call(arguments), + docFrag = document.createDocumentFragment(); + + argArr.forEach(function(argItem) { + var isNode = argItem instanceof Node; + docFrag.appendChild( + isNode + ? argItem + : document.createTextNode(String(argItem)) + ); + }); + + this.appendChild(docFrag); + } + }); + }); +})([Element.prototype, Document.prototype, DocumentFragment.prototype]); diff --git a/src/_polyfills/dom.before.js b/src/_polyfills/dom.before.js new file mode 100644 index 0000000..abb6dbc --- /dev/null +++ b/src/_polyfills/dom.before.js @@ -0,0 +1,28 @@ +// Source: https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/before()/before().md +(function(arr) { + arr.forEach(function(item) { + if (item.hasOwnProperty('before')) { + return; + } + Object.defineProperty(item, 'before', { + configurable: true, + enumerable: true, + writable: true, + value: function before() { + var argArr = Array.prototype.slice.call(arguments), + docFrag = document.createDocumentFragment(); + + argArr.forEach(function(argItem) { + var isNode = argItem instanceof Node; + docFrag.appendChild( + isNode + ? argItem + : document.createTextNode(String(argItem)) + ); + }); + + this.parentNode.insertBefore(docFrag, this); + } + }); + }); +})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); diff --git a/src/_polyfills/dom.prepend.js b/src/_polyfills/dom.prepend.js new file mode 100644 index 0000000..a3733a2 --- /dev/null +++ b/src/_polyfills/dom.prepend.js @@ -0,0 +1,28 @@ +// Source: https://github.com/jserz/js_piece/blob/master/DOM/ParentNode/prepend()/prepend().md +(function(arr) { + arr.forEach(function(item) { + if (item.hasOwnProperty('prepend')) { + return; + } + Object.defineProperty(item, 'prepend', { + configurable: true, + enumerable: true, + writable: true, + value: function prepend() { + var argArr = Array.prototype.slice.call(arguments), + docFrag = document.createDocumentFragment(); + + argArr.forEach(function(argItem) { + var isNode = argItem instanceof Node; + docFrag.appendChild( + isNode + ? argItem + : document.createTextNode(String(argItem)) + ); + }); + + this.insertBefore(docFrag, this.firstChild); + } + }); + }); +})([Element.prototype, Document.prototype, DocumentFragment.prototype]); diff --git a/src/_polyfills/dom.remove.js b/src/_polyfills/dom.remove.js new file mode 100644 index 0000000..a54ec74 --- /dev/null +++ b/src/_polyfills/dom.remove.js @@ -0,0 +1,16 @@ +// Source: https://github.com/jserz/js_piece/blob/master/DOM/ChildNode/remove()/remove().md +(function(arr) { + arr.forEach(function(item) { + if (item.hasOwnProperty('remove')) { + return; + } + Object.defineProperty(item, 'remove', { + configurable: true, + enumerable: true, + writable: true, + value: function remove() { + if (this.parentNode !== null) this.parentNode.removeChild(this); + } + }); + }); +})([Element.prototype, CharacterData.prototype, DocumentType.prototype]); diff --git a/src/_variables.scss b/src/_variables.scss new file mode 100644 index 0000000..1daf8e3 --- /dev/null +++ b/src/_variables.scss @@ -0,0 +1,69 @@ +// Animations +$mm_transitionDuration: 0.4s !default; +$mm_transitionDelay: 0.4s !default; +$mm_transitionFunction: ease !default; + +// Colors +$mm_backgroundColor: #f3f3f3 !default; +$mm_borderColor: rgba(#000, 0.1) !default; +$mm_dimmedTextColor: rgba(#000, 0.3) !default; +$mm_emphasizedBackgroundColor: rgba(#fff, 0.4) !default; +$mm_highlightedBackgroundColor: rgba(#000, 0.05) !default; +$mm_navbarColor: rgba(#000, 0.3) !default; +$mm_textColor: rgba(#000, 0.75) !default; + +// Positioning +$mm_offsetTop: 0 !default; +$mm_offsetRight: 0 !default; +$mm_offsetBottom: 0 !default; +$mm_offsetLeft: 0 !default; + +// Sizes +$mm_listitemSize: 44px !default; +$mm_btnSize: 50px !default; +$mm_padding: 10px !default; +$mm_lineHeight: 20px !default; + +$mm_listitemIndent: $mm_padding * 2 !default; +$mm_navbarSize: $mm_listitemSize !default; +$mm_panelPadding: $mm_padding * 2 !default; +$mm_subopenWidth: $mm_btnSize !default; +$mm_subpanelOffset: 30% !default; + +$mm_menuWidth: 0.8 !default; +$mm_menuMinWidth: 240px !default; +$mm_menuMaxWidth: 440px !default; +$mm_menuHeight: 0.8 !default; +$mm_menuMinHeight: 140px !default; +$mm_menuMaxHeight: 880px !default; + +$mm_opt_screenreader : true !default; + +$mm_counterWidth: $mm_btnSize !default; + +$mm_dropdownShadow: 0 2px 10px rgba( #000, 0.3 ) !default; +$mm_dropdownTipX: 20px !default; +$mm_dropdownTipY: 10px !default; + +$mm_iconbarSize: $mm_btnSize !default; + +$mm_iconpanelSize: $mm_btnSize !default; + +$mm_sectionIndexerSize: 20px !default; + +$mm_sidebarCollapsedSize: $mm_btnSize !default; +$mm_sidebarExpandedSize: $mm_menuMaxWidth !default; + +$mm_toggleCheckedColor: #4bd963 !default; +$mm_toggleHeight: $mm_listitemSize - $mm_padding !default; +$mm_toggleWidth: ($mm_toggleHeight * 2) - $mm_padding !default; +$mm_checkHeight: $mm_btnSize - $mm_padding !default; +$mm_checkWidth: $mm_btnSize - $mm_padding !default; + +$mm_fullscreen_full: 1 !default; +$mm_fullscreen_min: 140px !default; +$mm_fullscreen_max: 10000px !default; + +$mm_pagedimOpacity: 0.3 !default; +$mm_pagedimDelay: 0.4s !default; +$mm_popupShadow: 0 2px 10px rgba( #000, 0.3 ) !default; \ No newline at end of file diff --git a/src/_version.ts b/src/_version.ts new file mode 100644 index 0000000..8f294ea --- /dev/null +++ b/src/_version.ts @@ -0,0 +1 @@ +export default '8.5.3'; diff --git a/src/addons/autoheight/_includes.scss b/src/addons/autoheight/_includes.scss new file mode 100644 index 0000000..b4b89d1 --- /dev/null +++ b/src/addons/autoheight/_includes.scss @@ -0,0 +1 @@ +$mm_include_autoheight: true !default; diff --git a/src/addons/autoheight/_options.ts b/src/addons/autoheight/_options.ts new file mode 100644 index 0000000..72a5203 --- /dev/null +++ b/src/addons/autoheight/_options.ts @@ -0,0 +1,33 @@ +const opts : mmOptionsAutoheight = { + height: 'default' +}; +export default opts; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsAutoheight +) : mmOptionsAutoheight { + + if ( typeof options == 'boolean' && options ) { + options = { + height: 'auto' + }; + } + + if ( typeof options == 'string' ) { + options = { + height: options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/autoheight/_typings.d.ts b/src/addons/autoheight/_typings.d.ts new file mode 100644 index 0000000..b94dc82 --- /dev/null +++ b/src/addons/autoheight/_typings.d.ts @@ -0,0 +1,6 @@ +/** Options for the autoHeight add-on. */ +interface mmOptionsAutoheight { + + /** What type of height to use. */ + height ?: 'default' | 'auto' | 'highest' +} diff --git a/src/addons/autoheight/mmenu.autoheight.scss b/src/addons/autoheight/mmenu.autoheight.scss new file mode 100644 index 0000000..7ca4d62 --- /dev/null +++ b/src/addons/autoheight/mmenu.autoheight.scss @@ -0,0 +1,31 @@ +@import '../../mixins', '../../includes', '../../variables'; + +.mm-menu_autoheight { + &:not(.mm-menu_offcanvas) { + position: relative; + } + + &.mm-menu_position { + &-top, + &-bottom { + max-height: percentage($mm_menuHeight); + } + } + + &-measuring { + .mm-panel { + display: block !important; + } + + .mm-panels > .mm-panel { + bottom: auto !important; + height: auto !important; + } + + @if ($mm_include_vertical) { + .mm-listitem_vertical:not(.mm-listitem_opened) .mm-panel { + display: none !important; + } + } + } +} diff --git a/src/addons/autoheight/mmenu.autoheight.ts b/src/addons/autoheight/mmenu.autoheight.ts new file mode 100644 index 0000000..77e73c7 --- /dev/null +++ b/src/addons/autoheight/mmenu.autoheight.ts @@ -0,0 +1,105 @@ +import Mmenu from './../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.autoHeight = options; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.autoHeight); + this.opts.autoHeight = extend(options, Mmenu.options.autoHeight); + + if (options.height != 'auto' && options.height != 'highest') { + return; + } + + const setHeight = (() => { + const getCurrent = (): number => { + var panel = DOM.children(this.node.pnls, '.mm-panel_opened')[0]; + + if (panel) { + panel = measurablePanel(panel); + } + + // Fallback, just to be sure we have a panel. + if (!panel) { + panel = DOM.children(this.node.pnls, '.mm-panel')[0]; + } + + return panel.scrollHeight; + }; + + const getHighest = (): number => { + var highest = 0; + DOM.children(this.node.pnls, '.mm-panel').forEach(panel => { + panel = measurablePanel(panel); + highest = Math.max(highest, panel.scrollHeight); + }); + + return highest; + }; + + const measurablePanel = (panel: HTMLElement): HTMLElement => { + // If it's a vertically expanding panel... + if (panel.parentElement.matches('.mm-listitem_vertical')) { + // ...find the first parent panel that isn't. + panel = DOM.parents(panel, '.mm-panel').filter( + panel => + !panel.parentElement.matches('.mm-listitem_vertical') + )[0]; + } + return panel; + }; + + return () => { + if (this.opts.offCanvas && !this.vars.opened) { + return; + } + + var _hgh = 0; + var _dif = + this.node.menu.offsetHeight - this.node.pnls.offsetHeight; + + // The "measuring" classname undoes some CSS to be able to measure the height. + this.node.menu.classList.add('mm-menu_autoheight-measuring'); + + // Measure the height. + if (options.height == 'auto') { + _hgh = getCurrent(); + } else if (options.height == 'highest') { + _hgh = getHighest(); + } + + // Set the height. + this.node.menu.style.height = _hgh + _dif + 'px'; + + // Remove the "measuring" classname. + this.node.menu.classList.remove('mm-menu_autoheight-measuring'); + }; + })(); + + // Add the autoheight class to the menu. + this.bind('initMenu:after', () => { + this.node.menu.classList.add('mm-menu_autoheight'); + }); + + if (this.opts.offCanvas) { + // Measure the height when opening the off-canvas menu. + this.bind('open:start', setHeight); + } + + if (options.height == 'highest') { + // Measure the height when initiating panels. + this.bind('initPanels:after', setHeight); + } + + if (options.height == 'auto') { + // Measure the height when updating listviews. + this.bind('updateListview', setHeight); + + // Measure the height when opening a panel. + this.bind('openPanel:start', setHeight); + } +} diff --git a/src/addons/backbutton/_options.ts b/src/addons/backbutton/_options.ts new file mode 100644 index 0000000..26779a9 --- /dev/null +++ b/src/addons/backbutton/_options.ts @@ -0,0 +1,28 @@ +const options : mmOptionsBackbutton = { + close: false, + open: false +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsBackbutton +) : mmOptionsBackbutton { + + if ( typeof options == 'boolean' ) { + options = { + close: options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/backbutton/_typings.d.ts b/src/addons/backbutton/_typings.d.ts new file mode 100644 index 0000000..703ac3e --- /dev/null +++ b/src/addons/backbutton/_typings.d.ts @@ -0,0 +1,9 @@ +/** Options for the backButton add-on. */ +interface mmOptionsBackbutton { + + /** Whether or not to close the menu with the back-( and forth-)button. */ + close ?: boolean + + /** Whether or not to open the menu with the back-( and forth-)button. */ + open ?: boolean +} diff --git a/src/addons/backbutton/mmenu.backbutton.ts b/src/addons/backbutton/mmenu.backbutton.ts new file mode 100644 index 0000000..aab44e0 --- /dev/null +++ b/src/addons/backbutton/mmenu.backbutton.ts @@ -0,0 +1,73 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.backButton = options; + +export default function(this: Mmenu) { + if (!this.opts.offCanvas) { + return; + } + + var options = extendShorthandOptions(this.opts.backButton); + this.opts.backButton = extend(options, Mmenu.options.backButton); + + var _menu = '#' + this.node.menu.id; + + // Close menu + if (options.close) { + var states = []; + + const setStates = () => { + states = [_menu]; + DOM.children( + this.node.pnls, + '.mm-panel_opened, .mm-panel_opened-parent' + ).forEach(panel => { + states.push('#' + panel.id); + }); + }; + + this.bind('open:finish', () => { + history.pushState(null, document.title, _menu); + }); + this.bind('open:finish', setStates); + this.bind('openPanel:finish', setStates); + this.bind('close:finish', () => { + states = []; + history.back(); + history.pushState( + null, + document.title, + location.pathname + location.search + ); + }); + + window.addEventListener('popstate', evnt => { + if (this.vars.opened) { + if (states.length) { + states = states.slice(0, -1); + var hash = states[states.length - 1]; + + if (hash == _menu) { + this.close(); + } else { + this.openPanel(this.node.menu.querySelector(hash)); + history.pushState(null, document.title, _menu); + } + } + } + }); + } + + if (options.open) { + window.addEventListener('popstate', evnt => { + if (!this.vars.opened && location.hash == _menu) { + this.open(); + } + }); + } +} diff --git a/src/addons/columns/_includes.scss b/src/addons/columns/_includes.scss new file mode 100644 index 0000000..f0ea87d --- /dev/null +++ b/src/addons/columns/_includes.scss @@ -0,0 +1 @@ +$mm_include_columns: true !default; diff --git a/src/addons/columns/_mixins.scss b/src/addons/columns/_mixins.scss new file mode 100644 index 0000000..edaf4cb --- /dev/null +++ b/src/addons/columns/_mixins.scss @@ -0,0 +1,33 @@ +@mixin mm_columns_size($nr) { + [class*='mm-menu_columns-'] .mm-panels > .mm-panel_columns-#{$nr} { + transform: translate3d($nr * 100%, 0, 0); + } + + .mm-menu_columns-#{$nr} .mm-panels > .mm-panel { + z-index: $nr; + + @if ($nr > 0) { + width: ceil(100% / $nr * 100) / 100; + } + else { + width: 100%; + } + + &:not(.mm-panel_opened):not(.mm-panel_opened-parent) { + transform: translate3d(($nr + 1) * 100%, 0, 0); + } + } + + @include mm_offcanvas_size( + '.mm-menu_columns-#{$nr}', + $mm_menuWidth, + $mm_menuMinWidth, + $mm_menuMaxWidth * $nr + ); + @include mm_position_right( + '.mm-menu_columns-#{$nr}', + $mm_menuWidth, + $mm_menuMinWidth, + $mm_menuMaxWidth * $nr + ); +} diff --git a/src/addons/columns/_options.ts b/src/addons/columns/_options.ts new file mode 100644 index 0000000..d315a44 --- /dev/null +++ b/src/addons/columns/_options.ts @@ -0,0 +1,45 @@ +const options : mmOptionsColumns = { + add: false, + visible: { + min: 1, + max: 3 + } +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsColumns +) : mmOptionsColumns { + + if ( typeof options == 'boolean' ) { + options = { + add : options + }; + } + + if ( typeof options == 'number' ) { + options = { + add : true, + visible : options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + if ( typeof options.visible == 'number' ) { + options.visible = { + min : options.visible, + max : options.visible + }; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/columns/_typings.d.ts b/src/addons/columns/_typings.d.ts new file mode 100644 index 0000000..736c647 --- /dev/null +++ b/src/addons/columns/_typings.d.ts @@ -0,0 +1,19 @@ +/** Options for the columns add-on. */ +interface mmOptionsColumns { + + /** Whether or not a to split up the panels in multiple columns. */ + add ?: boolean + + /** Map for the visible columns. */ + visible ?: mmOptionsColumnsVisible +} + +/** Map for the visible columns. */ +interface mmOptionsColumnsVisible { + + /** The minimum number of visible columns. */ + min ?: number + + /** The maximum number of visible columns. */ + max ?: number +} diff --git a/src/addons/columns/mmenu.columns.scss b/src/addons/columns/mmenu.columns.scss new file mode 100644 index 0000000..5486b5c --- /dev/null +++ b/src/addons/columns/mmenu.columns.scss @@ -0,0 +1,58 @@ +@import '../../mixins', '../../includes', '../../variables'; + +[class*='mm-menu_columns-'] { + transition-property: width; + + .mm-panels { + > .mm-panel { + right: auto; + transition-property: width, transform; + + &_opened, + &_opened-parent { + display: block !important; + } + } + } +} + +[class*='mm-panel_columns-'] { + border-right: 1px solid; + border-color: inherit; +} + +.mm-menu_columns-1 .mm-panel_columns-0, +.mm-menu_columns-2 .mm-panel_columns-1, +.mm-menu_columns-3 .mm-panel_columns-2, +.mm-menu_columns-4 .mm-panel_columns-3 { + border-right: none; +} + +@include mm_columns_size(0); +@include mm_columns_size(1); +@include mm_columns_size(2); +@include mm_columns_size(3); +@include mm_columns_size(4); + +@if ($mm_include_positioning_top or $mm_include_positioning_bottom) { + [class*='mm-menu_columns-'] { + &.mm-menu_position { + &-bottom, + &-top { + width: 100%; + max-width: 100%; + min-width: 100%; + } + } + } +} + +@if ($mm_include_positioning_front) { + .mm-wrapper_opening [class*='mm-menu_columns-'] { + &.mm-menu_position { + &-front { + transition-property: width, min-width, max-width, transform; + } + } + } +} diff --git a/src/addons/columns/mmenu.columns.ts b/src/addons/columns/mmenu.columns.ts new file mode 100644 index 0000000..3180afe --- /dev/null +++ b/src/addons/columns/mmenu.columns.ts @@ -0,0 +1,137 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.columns = options; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.columns); + this.opts.columns = extend(options, Mmenu.options.columns); + + // Add the columns + if (options.add) { + options.visible.min = Math.max(1, Math.min(6, options.visible.min)); + options.visible.max = Math.max( + options.visible.min, + Math.min(6, options.visible.max) + ); + + /** Columns related clasnames for the menu. */ + var colm = []; + + /** Columns related clasnames for the panels. */ + var colp = []; + + /** Classnames to remove from panels in favor of showing columns. */ + var rmvc = [ + 'mm-panel_opened', + 'mm-panel_opened-parent', + 'mm-panel_highest' + ]; + + for (var i = 0; i <= options.visible.max; i++) { + colm.push('mm-menu_columns-' + i); + colp.push('mm-panel_columns-' + i); + } + rmvc.push(...colp); + + // Close all later opened panels + this.bind('openPanel:before', (panel: HTMLElement) => { + /** The parent panel. */ + var parent: HTMLElement; + + if (panel) { + parent = panel['mmParent']; + } + + if (!parent) { + return; + } + + parent = parent.closest('.mm-panel') as HTMLElement; + if (!parent) { + return; + } + + var classname = parent.className; + if (!classname.length) { + return; + } + classname = classname.split('mm-panel_columns-')[1]; + if (!classname) { + return; + } + + var colnr = parseInt(classname.split(' ')[0], 10) + 1; + + while (colnr > 0) { + panel = DOM.children( + this.node.pnls, + '.mm-panel_columns-' + colnr + )[0]; + if (panel) { + colnr++; + panel.classList.add('mm-hidden'); + + // IE11: + rmvc.forEach(classname => { + panel.classList.remove(classname); + }); + + // Better browsers: + // panel.classList.remove(...rmvc); + } else { + colnr = -1; + break; + } + } + }); + + this.bind('openPanel:start', (panel: HTMLElement) => { + var columns = DOM.children( + this.node.pnls, + '.mm-panel_opened-parent' + ).length; + if (!panel.matches('.mm-panel_opened-parent')) { + columns++; + } + columns = Math.min( + options.visible.max, + Math.max(options.visible.min, columns) + ); + + // IE11: + colm.forEach(classname => { + this.node.menu.classList.remove(classname); + }); + + // Better browsers: + // this.node.menu.classList.remove(...colm); + + this.node.menu.classList.add('mm-menu_columns-' + columns); + + var panels: HTMLElement[] = []; + DOM.children(this.node.pnls, '.mm-panel').forEach(panel => { + // IE11: + colp.forEach(classname => { + panel.classList.remove(classname); + }); + + // Better browsers: + // panel.classList.remove(...colp); + + if (panel.matches('.mm-panel_opened-parent')) { + panels.push(panel); + } + }); + + panels.push(panel); + panels.slice(-options.visible.max).forEach((panel, p) => { + panel.classList.add('mm-panel_columns-' + p); + }); + }); + } +} diff --git a/src/addons/counters/_counters.rtl.scss b/src/addons/counters/_counters.rtl.scss new file mode 100644 index 0000000..3bf52d2 --- /dev/null +++ b/src/addons/counters/_counters.rtl.scss @@ -0,0 +1,8 @@ +@if ($mm_include_rtl) { + [dir='rtl'] .mm-counter { + text-align: left; + float: left; + padding-left: 0; + padding-right: $mm_padding * 2; + } +} diff --git a/src/addons/counters/_includes.scss b/src/addons/counters/_includes.scss new file mode 100644 index 0000000..b9f1dd3 --- /dev/null +++ b/src/addons/counters/_includes.scss @@ -0,0 +1 @@ +$mm_include_counters: true !default; diff --git a/src/addons/counters/_options.ts b/src/addons/counters/_options.ts new file mode 100644 index 0000000..b4759b8 --- /dev/null +++ b/src/addons/counters/_options.ts @@ -0,0 +1,34 @@ +const options: mmOptionsCounters = { + add: false, + addTo: 'panels', + count: false +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options: mmOptionsCounters +): mmOptionsCounters { + if (typeof options == 'boolean') { + options = { + add: options, + addTo: 'panels', + count: options + }; + } + + if (typeof options != 'object') { + options = {}; + } + + if (options.addTo == 'panels') { + options.addTo = '.mm-listview'; + } + + return options; +} diff --git a/src/addons/counters/_typings.d.ts b/src/addons/counters/_typings.d.ts new file mode 100644 index 0000000..0cf4e50 --- /dev/null +++ b/src/addons/counters/_typings.d.ts @@ -0,0 +1,12 @@ +/** Options for the counters add-on. */ +interface mmOptionsCounters { + + /** Whether or not to automatically append a counter to each menu item that has a submenu. */ + add ?: boolean + + /** Where to add the counters. */ + addTo ?: string + + /** Whether or not to automatically count the number of items in the submenu. */ + count ?: boolean +} diff --git a/src/addons/counters/_variables.scss b/src/addons/counters/_variables.scss new file mode 100644 index 0000000..aeab820 --- /dev/null +++ b/src/addons/counters/_variables.scss @@ -0,0 +1 @@ +$mm_counterWidth: $mm_btnSize !default; diff --git a/src/addons/counters/mmenu.counters.scss b/src/addons/counters/mmenu.counters.scss new file mode 100644 index 0000000..f0bd463 --- /dev/null +++ b/src/addons/counters/mmenu.counters.scss @@ -0,0 +1,23 @@ +@import '../../mixins', '../../includes', '../../variables'; + +$mm_module: '.mm-counter'; + +#{$mm_module} { + @if ($mm_IE11Fallbacks) { + color: $mm_dimmedTextColor; + } + + display: block; + padding-left: $mm_padding * 2; + float: right; + text-align: right; + color: var(--mm-color-text-dimmed); +} + +@if ($mm_include_searchfield) { + .mm-listitem_nosubitems > #{$mm_module} { + display: none; + } +} + +@import 'counters.rtl'; diff --git a/src/addons/counters/mmenu.counters.ts b/src/addons/counters/mmenu.counters.ts new file mode 100644 index 0000000..688e908 --- /dev/null +++ b/src/addons/counters/mmenu.counters.ts @@ -0,0 +1,79 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.counters = options; + +// Add the classnames. +Mmenu.configs.classNames.counters = { + counter: 'Counter' +}; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.counters); + this.opts.counters = extend(options, Mmenu.options.counters); + + // Refactor counter class + this.bind('initListview:after', (listview: HTMLElement) => { + var cntrclss = this.conf.classNames.counters.counter, + counters = DOM.find(listview, '.' + cntrclss); + + counters.forEach(counter => { + DOM.reClass(counter as HTMLElement, cntrclss, 'mm-counter'); + }); + }); + + // Add the counters after a listview is initiated. + if (options.add) { + this.bind('initListview:after', (listview: HTMLElement) => { + if (!listview.matches(options.addTo)) { + return; + } + + var parent: HTMLElement = listview.closest('.mm-panel')['mmParent']; + if (parent) { + // Check if no counter already excists. + if (!DOM.find(parent, '.mm-counter').length) { + let btn = DOM.children(parent, '.mm-btn')[0]; + if (btn) { + btn.prepend(DOM.create('span.mm-counter')); + } + } + } + }); + } + + if (options.count) { + const count = (listview?: HTMLElement) => { + var panels: HTMLElement[] = listview + ? [listview.closest('.mm-panel') as HTMLElement] + : DOM.children(this.node.pnls, '.mm-panel'); + + panels.forEach(panel => { + var parent: HTMLElement = panel['mmParent']; + + if (!parent) { + return; + } + + var counter = DOM.find(parent, '.mm-counter')[0]; + if (!counter) { + return; + } + + var listitems: HTMLElement[] = []; + DOM.children(panel, '.mm-listview').forEach(listview => { + listitems.push(...DOM.children(listview)); + }); + + counter.innerHTML = DOM.filterLI(listitems).length.toString(); + }); + }; + + this.bind('initListview:after', count); + this.bind('updateListview', count); + } +} diff --git a/src/addons/dividers/_includes.scss b/src/addons/dividers/_includes.scss new file mode 100644 index 0000000..a79d8e9 --- /dev/null +++ b/src/addons/dividers/_includes.scss @@ -0,0 +1 @@ +$mm_include_dividers: true !default; diff --git a/src/addons/dividers/_options.ts b/src/addons/dividers/_options.ts new file mode 100644 index 0000000..426ccb2 --- /dev/null +++ b/src/addons/dividers/_options.ts @@ -0,0 +1,31 @@ +const options: mmOptionsDividers = { + add: false, + addTo: 'panels' +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options: mmOptionsDividers +): mmOptionsDividers { + if (typeof options == 'boolean') { + options = { + add: options + }; + } + + if (typeof options != 'object') { + options = {}; + } + + if (options.addTo == 'panels') { + options.addTo = '.mm-listview'; + } + + return options; +} diff --git a/src/addons/dividers/_typings.d.ts b/src/addons/dividers/_typings.d.ts new file mode 100644 index 0000000..eb5866b --- /dev/null +++ b/src/addons/dividers/_typings.d.ts @@ -0,0 +1,8 @@ +/** Options for the dividers add-on. */ +interface mmOptionsDividers { + /** Whether or not to automatically add dividers to the menu (dividing the listitems alphabetically). */ + add?: boolean; + + /** Where to add the dividers. */ + addTo?: string; +} diff --git a/src/addons/dividers/mmenu.dividers.scss b/src/addons/dividers/mmenu.dividers.scss new file mode 100644 index 0000000..17d9123 --- /dev/null +++ b/src/addons/dividers/mmenu.dividers.scss @@ -0,0 +1,53 @@ +@import '../../mixins', '../../includes', '../../variables'; + +$mm_module: '.mm-divider'; + +#{$mm_module} { + @if ($mm_IE11Fallbacks) { + position: relative; + min-height: $mm_lineHeight; + padding: (($mm_listitemSize * 0.65) - $mm_lineHeight) * 0.5; + background: $mm_backgroundColor; + + &:before { + background: $mm_highlightedBackgroundColor; + } + } + + @include mm_ellipsis; + + @supports (position: sticky) { + position: sticky; + z-index: 2; + top: 0; + + .mm-navbar_sticky:not(.mm-hidden) ~ .mm-listview & { + top: var(--mm-navbar-size); + } + } + + min-height: var(--mm-line-height); + padding: calc( + ((var(--mm-listitem-size) * 0.65) - var(--mm-line-height)) * 0.5 + ); + padding-right: $mm_padding; + padding-left: $mm_listitemIndent; + + font-size: 75%; + text-transform: uppercase; + background: var(--mm-color-background); + + opacity: 1; + transition: opacity $mm_transitionDuration $mm_transitionFunction; + + &:before { + content: ''; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: -1; + background: var(--mm-color-background-highlight); + } +} diff --git a/src/addons/dividers/mmenu.dividers.ts b/src/addons/dividers/mmenu.dividers.ts new file mode 100644 index 0000000..882948a --- /dev/null +++ b/src/addons/dividers/mmenu.dividers.ts @@ -0,0 +1,56 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.dividers = options; + +// Add the classnames. +Mmenu.configs.classNames.divider = 'Divider'; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.dividers); + this.opts.dividers = extend(options, Mmenu.options.dividers); + + // Refactor divider classname + this.bind('initListview:after', listview => { + DOM.children(listview).forEach(listitem => { + DOM.reClass(listitem, this.conf.classNames.divider, 'mm-divider'); + if (listitem.matches('.mm-divider')) { + listitem.classList.remove('mm-listitem'); + } + }); + }); + + // Add dividers + if (options.add) { + this.bind('initListview:after', (listview: HTMLElement) => { + if (!listview.matches(options.addTo)) { + return; + } + + DOM.find(listview, '.mm-divider').forEach(divider => { + divider.remove(); + }); + + var lastletter = '', + listitems = DOM.children(listview); + + DOM.filterLI(listitems).forEach(listitem => { + let letter = DOM.children(listitem, '.mm-listitem__text')[0] + .textContent.trim() + .toLowerCase()[0]; + + if (letter.length && letter != lastletter) { + lastletter = letter; + let divider = DOM.create('li.mm-divider'); + divider.textContent = letter; + + listview.insertBefore(divider, listitem); + } + }); + }); + } +} diff --git a/src/addons/drag/_drag.open.ts b/src/addons/drag/_drag.open.ts new file mode 100644 index 0000000..7f542e2 --- /dev/null +++ b/src/addons/drag/_drag.open.ts @@ -0,0 +1,277 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import DragEvents from '../../_modules/dragevents/index'; +import * as DOM from '../../_modules/dom'; +import * as events from '../../_modules/eventlisteners'; +import * as media from '../../_modules/matchmedia'; + +/** Instance of the DragEvents class. */ +var dragInstance: DragEvents = null; + +/** THe node that can be dragged. */ +var dragNode: HTMLElement = null; + +/** How far the page (or menu) can be dragged. */ +var maxDistance: number = 0; + +export default function(this: Mmenu, page) { + /** Variables that vary for each menu position (top, right, bottom, left. front, back). */ + var vars: mmLooseObject = {}; + + /** Whether or not the page or menu is actually being moved. */ + var moving: boolean = false; + + /** + * Add the dragging events. + */ + const addEvents = () => { + if (dragNode) { + // Prepare the page or menu to be moved. + events.on(dragNode, 'dragStart', evnt => { + if (evnt['detail'].direction == vars.direction) { + moving = true; + + // Class prevents interaction with the page. + this.node.wrpr.classList.add('mm-wrapper_dragging'); + + // Prepare the menu to be opened. + this._openSetup(); + this.trigger('open:start'); + + // Get the maximum distance to move out the page or menu. + maxDistance = this.node.menu[ + vars.axis == 'x' ? 'clientWidth' : 'clientHeight' + ]; + } + }); + + // Move the page or menu when dragging. + events.on(dragNode, 'dragMove', evnt => { + if (evnt['detail'].axis == vars.axis) { + if (moving) { + var distance = + evnt['detail'][ + 'distance' + vars.axis.toUpperCase() + ]; + switch (vars.position) { + case 'right': + case 'bottom': + distance = Math.min( + Math.max(distance, -maxDistance), + 0 + ); + break; + + default: + distance = Math.max( + Math.min(distance, maxDistance), + 0 + ); + } + + // Deviate for position front (the menu starts out of view). + if (vars.zposition == 'front') { + switch (vars.position) { + case 'right': + case 'bottom': + distance += maxDistance; + break; + + default: + distance -= maxDistance; + break; + } + } + + vars.slideOutNodes.forEach(node => { + node.style['transform'] = + 'translate' + + vars.axis.toUpperCase() + + '(' + + distance + + 'px)'; + }); + } + } + }); + + // Stop the page or menu from being moved. + events.on(dragNode, 'dragEnd', evnt => { + if (evnt['detail'].axis == vars.axis) { + if (moving) { + moving = false; + this.node.wrpr.classList.remove('mm-wrapper_dragging'); + + vars.slideOutNodes.forEach(node => { + node.style['transform'] = ''; + }); + + // Determine if the menu should open or close. + let open = + Math.abs( + evnt['detail'][ + 'distance' + vars.axis.toUpperCase() + ] + ) >= + maxDistance * 0.75; + + if (!open) { + let movement = + evnt['detail'][ + 'movement' + vars.axis.toUpperCase() + ]; + switch (vars.position) { + case 'right': + case 'bottom': + open = movement <= 0; + break; + + default: + open = movement >= 0; + break; + } + } + + if (open) { + this._openStart(); + } else { + this.close(); + } + } + } + }); + } + }; + + /** + * Remove the dragging events. + */ + const removeEvents = () => { + if (dragNode) { + events.off(dragNode, 'dragStart'); + events.off(dragNode, 'dragMove'); + events.off(dragNode, 'dragEnd'); + } + }; + + let addMatchMedia = () => { + var queries = Object.keys(this.opts.extensions); + if (queries.length) { + // A media query that'll match if any of the other media query matches: + // set the defaults if it doesn't match. + media.add( + queries.join(', '), + () => {}, + () => { + vars = getPositionVars(vars, [], this.node.menu); + } + ); + + // The other media queries. + queries.forEach(query => { + media.add( + query, + () => { + vars = getPositionVars( + vars, + this.opts.extensions[query], + this.node.menu + ); + }, + () => {} + ); + }); + + // No extensions, just use the defaults. + } else { + vars = getPositionVars(vars, [], this.node.menu); + } + }; + + // Remove events from previous "page" + removeEvents(); + + // Store new "page" + dragNode = page; + + // Initialize the drag events. + dragInstance = new DragEvents(dragNode); + + addMatchMedia(); + addMatchMedia = () => {}; + + addEvents(); +} + +const getPositionVars = ( + vars: mmLooseObject, + extensions: string[], + menu: HTMLElement +) => { + // Default position and z-position. + vars.position = 'left'; + vars.zposition = 'back'; + + // Find position. + ['right', 'top', 'bottom'].forEach(pos => { + if (extensions.indexOf('position-' + pos) > -1) { + vars.position = pos; + } + }); + + // Find z-position. + ['front', 'top', 'bottom'].forEach(pos => { + if (extensions.indexOf('position-' + pos) > -1) { + vars.zposition = 'front'; + } + }); + + // Set the area where the dragging can start. + dragInstance.area = { + top: vars.position == 'bottom' ? '75%' : 0, + right: vars.position == 'left' ? '75%' : 0, + bottom: vars.position == 'top' ? '75%' : 0, + left: vars.position == 'right' ? '75%' : 0 + }; + + // What side of the menu to measure (width or height). + // What axis to drag the menu along (x or y). + switch (vars.position) { + case 'top': + case 'bottom': + vars.axis = 'y'; + break; + + default: + vars.axis = 'x'; + } + + // What direction to drag in. + switch (vars.position) { + case 'top': + vars.direction = 'Down'; + break; + + case 'right': + vars.direction = 'Left'; + break; + + case 'bottom': + vars.direction = 'Up'; + break; + + default: + vars.direction = 'Right'; + } + + // What nodes to slide out while dragging. + switch (vars.zposition) { + case 'front': + vars.slideOutNodes = [menu]; + break; + + default: + vars.slideOutNodes = DOM.find(document.body, '.mm-slideout'); + } + + return vars; +}; diff --git a/src/addons/drag/_includes.scss b/src/addons/drag/_includes.scss new file mode 100644 index 0000000..940e12c --- /dev/null +++ b/src/addons/drag/_includes.scss @@ -0,0 +1 @@ +$mm_include_drag: true !default; diff --git a/src/addons/drag/_options.ts b/src/addons/drag/_options.ts new file mode 100644 index 0000000..a9c02fb --- /dev/null +++ b/src/addons/drag/_options.ts @@ -0,0 +1,25 @@ +const options: mmOptionsDrag = { + open: false, + node: null +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions(options: mmOptionsDrag): mmOptionsDrag { + if (typeof options == 'boolean') { + options = { + open: options + }; + } + + if (typeof options != 'object') { + options = {}; + } + + return options; +} diff --git a/src/addons/drag/_typings.d.ts b/src/addons/drag/_typings.d.ts new file mode 100644 index 0000000..aab4de7 --- /dev/null +++ b/src/addons/drag/_typings.d.ts @@ -0,0 +1,8 @@ +/** Options for the drag add-on. */ +interface mmOptionsDrag { + /** Whether or not to open the menu when dragging the page. */ + open?: boolean; + + /** The element on which the user can drag to open the menu. */ + node?: HTMLElement; +} diff --git a/src/addons/drag/mmenu.drag.scss b/src/addons/drag/mmenu.drag.scss new file mode 100644 index 0000000..d99a689 --- /dev/null +++ b/src/addons/drag/mmenu.drag.scss @@ -0,0 +1,17 @@ +@import '../../mixins', '../../includes', '../../variables'; + +.mm-wrapper_dragging { + .mm-menu, + .mm-slideout { + transition-duration: 0s !important; + user-select: none !important; + } + + .mm-menu { + pointer-events: none !important; + } + + .mm-wrapper__blocker { + display: none !important; + } +} diff --git a/src/addons/drag/mmenu.drag.ts b/src/addons/drag/mmenu.drag.ts new file mode 100644 index 0000000..5d01b24 --- /dev/null +++ b/src/addons/drag/mmenu.drag.ts @@ -0,0 +1,24 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import dragOpen from './_drag.open'; +import { extend } from '../../_modules/helpers'; + +// Add the options and configs. +Mmenu.options.drag = options; + +export default function(this: Mmenu) { + if (!this.opts.offCanvas) { + return; + } + + var options = extendShorthandOptions(this.opts.drag); + this.opts.drag = extend(options, Mmenu.options.drag); + + // Drag open the menu + if (options.open) { + this.bind('setPage:after', page => { + dragOpen.call(this, options.node || page); + }); + } +} diff --git a/src/addons/dropdown/_configs.ts b/src/addons/dropdown/_configs.ts new file mode 100644 index 0000000..d7ea4b7 --- /dev/null +++ b/src/addons/dropdown/_configs.ts @@ -0,0 +1,19 @@ +const configs : mmConfigsDropdown = { + offset: { + button: { + x: -5, + y: 5 + }, + viewport: { + x: 20, + y: 20 + } + }, + height: { + max: 880 + }, + width: { + max: 440 + } +}; +export default configs; \ No newline at end of file diff --git a/src/addons/dropdown/_includes.scss b/src/addons/dropdown/_includes.scss new file mode 100644 index 0000000..74b70a3 --- /dev/null +++ b/src/addons/dropdown/_includes.scss @@ -0,0 +1,2 @@ +$mm_include_dropdown: true !default; +$mm_include_dropdown_tip: $mm_include_dropdown !default; diff --git a/src/addons/dropdown/_options.ts b/src/addons/dropdown/_options.ts new file mode 100644 index 0000000..3c52054 --- /dev/null +++ b/src/addons/dropdown/_options.ts @@ -0,0 +1,37 @@ +const options : mmOptionsDropdown = { + drop: false, + fitViewport: true, + event: 'click', + position: {}, + tip: true +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsDropdown +) : mmOptionsDropdown { + + if ( typeof options == 'boolean' && options ) { + options = { + drop: options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + if ( typeof options.position == 'string' ) { + options.position = { + of: options.position + }; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/dropdown/_typings.d.ts b/src/addons/dropdown/_typings.d.ts new file mode 100644 index 0000000..f1b54f0 --- /dev/null +++ b/src/addons/dropdown/_typings.d.ts @@ -0,0 +1,72 @@ +/** Options for the dropdown add-on. */ +interface mmOptionsDropdown { + + /** Whether or not to open the menu as a dropdown from the menu-button. */ + drop ?: boolean + + /** The event to open and close the menu. */ + event ?: 'click' | 'hover' | 'click hover' | 'hover click' + + /** Whether or not to fit the menu in the viewport. */ + fitViewport ?: boolean + + /** Positioning options. */ + position ?: mmLooseObject + + /** Whether or not to prepend the menu with a tip pointing to the menu-button. */ + tip ?: boolean +} + +/** Positioning options for the dropdown add-on. */ +interface mmOptionsDropdownPosition { + + /** Query selector for the button to click. */ + of ?: string + + /** How to horizontally position the menu relative to the button. */ + x ?: 'left' | 'right' + + /** How to vertically position the menu relative to the button. */ + y ?: 'top' | 'bottom' +} + + +/** Configuration for the dropdown add-on. */ +interface mmConfigsDropdown { + + /** Offset confgiuration. */ + offset ?: mmConfigsDropdownOffset + + /** Height confgiuration. */ + height ?: mmConfigsDropdownDimensions + + /** Width confgiuration. */ + width ?: mmConfigsDropdownDimensions +} + +/** Offset configuration for the dropdown add-on. */ +interface mmConfigsDropdownOffset { + + /** Button positioning configuration. */ + button ?: mmConfigsDropdownOffsetPositions + + /** Viewport positioning configuration. */ + viewport ?: mmConfigsDropdownOffsetPositions +} + +/** Positioning configuration for the dropdown add-on. */ +interface mmConfigsDropdownOffsetPositions { + + /** The horizontal offset for the menu. */ + x ?: number + + /** The vertical offset for the menu. */ + y ?: number +} + +/** Dimensions configuration for the dropdown add-on. */ +interface mmConfigsDropdownDimensions { + + /** The maximum size of the menu. */ + max ?: number +} diff --git a/src/addons/dropdown/_variables.scss b/src/addons/dropdown/_variables.scss new file mode 100644 index 0000000..5c47faf --- /dev/null +++ b/src/addons/dropdown/_variables.scss @@ -0,0 +1,3 @@ +$mm_dropdownShadow: 0 2px 10px rgba( #000, 0.3 ) !default; +$mm_dropdownTipX: 20px !default; +$mm_dropdownTipY: 10px !default; diff --git a/src/addons/dropdown/mmenu.dropdown.scss b/src/addons/dropdown/mmenu.dropdown.scss new file mode 100644 index 0000000..d7c377b --- /dev/null +++ b/src/addons/dropdown/mmenu.dropdown.scss @@ -0,0 +1,71 @@ +@import '../../mixins', '../../includes', '../../variables'; + +@if ($mm_include_dropdown) { + .mm-menu_dropdown { + box-shadow: $mm_dropdownShadow; + height: percentage($mm_menuHeight); + } + + .mm-wrapper_dropdown { + .mm-slideout { + transform: none !important; + z-index: 0; + } + + @if ($mm_include_offcanvas_blocker) { + .mm-wrapper__blocker { + transition-delay: 0s !important; + z-index: 1; + } + } + + .mm-menu_dropdown { + z-index: 2; + } + + &.mm-wrapper_opened:not(.mm-wrapper_opening) .mm-menu_dropdown { + display: none; + } + } +} + +// Tip +@if ($mm_include_dropdown_tip) { + .mm-menu_tip { + &-left, + &-right, + &-top, + &-bottom { + &:before { + content: ''; + background: inherit; + box-shadow: $mm_dropdownShadow; + + display: block; + width: 15px; + height: 15px; + + position: absolute; + z-index: -1; + + transform: rotate(45deg); + } + } + + &-left:before { + left: 2 + $mm_dropdownTipX; + } + + &-right:before { + right: 2 + $mm_dropdownTipX; + } + + &-top:before { + top: 2 - $mm_dropdownTipY; + } + + &-bottom:before { + bottom: 2 - $mm_dropdownTipY; + } + } +} diff --git a/src/addons/dropdown/mmenu.dropdown.ts b/src/addons/dropdown/mmenu.dropdown.ts new file mode 100644 index 0000000..6f5e695 --- /dev/null +++ b/src/addons/dropdown/mmenu.dropdown.ts @@ -0,0 +1,223 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend, originalId } from '../../_modules/helpers'; + +// Add the options and configs. +Mmenu.options.dropdown = options; +Mmenu.configs.dropdown = configs; + +export default function(this: Mmenu) { + if (!this.opts.offCanvas) { + return; + } + + var options = extendShorthandOptions(this.opts.dropdown); + this.opts.dropdown = extend(options, Mmenu.options.dropdown); + + var configs = this.conf.dropdown; + + if (!options.drop) { + return; + } + + var button: HTMLElement; + + this.bind('initMenu:after', () => { + this.node.menu.classList.add('mm-menu_dropdown'); + + if (typeof options.position.of != 'string') { + let id = originalId(this.node.menu.id); + if (id) { + options.position.of = '[href="#' + id + '"]'; + } + } + + if (typeof options.position.of != 'string') { + return; + } + + // Get the button to put the menu next to + button = DOM.find(document.body, options.position.of)[0]; + + // Emulate hover effect + var events = options.event.split(' '); + if (events.length == 1) { + events[1] = events[0]; + } + + if (events[0] == 'hover') { + button.addEventListener( + 'mouseenter', + () => { + this.open(); + }, + { passive: true } + ); + } + + if (events[1] == 'hover') { + this.node.menu.addEventListener( + 'mouseleave', + () => { + this.close(); + }, + { passive: true } + ); + } + }); + + // Add/remove classname and style when opening/closing the menu + this.bind('open:start', () => { + this.node.menu['mmStyle'] = this.node.menu.getAttribute('style'); + this.node.wrpr.classList.add('mm-wrapper_dropdown'); + }); + + this.bind('close:finish', () => { + this.node.menu.setAttribute('style', this.node.menu['mmStyle']); + this.node.wrpr.classList.remove('mm-wrapper_dropdown'); + }); + + /** + * Find the position (x, y) and sizes (width, height) for the menu. + * + * @param {string} dir The direction to measure ("x" for horizontal, "y" for vertical) + * @param {object} obj The object where (previously) measured values are stored. + * @return {object} The object where measered values are stored. + */ + var getPosition = function( + this: Mmenu, + dir: string, + obj: mmLooseObject + ): mmLooseObject { + var css = obj[0], + cls = obj[1]; + + var _outerSize = dir == 'x' ? 'offsetWidth' : 'offsetHeight', + _startPos = dir == 'x' ? 'left' : 'top', + _stopPos = dir == 'x' ? 'right' : 'bottom', + _size = dir == 'x' ? 'width' : 'height', + _winSize = dir == 'x' ? 'innerWidth' : 'innerHeight', + _maxSize = dir == 'x' ? 'maxWidth' : 'maxHeight', + _position = null; + + var startPos = DOM.offset(button, _startPos), + stopPos = startPos + button[_outerSize], + windowSize = window[_winSize]; + + /** Offset for the menu relative to the button. */ + var offs = configs.offset.button[dir] + configs.offset.viewport[dir]; + + // Position set in option + if (options.position[dir]) { + switch (options.position[dir]) { + case 'left': + case 'bottom': + _position = 'after'; + break; + + case 'right': + case 'top': + _position = 'before'; + break; + } + } + + // Position not set in option, find most space + if (_position === null) { + _position = + startPos + (stopPos - startPos) / 2 < windowSize / 2 + ? 'after' + : 'before'; + } + + // Set position and max + var val, max; + if (_position == 'after') { + val = dir == 'x' ? startPos : stopPos; + max = windowSize - (val + offs); + + css[_startPos] = val + configs.offset.button[dir] + 'px'; + css[_stopPos] = 'auto'; + + if (options.tip) { + cls.push('mm-menu_tip-' + (dir == 'x' ? 'left' : 'top')); + } + } else { + val = dir == 'x' ? stopPos : startPos; + max = val - offs; + + css[_stopPos] = + 'calc( 100% - ' + (val - configs.offset.button[dir]) + 'px )'; + css[_startPos] = 'auto'; + + if (options.tip) { + cls.push('mm-menu_tip-' + (dir == 'x' ? 'right' : 'bottom')); + } + } + + if (options.fitViewport) { + css[_maxSize] = Math.min(configs[_size].max, max) + 'px'; + } + + return [css, cls]; + }; + function position(this: Mmenu) { + if (!this.vars.opened) { + return; + } + + this.node.menu.setAttribute('style', this.node.menu['mmStyle']); + + var obj: [mmLooseObject, string[]] = [{}, []]; + obj = getPosition.call(this, 'y', obj); + obj = getPosition.call(this, 'x', obj); + + for (let s in obj[0]) { + this.node.menu.style[s] = obj[0][s]; + } + + if (options.tip) { + var classnames = [ + 'mm-menu_tip-left', + 'mm-menu_tip-right', + 'mm-menu_tip-top', + 'mm-menu_tip-bottom' + ]; + + // IE11: + classnames.forEach(classname => { + this.node.menu.classList.remove(classname); + }); + obj[1].forEach(classname => { + this.node.menu.classList.add(classname); + }); + + // Better browsers: + // this.node.menu.classList.remove(...classnames); + // this.node.menu.classList.add(...obj[1]); + } + } + + this.bind('open:start', position); + + window.addEventListener( + 'resize', + evnt => { + position.call(this); + }, + { passive: true } + ); + + if (!this.opts.offCanvas.blockUI) { + window.addEventListener( + 'scroll', + evnt => { + position.call(this); + }, + { passive: true } + ); + } +} diff --git a/src/addons/fixedelements/_configs.ts b/src/addons/fixedelements/_configs.ts new file mode 100644 index 0000000..d8082f9 --- /dev/null +++ b/src/addons/fixedelements/_configs.ts @@ -0,0 +1,5 @@ +const configs: mmConfigsFixedelements = { + insertMethod: 'append', + insertSelector: 'body' +}; +export default configs; diff --git a/src/addons/fixedelements/_typings.d.ts b/src/addons/fixedelements/_typings.d.ts new file mode 100644 index 0000000..eab9cdc --- /dev/null +++ b/src/addons/fixedelements/_typings.d.ts @@ -0,0 +1,8 @@ +/** Configuration for the fixedElements add-on. */ +interface mmConfigsFixedelements { + /** How to insert the fixed element to the DOM. */ + insertMethod?: 'prepend' | 'append'; + + /** Query selector for the element the fixed element should be inserted in. */ + insertSelector?: string; +} diff --git a/src/addons/fixedelements/mmenu.fixedelements.ts b/src/addons/fixedelements/mmenu.fixedelements.ts new file mode 100644 index 0000000..ecd2a77 --- /dev/null +++ b/src/addons/fixedelements/mmenu.fixedelements.ts @@ -0,0 +1,31 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import configs from './_configs'; +import * as DOM from '../../_modules/dom'; + +// Add the configs. +Mmenu.configs.fixedElements = configs; + +// Add the classnames. +Mmenu.configs.classNames.fixedElements = { + fixed: 'Fixed' +}; + +export default function(this: Mmenu) { + if (!this.opts.offCanvas) { + return; + } + + var configs = this.conf.fixedElements; + + var _fixd: string, fixed: HTMLElement[], wrppr: HTMLElement; + + this.bind('setPage:after', (page: HTMLElement) => { + _fixd = this.conf.classNames.fixedElements.fixed; + wrppr = DOM.find(document, configs.insertSelector)[0]; + fixed = DOM.find(page, '.' + _fixd); + fixed.forEach(fxd => { + DOM.reClass(fxd, _fixd, 'mm-slideout'); + wrppr[configs.insertMethod](fxd); + }); + }); +} diff --git a/src/addons/iconbar/_includes.scss b/src/addons/iconbar/_includes.scss new file mode 100644 index 0000000..480299c --- /dev/null +++ b/src/addons/iconbar/_includes.scss @@ -0,0 +1,2 @@ +$mm_include_iconbar: true !default; +$mm_include_iconbar_tabs: $mm_include_iconbar !default; diff --git a/src/addons/iconbar/_options.ts b/src/addons/iconbar/_options.ts new file mode 100644 index 0000000..eb07bff --- /dev/null +++ b/src/addons/iconbar/_options.ts @@ -0,0 +1,41 @@ +import { type } from '../../_modules/helpers'; + +const options: mmOptionsIconbar = { + use: false, + top: [], + bottom: [], + position: 'left', + type: 'default' +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options: mmOptionsIconbar +): mmOptionsIconbar { + if (type(options) == 'array') { + options = { + use: true, + top: options as any + }; + } + + if (type(options) != 'object') { + options = {}; + } + + if (typeof options.use == 'undefined') { + options.use = true; + } + + if (typeof options.use == 'boolean' && options.use) { + options.use = true; + } + + return options; +} diff --git a/src/addons/iconbar/_typings.d.ts b/src/addons/iconbar/_typings.d.ts new file mode 100644 index 0000000..04536da --- /dev/null +++ b/src/addons/iconbar/_typings.d.ts @@ -0,0 +1,18 @@ +/** Options for the iconbar add-on. */ +interface mmOptionsIconbar { + + /** Whether or not (and at what breakpoint) to add an iconbar to the menu. */ + use ?: boolean | number | string, + + /** An array of strings (for text or HTML) or HTML elements for icons to put in the top of the iconbar. */ + top ?: string[] | HTMLElement[], + + /** An array of strings (for text or HTML) or HTML elements for icons to put in the bottom of the iconbar. */ + bottom ?: string[] | HTMLElement[], + + /** Where to position the iconbar in the menu. */ + position ?: 'left' | 'right' + + /** The type of iconbar. */ + type ?: 'default' | 'tabs' +} diff --git a/src/addons/iconbar/_variables.scss b/src/addons/iconbar/_variables.scss new file mode 100644 index 0000000..ffddd56 --- /dev/null +++ b/src/addons/iconbar/_variables.scss @@ -0,0 +1 @@ +$mm_iconbarSize: $mm_btnSize !default; diff --git a/src/addons/iconbar/mmenu.iconbar.scss b/src/addons/iconbar/mmenu.iconbar.scss new file mode 100644 index 0000000..cf4f952 --- /dev/null +++ b/src/addons/iconbar/mmenu.iconbar.scss @@ -0,0 +1,105 @@ +@import '../../mixins', '../../includes', '../../variables'; + +$mm_module: '.mm-iconbar'; + +:root { + --mm-iconbar-size: #{$mm_iconbarSize}; +} + +.mm-menu_iconbar { + &-left { + .mm-panels, + .mm-navbars_top, + .mm-navbars_bottom { + @if ($mm_IE11Fallbacks) { + margin-left: $mm_iconbarSize; + } + + margin-left: var(--mm-iconbar-size); + } + + #{$mm_module} { + border-right-width: 1px; + display: block; + left: 0; + } + } + + &-right { + .mm-panels, + .mm-navbars_top, + .mm-navbars_bottom { + @if ($mm_IE11Fallbacks) { + margin-right: $mm_iconbarSize; + } + + margin-right: var(--mm-iconbar-size); + } + + #{$mm_module} { + border-left-width: 1px; + display: block; + right: 0; + } + } +} + +#{$mm_module} { + @if ($mm_IE11Fallbacks) { + width: $mm_iconbarSize; + border-color: $mm_borderColor; + background: $mm_backgroundColor; + color: $mm_dimmedTextColor; + } + + display: none; + width: var(--mm-iconbar-size); + overflow: hidden; + box-sizing: border-box; + + position: absolute; + top: 0; + bottom: 0; + z-index: 2; + + border: 0 solid; + border-color: var(--mm-color-border); + background: var(--mm-color-background); + color: var(--mm-color-text-dimmed); + text-align: center; +} + +%mm_iconbar_part { + width: inherit; + position: absolute; + + > * { + box-sizing: border-box; + display: block; + padding: ($mm_btnSize / 4) 0; + } + + a, + a:hover { + text-decoration: none; + } +} +#{$mm_module}__top { + @extend %mm_iconbar_part; + top: 0; +} + +#{$mm_module}__bottom { + @extend %mm_iconbar_part; + bottom: 0; +} + +@if ($mm_include_iconbar_tabs) { + #{$mm_module}__tab_selected { + @if ($mm_IE11Fallbacks) { + background: $mm_emphasizedBackgroundColor; + } + + background: var(--mm-color-background-emphasis); + } +} diff --git a/src/addons/iconbar/mmenu.iconbar.ts b/src/addons/iconbar/mmenu.iconbar.ts new file mode 100644 index 0000000..9d6ef17 --- /dev/null +++ b/src/addons/iconbar/mmenu.iconbar.ts @@ -0,0 +1,120 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as media from '../../_modules/matchmedia'; +import { type, extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.iconbar = options; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.iconbar); + this.opts.iconbar = extend(options, Mmenu.options.iconbar); + + if (!options.use) { + return; + } + + var iconbar: HTMLElement; + + ['top', 'bottom'].forEach((position, n) => { + var ctnt = options[position]; + + // Extend shorthand options + if (type(ctnt) != 'array') { + ctnt = [ctnt]; + } + + // Create node + var part = DOM.create('div.mm-iconbar__' + position); + + // Add content + for (let c = 0, l = ctnt.length; c < l; c++) { + if (typeof ctnt[c] == 'string') { + part.innerHTML += ctnt[c]; + } else { + part.append(ctnt[c]); + } + } + + if (part.children.length) { + if (!iconbar) { + iconbar = DOM.create('div.mm-iconbar'); + } + iconbar.append(part); + } + }); + + // Add to menu + if (iconbar) { + // Add the iconbar. + this.bind('initMenu:after', () => { + this.node.menu.prepend(iconbar); + }); + + // En-/disable the iconbar. + let classname = 'mm-menu_iconbar-' + options.position; + let enable = () => { + this.node.menu.classList.add(classname); + Mmenu.sr_aria(iconbar, 'hidden', false); + }; + let disable = () => { + this.node.menu.classList.remove(classname); + Mmenu.sr_aria(iconbar, 'hidden', true); + }; + + if (typeof options.use == 'boolean') { + this.bind('initMenu:after', enable); + } else { + media.add(options.use, enable, disable); + } + + // Tabs + if (options.type == 'tabs') { + iconbar.classList.add('mm-iconbar_tabs'); + iconbar.addEventListener('click', evnt => { + var anchor = evnt.target as HTMLElement; + + if (!anchor.matches('a')) { + return; + } + + if (anchor.matches('.mm-iconbar__tab_selected')) { + evnt.stopImmediatePropagation(); + return; + } + + try { + var panel = this.node.menu.querySelector( + anchor.getAttribute('href') + )[0]; + + if (panel && panel.matches('.mm-panel')) { + evnt.preventDefault(); + evnt.stopImmediatePropagation(); + + this.openPanel(panel, false); + } + } catch (err) {} + }); + + const selectTab = (panel: HTMLElement) => { + DOM.find(iconbar, 'a').forEach(anchor => { + anchor.classList.remove('mm-iconbar__tab_selected'); + }); + + var anchor = DOM.find(iconbar, '[href="#' + panel.id + '"]')[0]; + if (anchor) { + anchor.classList.add('mm-iconbar__tab_selected'); + } else { + let parent: HTMLElement = panel['mmParent']; + if (parent) { + selectTab(parent.closest('.mm-panel') as HTMLElement); + } + } + }; + this.bind('openPanel:start', selectTab); + } + } +} diff --git a/src/addons/iconpanels/_iconpanels.rtl.scss b/src/addons/iconpanels/_iconpanels.rtl.scss new file mode 100644 index 0000000..e9fe5ed --- /dev/null +++ b/src/addons/iconpanels/_iconpanels.rtl.scss @@ -0,0 +1,15 @@ +@if ($mm_include_counters and $mm_include_iconpanels) { + [dir='rtl'] .mm-menu_iconpanel .mm-panels { + > .mm-panel { + left: 0; + right: auto; + transition-property: transform, width; + + &:not(.mm-panel_iconpanel-first):not(.mm-panel_iconpanel-0) { + border-left: none; + border-right: 1px solid; + border-color: inherit; + } + } + } +} diff --git a/src/addons/iconpanels/_includes.scss b/src/addons/iconpanels/_includes.scss new file mode 100644 index 0000000..c472bca --- /dev/null +++ b/src/addons/iconpanels/_includes.scss @@ -0,0 +1,2 @@ +$mm_include_iconpanels: true !default; +$mm_include_iconpanels_blocker: $mm_include_iconpanels !default; diff --git a/src/addons/iconpanels/_mixins.scss b/src/addons/iconpanels/_mixins.scss new file mode 100644 index 0000000..ced68af --- /dev/null +++ b/src/addons/iconpanels/_mixins.scss @@ -0,0 +1,9 @@ +@mixin mm_iconpanel_size($nr) { + .mm-panel_iconpanel-#{$nr} { + @if ($mm_IE11Fallbacks) { + width: calc(100% - #{$mm_iconpanelSize * $nr}); + } + + width: calc(100% - (var(--mm-iconpanel-size) * #{$nr})); + } +} diff --git a/src/addons/iconpanels/_options.ts b/src/addons/iconpanels/_options.ts new file mode 100644 index 0000000..ce62733 --- /dev/null +++ b/src/addons/iconpanels/_options.ts @@ -0,0 +1,40 @@ +const options : mmOptionsIconpanels = { + add: false, + blockPanel: true, + hideDivider: false, + hideNavbar: true, + visible: 3 +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsIconpanels +) : mmOptionsIconpanels { + + if ( typeof options == 'boolean' ) { + options = { + add : options + }; + } + + if ( typeof options == 'number' || + typeof options == 'string' + ) { + options = { + add : true, + visible : options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/iconpanels/_typings.d.ts b/src/addons/iconpanels/_typings.d.ts new file mode 100644 index 0000000..f975027 --- /dev/null +++ b/src/addons/iconpanels/_typings.d.ts @@ -0,0 +1,18 @@ +/** Options for the iconPanels add-on. */ +interface mmOptionsIconpanels { + + /** Whether or not a small part of parent panels should be visible. */ + add ?: boolean + + /** Whether or not to block the parent panels from interaction. */ + blockPanel ?: boolean + + /** Whether or not to hide dividers in parent panels, showing only the listitems. */ + hideDivider ?: boolean + + /** Whether or not to hide navbars in parent panels, showing only the listviews. */ + hideNavbar ?: boolean + + /** The number of visible parent panels. */ + visible ?: number | 'first' +} diff --git a/src/addons/iconpanels/_variables.scss b/src/addons/iconpanels/_variables.scss new file mode 100644 index 0000000..5c8c393 --- /dev/null +++ b/src/addons/iconpanels/_variables.scss @@ -0,0 +1 @@ +$mm_iconpanelSize: $mm_btnSize !default; diff --git a/src/addons/iconpanels/mmenu.iconpanels.scss b/src/addons/iconpanels/mmenu.iconpanels.scss new file mode 100644 index 0000000..fc01ff7 --- /dev/null +++ b/src/addons/iconpanels/mmenu.iconpanels.scss @@ -0,0 +1,69 @@ +@import '../../mixins', '../../includes', '../../variables'; + +:root { + --mm-iconpanel-size: #{$mm_iconpanelSize}; +} + +@include mm_iconpanel_size(1); +@include mm_iconpanel_size(2); +@include mm_iconpanel_size(3); + +.mm-panel_iconpanel-first { + ~ .mm-panel { + @if ($mm_IE11Fallbacks) { + width: calc(100% - #{$mm_iconpanelSize}); + } + + width: calc(100% - var(--mm-iconpanel-size)); + } +} + +.mm-menu_iconpanel .mm-panels { + > .mm-panel { + left: auto; + transition-property: transform, width; + + &_opened, + &_opened-parent { + display: block !important; + } + + &_opened-parent { + overflow-y: hidden; + transform: unset; + } + + &:not(.mm-panel_iconpanel-first):not(.mm-panel_iconpanel-0) { + border-left-width: 1px; + border-left-style: solid; + } + } +} + +.mm-menu_hidenavbar .mm-panel_opened-parent .mm-navbar, +.mm-menu_hidedivider .mm-panel_opened-parent .mm-divider { + opacity: 0; +} + +@if ($mm_include_iconpanels_blocker) { + .mm-panel__blocker { + background: inherit; + opacity: 0; + display: block; + + position: absolute; + top: 0; + right: 0; + left: 0; + z-index: 3; + + transition: opacity $mm_transitionDuration $mm_transitionFunction; + + .mm-panel_opened-parent & { + opacity: 0.6; + bottom: -100000px; + } + } +} + +@import 'iconpanels.rtl'; diff --git a/src/addons/iconpanels/mmenu.iconpanels.ts b/src/addons/iconpanels/mmenu.iconpanels.ts new file mode 100644 index 0000000..4ea72ed --- /dev/null +++ b/src/addons/iconpanels/mmenu.iconpanels.ts @@ -0,0 +1,126 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.iconPanels = options; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.iconPanels); + this.opts.iconPanels = extend(options, Mmenu.options.iconPanels); + + var keepFirst = false; + + if (options.visible == 'first') { + keepFirst = true; + options.visible = 1; + } + + options.visible = Math.min(3, Math.max(1, options.visible)); + options.visible++; + + // Add the iconpanels + if (options.add) { + this.bind('initMenu:after', () => { + let classnames = ['mm-menu_iconpanel']; + + if (options.hideNavbar) { + classnames.push('mm-menu_hidenavbar'); + } + + if (options.hideDivider) { + classnames.push('mm-menu_hidedivider'); + } + + // IE11: + classnames.forEach(classname => { + this.node.menu.classList.add(classname); + }); + + // Better browsers: + // this.node.menu.classList.add(...classnames); + }); + + let classnames = []; + if (!keepFirst) { + for (let i = 0; i <= options.visible; i++) { + classnames.push('mm-panel_iconpanel-' + i); + } + } + + this.bind('openPanel:start', (panel?: HTMLElement) => { + var panels = DOM.children(this.node.pnls, '.mm-panel'); + panel = panel || panels[0]; + + if (panel.parentElement.matches('.mm-listitem_vertical')) { + return; + } + + if (keepFirst) { + panels.forEach((panel, p) => { + panel.classList[p == 0 ? 'add' : 'remove']( + 'mm-panel_iconpanel-first' + ); + }); + } else { + // Remove the "iconpanel" classnames from all panels. + panels.forEach(panel => { + // IE11: + classnames.forEach(classname => { + panel.classList.remove(classname); + }); + + // Better browsers: + // panel.classList.remove(...classnames); + }); + + // Filter out panels that are not opened. + panels = panels.filter(panel => + panel.matches('.mm-panel_opened-parent') + ); + + // Add the current panel to the list. + let panelAdded = false; + panels.forEach(elem => { + if (panel === elem) { + panelAdded = true; + } + }); + if (!panelAdded) { + panels.push(panel); + } + + // Remove the "hidden" classname from all opened panels. + panels.forEach(panel => { + panel.classList.remove('mm-hidden'); + }); + + // Slice the opened panels to the max visible amount. + panels = panels.slice(-options.visible); + + // Add the "iconpanel" classnames. + panels.forEach((panel, p) => { + panel.classList.add('mm-panel_iconpanel-' + p); + }); + } + }); + + this.bind('initPanel:after', (panel: HTMLElement) => { + if ( + options.blockPanel && + !panel.parentElement.matches('.mm-listitem_vertical') && + !DOM.children(panel, '.mm-panel__blocker')[0] + ) { + let blocker = DOM.create('a.mm-panel__blocker'); + blocker.setAttribute( + 'href', + '#' + panel.closest('.mm-panel').id + ); + + panel.prepend(blocker); + } + }); + } +} diff --git a/src/addons/keyboardnavigation/_includes.scss b/src/addons/keyboardnavigation/_includes.scss new file mode 100644 index 0000000..4e6a931 --- /dev/null +++ b/src/addons/keyboardnavigation/_includes.scss @@ -0,0 +1 @@ +$mm_include_keyboardnavigation: true !default; diff --git a/src/addons/keyboardnavigation/_options.ts b/src/addons/keyboardnavigation/_options.ts new file mode 100644 index 0000000..f072d16 --- /dev/null +++ b/src/addons/keyboardnavigation/_options.ts @@ -0,0 +1,28 @@ +const options : mmOptionsKeyboardnavigation = { + enable: false, + enhance: false +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsKeyboardnavigation +) : mmOptionsKeyboardnavigation { + + if ( typeof options == 'boolean' || typeof options == 'string' ) { + options = { + enable: options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/keyboardnavigation/_typings.d.ts b/src/addons/keyboardnavigation/_typings.d.ts new file mode 100644 index 0000000..7ddbe29 --- /dev/null +++ b/src/addons/keyboardnavigation/_typings.d.ts @@ -0,0 +1,9 @@ +/** Options for the keyboardNavigation add-on. */ +interface mmOptionsKeyboardnavigation { + + /** Whether or not to enable navigating the menu with a keyboard. */ + enable ?: boolean | 'default' + + /** Whether or not to enhance the basic default keyboard navigation. */ + enhance ?: boolean +} diff --git a/src/addons/keyboardnavigation/mmenu.keyboardnavigation.scss b/src/addons/keyboardnavigation/mmenu.keyboardnavigation.scss new file mode 100644 index 0000000..88ee74d --- /dev/null +++ b/src/addons/keyboardnavigation/mmenu.keyboardnavigation.scss @@ -0,0 +1,29 @@ +@import '../../mixins', '../../includes', '../../variables'; + +.mm-menu_keyboardfocus { + &, + &.mm-menu_opened ~ .mm-wrapper__blocker { + a:focus { + @if ($mm_IE11Fallbacks) { + background: $mm_emphasizedBackgroundColor; + } + + background: var(--mm-color-background-emphasis); + outline: none; + } + } +} + +.mm-wrapper__blocker { + .mm-tabstart { + cursor: default; + display: block; + width: 100%; + height: 100%; + } + .mm-tabend { + opacity: 0; + position: absolute; + bottom: 0; + } +} diff --git a/src/addons/keyboardnavigation/mmenu.keyboardnavigation.ts b/src/addons/keyboardnavigation/mmenu.keyboardnavigation.ts new file mode 100644 index 0000000..c336ee0 --- /dev/null +++ b/src/addons/keyboardnavigation/mmenu.keyboardnavigation.ts @@ -0,0 +1,237 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as events from '../../_modules/eventlisteners'; +import * as support from '../../_modules/support'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.keyboardNavigation = options; + +export default function(this: Mmenu) { + // Keyboard navigation on touchscreens opens the virtual keyboard :/ + // Lets prevent that. + if (support.touch) { + return; + } + + var options = extendShorthandOptions(this.opts.keyboardNavigation); + this.opts.keyboardNavigation = extend( + options, + Mmenu.options.keyboardNavigation + ); + + // Enable keyboard navigation + if (options.enable) { + let menuStart = DOM.create('button.mm-tabstart.mm-sronly'), + menuEnd = DOM.create('button.mm-tabend.mm-sronly'), + blockerEnd = DOM.create('button.mm-tabend.mm-sronly'); + + this.bind('initMenu:after', () => { + if (options.enhance) { + this.node.menu.classList.add('mm-menu_keyboardfocus'); + } + + initWindow.call(this, options.enhance); + }); + + this.bind('initOpened:before', () => { + this.node.menu.prepend(menuStart); + this.node.menu.append(menuEnd); + DOM.children( + this.node.menu, + '.mm-navbars-top, .mm-navbars-bottom' + ).forEach(navbars => { + navbars.querySelectorAll('.mm-navbar__title').forEach(title => { + title.setAttribute('tabindex', '-1'); + }); + }); + }); + + this.bind('initBlocker:after', () => { + Mmenu.node.blck.append(blockerEnd); + DOM.children(Mmenu.node.blck, 'a')[0].classList.add('mm-tabstart'); + }); + + let focusable = 'input, select, textarea, button, label, a[href]'; + const setFocus = (panel?: HTMLElement) => { + panel = + panel || DOM.children(this.node.pnls, '.mm-panel_opened')[0]; + + var focus: HTMLElement = null; + + // Focus already is on an element in a navbar in this menu. + var navbar = document.activeElement.closest('.mm-navbar'); + if (navbar) { + if (navbar.closest('.mm-menu') == this.node.menu) { + return; + } + } + + // Set the focus to the first focusable element by default. + if (options.enable == 'default') { + // First visible anchor in a listview in the current panel. + focus = DOM.find( + panel, + '.mm-listview a[href]:not(.mm-hidden)' + )[0]; + + // First focusable and visible element in the current panel. + if (!focus) { + focus = DOM.find(panel, focusable + ':not(.mm-hidden)')[0]; + } + + // First focusable and visible element in a navbar. + if (!focus) { + let elements: HTMLElement[] = []; + DOM.children( + this.node.menu, + '.mm-navbars_top, .mm-navbars_bottom' + ).forEach(navbar => { + elements.push( + ...DOM.find(navbar, focusable + ':not(.mm-hidden)') + ); + }); + focus = elements[0]; + } + } + + // Default. + if (!focus) { + focus = DOM.children(this.node.menu, '.mm-tabstart')[0]; + } + + if (focus) { + focus.focus(); + } + }; + this.bind('open:finish', setFocus); + this.bind('openPanel:finish', setFocus); + + // Add screenreader / aria support. + this.bind('initOpened:after:sr-aria', () => { + [this.node.menu, Mmenu.node.blck].forEach(element => { + DOM.children(element, '.mm-tabstart, .mm-tabend').forEach( + tabber => { + Mmenu.sr_aria(tabber, 'hidden', true); + Mmenu.sr_role(tabber, 'presentation'); + } + ); + }); + }); + } +} + +/** + * Initialize the window for keyboard navigation. + * @param {boolean} enhance - Whether or not to also rich enhance the keyboard behavior. + **/ +const initWindow = function(this: Mmenu, enhance: boolean) { + // Re-enable tabbing in general + events.off(document.body, 'keydown.tabguard'); + + // Intersept the target when tabbing. + events.off(document.body, 'focusin.tabguard'); + events.on(document.body, 'focusin.tabguard', (evnt: KeyboardEvent) => { + if (this.node.wrpr.matches('.mm-wrapper_opened')) { + let target = evnt.target as HTMLElement; + + if (target.matches('.mm-tabend')) { + let next; + + // Jump from menu to blocker. + if (target.parentElement.matches('.mm-menu')) { + if (Mmenu.node.blck) { + next = Mmenu.node.blck; + } + } + + // Jump to opened menu. + if (target.parentElement.matches('.mm-wrapper__blocker')) { + next = DOM.find( + document.body, + '.mm-menu_offcanvas.mm-menu_opened' + )[0]; + } + + // If no available element found, stay in current element. + if (!next) { + next = target.parentElement; + } + + if (next) { + DOM.children(next, '.mm-tabstart')[0].focus(); + } + } + } + }); + + // Add Additional keyboard behavior. + events.off(document.body, 'keydown.navigate'); + events.on(document.body, 'keydown.navigate', (evnt: KeyboardEvent) => { + var target = evnt.target as HTMLElement; + var menu = target.closest('.mm-menu') as HTMLElement; + + if (menu) { + let api: mmApi = menu['mmApi']; + + if (!target.matches('input, textarea')) { + switch (evnt.keyCode) { + // press enter to toggle and check + case 13: + if ( + target.matches('.mm-toggle') || + target.matches('.mm-check') + ) { + target.dispatchEvent(new Event('click')); + } + break; + + // prevent spacebar or arrows from scrolling the page + case 32: // space + case 37: // left + case 38: // top + case 39: // right + case 40: // bottom + evnt.preventDefault(); + break; + } + } + + if (enhance) { + // special case for input + if (target.matches('input')) { + switch (evnt.keyCode) { + // empty searchfield with esc + case 27: + (target as HTMLInputElement).value = ''; + break; + } + } else { + let api: mmApi = menu['mmApi']; + + switch (evnt.keyCode) { + // close submenu with backspace + case 8: + let parent: HTMLElement = DOM.find( + menu, + '.mm-panel_opened' + )[0]['mmParent']; + if (parent) { + api.openPanel(parent.closest('.mm-panel')); + } + break; + + // close menu with esc + case 27: + if (menu.matches('.mm-menu_offcanvas')) { + api.close(); + } + break; + } + } + } + } + }); +}; diff --git a/src/addons/lazysubmenus/_options.ts b/src/addons/lazysubmenus/_options.ts new file mode 100644 index 0000000..4b8e205 --- /dev/null +++ b/src/addons/lazysubmenus/_options.ts @@ -0,0 +1,27 @@ +const options : mmOptionsLazysubmenus = { + load: false +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsLazysubmenus +) : mmOptionsLazysubmenus { + + if ( typeof options == 'boolean' ) { + options = { + load : options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/lazysubmenus/_typings.d.ts b/src/addons/lazysubmenus/_typings.d.ts new file mode 100644 index 0000000..5f88f8c --- /dev/null +++ b/src/addons/lazysubmenus/_typings.d.ts @@ -0,0 +1,6 @@ +/** Options for the lazySubmenus add-on. */ +interface mmOptionsLazysubmenus { + + /** Whether or not to lazy load submenus. */ + load ?: boolean +} diff --git a/src/addons/lazysubmenus/mmenu.lazysubmenus.ts b/src/addons/lazysubmenus/mmenu.lazysubmenus.ts new file mode 100644 index 0000000..1b8f608 --- /dev/null +++ b/src/addons/lazysubmenus/mmenu.lazysubmenus.ts @@ -0,0 +1,139 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.lazySubmenus = options; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.lazySubmenus); + this.opts.lazySubmenus = extend(options, Mmenu.options.lazySubmenus); + + if (options.load) { + // Prevent all sub panels from being initialized. + this.bind('initMenu:after', () => { + var panels: HTMLElement[] = []; + + // Find all potential subpanels. + DOM.find(this.node.pnls, 'li').forEach(listitem => { + panels.push( + ...DOM.children( + listitem, + this.conf.panelNodetype.join(', ') + ) + ); + }); + + // Filter out all non-panels and add the lazyload classes + panels + .filter(panel => !panel.matches('.mm-listview_inset')) + .filter(panel => !panel.matches('.mm-nolistview')) + .filter(panel => !panel.matches('.mm-nopanel')) + .forEach(panel => { + var classnames = [ + 'mm-panel_lazysubmenu', + 'mm-nolistview', + 'mm-nopanel' + ]; + + // IE11: + classnames.forEach(classname => { + panel.classList.add(classname); + }); + + // Better browsers: + // panel.classList.add(...classnames); + }); + }); + + // Prepare current and one level sub panels for initPanels + this.bind('initPanels:before', () => { + const panels = DOM.children( + this.node.pnls, + this.conf.panelNodetype.join(', ') + ); + + panels.forEach(panel => { + var filter = '.mm-panel_lazysubmenu', + children = DOM.find(panel, filter); + + if (panel.matches(filter)) { + children.unshift(panel); + } + children + .filter( + child => + !child.matches( + '.mm-panel_lazysubmenu .mm-panel_lazysubmenu' + ) + ) + .forEach(child => { + let classnames = [ + 'mm-panel_lazysubmenu', + 'mm-nolistview', + 'mm-nopanel' + ]; + + // IE11: + classnames.forEach(classname => { + child.classList.remove(classname); + }); + + // Better browsers: + // child.classList.remove(...classnames); + }); + }); + }); + + // initPanels for the default opened panel + this.bind('initOpened:before', () => { + var panels: HTMLElement[] = []; + DOM.find( + this.node.pnls, + '.' + this.conf.classNames.selected + ).forEach(listitem => { + panels.push(...DOM.parents(listitem, '.mm-panel_lazysubmenu')); + }); + + if (panels.length) { + panels.forEach(panel => { + let classnames = [ + 'mm-panel_lazysubmenu', + 'mm-nolistview', + 'mm-nopanel' + ]; + + // IE11: + classnames.forEach(classname => { + panel.classList.remove(classname); + }); + + // Better browsers: + // panel.classList.remove(...classnames); + }); + this.initPanel(panels[panels.length - 1]); + } + }); + + // initPanels for current- and sub panels before openPanel + this.bind('openPanel:before', (panel: HTMLElement) => { + var filter = '.mm-panel_lazysubmenu', + panels = DOM.find(panel, filter); + if (panel.matches(filter)) { + panels.unshift(panel); + } + panels = panels.filter( + panel => + !panel.matches( + '.mm-panel_lazysubmenu .mm-panel_lazysubmenu' + ) + ); + + panels.forEach(panel => { + this.initPanel(panel); + }); + }); + } +} diff --git a/src/addons/navbars/_configs.ts b/src/addons/navbars/_configs.ts new file mode 100644 index 0000000..11b91f5 --- /dev/null +++ b/src/addons/navbars/_configs.ts @@ -0,0 +1,7 @@ +const configs : mmConfigsNavbars = { + breadcrumbs: { + separator: '/', + removeFirst: false + } +}; +export default configs; \ No newline at end of file diff --git a/src/addons/navbars/_includes.scss b/src/addons/navbars/_includes.scss new file mode 100644 index 0000000..985ca0c --- /dev/null +++ b/src/addons/navbars/_includes.scss @@ -0,0 +1,6 @@ +$mm_include_navbars: true !default; +$mm_include_navbars_top: $mm_include_navbars !default; +$mm_include_navbars_bottom: $mm_include_navbars !default; +$mm_include_navbars_breadcrumbs: $mm_include_navbars !default; +$mm_include_navbars_searchfield: $mm_include_navbars !default; +$mm_include_navbars_tabs: $mm_include_navbars !default; diff --git a/src/addons/navbars/_mixins.scss b/src/addons/navbars/_mixins.scss new file mode 100644 index 0000000..e3f6129 --- /dev/null +++ b/src/addons/navbars/_mixins.scss @@ -0,0 +1,15 @@ +@mixin mm_navbar_tabs_borders( $top, $bottom, $last, $first ) { + .mm-navbars_#{$top} { + .mm-navbar_tabs:not( :#{$last}-child ) { + border-#{$bottom}-width: 1px; + border-#{$bottom}-style: solid; + } + .mm-navbar__tab_selected { + border-#{$bottom}: none; + margin-#{$bottom}: -1px; + } + .mm-navbar_tabs:#{$first}-child .mm-navbar__tab_selected { + border-#{$top}: none; + } + } +} diff --git a/src/addons/navbars/_navbar.breadcrumbs.scss b/src/addons/navbars/_navbar.breadcrumbs.scss new file mode 100644 index 0000000..689b7f3 --- /dev/null +++ b/src/addons/navbars/_navbar.breadcrumbs.scss @@ -0,0 +1,31 @@ +@if ($mm_include_navbars_breadcrumbs) { + .mm-navbar__breadcrumbs { + @include mm_ellipsis; + + flex: 1 1 50%; + display: flex; + justify-content: flex-start; + padding: 0 $mm_panelPadding; + overflow-x: auto; + -webkit-overflow-scrolling: touch; + + > * { + display: flex; + align-items: center; + justify-content: center; + padding-right: 6px; + } + + > a { + text-decoration: underline; + } + + &:not(:last-child) { + padding-right: 0; + } + + .mm-btn:not(.mm-hidden) + & { + padding-left: 0; + } + } +} diff --git a/src/addons/navbars/_navbar.breadcrumbs.ts b/src/addons/navbars/_navbar.breadcrumbs.ts new file mode 100644 index 0000000..5bd59a9 --- /dev/null +++ b/src/addons/navbars/_navbar.breadcrumbs.ts @@ -0,0 +1,69 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; + +export default function(this: Mmenu, navbar: HTMLElement) { + // Add content + var breadcrumbs = DOM.create('div.mm-navbar__breadcrumbs'); + navbar.append(breadcrumbs); + + this.bind('initNavbar:after', (panel: HTMLElement) => { + if (panel.querySelector('.mm-navbar__breadcrumbs')) { + return; + } + + DOM.children(panel, '.mm-navbar')[0].classList.add('mm-hidden'); + + var crumbs: string[] = [], + breadcrumbs = DOM.create('span.mm-navbar__breadcrumbs'), + current = panel, + first = true; + + while (current) { + current = current.closest('.mm-panel') as HTMLElement; + + if (!current.parentElement.matches('.mm-listitem_vertical')) { + let title = DOM.find(current, '.mm-navbar__title span')[0]; + if (title) { + let text = title.textContent; + if (text.length) { + crumbs.unshift( + first + ? '' + text + '' + : '' + + text + + '' + ); + } + } + first = false; + } + current = current['mmParent']; + } + + if (this.conf.navbars.breadcrumbs.removeFirst) { + crumbs.shift(); + } + + breadcrumbs.innerHTML = crumbs.join( + '' + + this.conf.navbars.breadcrumbs.separator + + '' + ); + DOM.children(panel, '.mm-navbar')[0].append(breadcrumbs); + }); + + // Update for to opened panel + this.bind('openPanel:start', (panel: HTMLElement) => { + var crumbs = panel.querySelector('.mm-navbar__breadcrumbs'); + breadcrumbs.innerHTML = crumbs ? crumbs.innerHTML : ''; + }); + + // Add screenreader / aria support + this.bind('initNavbar:after:sr-aria', (panel: HTMLElement) => { + DOM.find(panel, '.mm-breadcrumbs a').forEach(anchor => { + Mmenu.sr_aria(anchor, 'owns', anchor.getAttribute('href').slice(1)); + }); + }); +} diff --git a/src/addons/navbars/_navbar.close.ts b/src/addons/navbars/_navbar.close.ts new file mode 100644 index 0000000..bdf3207 --- /dev/null +++ b/src/addons/navbars/_navbar.close.ts @@ -0,0 +1,21 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; + +export default function(this: Mmenu, navbar: HTMLElement) { + // Add content + var close = DOM.create('a.mm-btn.mm-btn_close.mm-navbar__btn'); + navbar.append(close); + + // Update to page node + this.bind('setPage:after', (page: HTMLElement) => { + close.setAttribute('href', '#' + page.id); + }); + + // Add screenreader / text support + this.bind('setPage:after:sr-text', () => { + close.innerHTML = Mmenu.sr_text( + this.i18n(this.conf.screenReader.text.closeMenu) + ); + Mmenu.sr_aria(close, 'owns', close.getAttribute('href').slice(1)); + }); +} diff --git a/src/addons/navbars/_navbar.prev.ts b/src/addons/navbars/_navbar.prev.ts new file mode 100644 index 0000000..93d4b90 --- /dev/null +++ b/src/addons/navbars/_navbar.prev.ts @@ -0,0 +1,48 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; + +export default function(this: Mmenu, navbar: HTMLElement) { + // Add content. + var prev = DOM.create('a.mm-btn.mm-btn_prev.mm-navbar__btn'); + navbar.append(prev); + + this.bind('initNavbar:after', (panel: HTMLElement) => { + DOM.children(panel, '.mm-navbar')[0].classList.add('mm-hidden'); + }); + + // Update to opened panel. + var org: HTMLElement; + var _url, _txt; + + this.bind('openPanel:start', (panel: HTMLElement) => { + if (panel.parentElement.matches('.mm-listitem_vertical')) { + return; + } + + org = panel.querySelector('.' + this.conf.classNames.navbars.panelPrev); + if (!org) { + org = panel.querySelector('.mm-navbar__btn.mm-btn_prev'); + } + + _url = org ? org.getAttribute('href') : ''; + _txt = org ? org.innerHTML : ''; + + if (_url) { + prev.setAttribute('href', _url); + } else { + prev.removeAttribute('href'); + } + + prev.classList[_url || _txt ? 'remove' : 'add']('mm-hidden'); + prev.innerHTML = _txt; + }); + + // Add screenreader / aria support + this.bind('initNavbar:after:sr-aria', (panel: HTMLElement) => { + Mmenu.sr_aria(panel.querySelector('.mm-navbar'), 'hidden', true); + }); + this.bind('openPanel:start:sr-aria', (panel: HTMLElement) => { + Mmenu.sr_aria(prev, 'hidden', prev.matches('.mm-hidden')); + Mmenu.sr_aria(prev, 'owns', (prev.getAttribute('href') || '').slice(1)); + }); +} diff --git a/src/addons/navbars/_navbar.searchfield.scss b/src/addons/navbars/_navbar.searchfield.scss new file mode 100644 index 0000000..b20165d --- /dev/null +++ b/src/addons/navbars/_navbar.searchfield.scss @@ -0,0 +1,11 @@ +@if ($mm_include_navbars_searchfield) { + .mm-navbar__searchfield { + .mm-btn:not(.mm-hidden) + & .mm-searchfield__input { + padding-left: 0; + } + + &:not(:last-child) .mm-searchfield__input { + padding-right: 0; + } + } +} diff --git a/src/addons/navbars/_navbar.searchfield.ts b/src/addons/navbars/_navbar.searchfield.ts new file mode 100644 index 0000000..5efc87c --- /dev/null +++ b/src/addons/navbars/_navbar.searchfield.ts @@ -0,0 +1,15 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; +import { type } from '../../_modules/helpers'; + +export default function(this: Mmenu, navbar: HTMLElement) { + if (type(this.opts.searchfield) != 'object') { + this.opts.searchfield = {}; + } + + var searchfield = DOM.create('div.mm-navbar__searchfield'); + navbar.append(searchfield); + + this.opts.searchfield.add = true; + this.opts.searchfield.addTo = [searchfield]; +} diff --git a/src/addons/navbars/_navbar.tabs.scss b/src/addons/navbars/_navbar.tabs.scss new file mode 100644 index 0000000..187629e --- /dev/null +++ b/src/addons/navbars/_navbar.tabs.scss @@ -0,0 +1,133 @@ +$mm_module: '.mm-navbar'; + +@if ($mm_include_navbars_tabs) { + // All tabs. + #{$mm_module}_tabs { + > * { + padding: 0 $mm_padding; + border: 1px solid transparent; + } + } + + // Selected tab. + #{$mm_module}__tab_selected { + @if ($mm_IE11Fallbacks) { + background: $mm_backgroundColor; + color: $mm_textColor; + + &:not(:first-child) { + border-left-color: $mm_borderColor; + } + + &:not(:last-child) { + border-right-color: $mm_borderColor; + } + } + + background: var(--mm-color-background); + + // TODO: not specific enough :/ overriden by .mm-menu a :/ :/ :/ + color: var(--mm-color-text); + // /TODO + &:not(:first-child) { + border-left-color: var(--mm-color-border); + } + + &:not(:last-child) { + border-right-color: var(--mm-color-border); + } + } +} + +// Navbars at the top. +@if ($mm_include_navbars_top) { + .mm-navbars_top { + #{$mm_module}_tabs { + border-bottom: none; + } + + // Borders. + #{$mm_module}_tabs > * { + @if ($mm_IE11Fallbacks) { + border-bottom-color: $mm_borderColor; + } + + border-bottom-color: var(--mm-color-border); + } + + #{$mm_module}__tab_selected { + @if ($mm_IE11Fallbacks) { + border-top-color: $mm_borderColor; + } + + border-top-color: var(--mm-color-border); + border-bottom-color: transparent; + } + + // Backgrounds + &.mm-navbars_has-tabs { + #{$mm_module} { + @if ($mm_IE11Fallbacks) { + background: $mm_emphasizedBackgroundColor; + } + + background: var(--mm-color-background-emphasis); + } + + #{$mm_module}_tabs ~ #{$mm_module} { + @if ($mm_IE11Fallbacks) { + background: $mm_backgroundColor; + } + + background: var(--mm-color-background); + } + } + } +} + +@if ($mm_include_navbars_bottom) { + .mm-navbars_bottom { + #{$mm_module}_tabs { + &:first-child { + border-top: none; + } + } + + // Borders. + #{$mm_module}_tabs > * { + @if ($mm_IE11Fallbacks) { + border-top-color: $mm_borderColor; + } + + border-top-color: var(--mm-color-border); + } + + #{$mm_module}__tab_selected { + @if ($mm_IE11Fallbacks) { + border-bottom-color: $mm_borderColor; + } + + border-bottom-color: var(--mm-color-border); + border-top-color: transparent; + } + // Backgrounds + &.mm-navbars_has-tabs { + #{$mm_module} { + @if ($mm_IE11Fallbacks) { + background: $mm_backgroundColor; + } + + background: var(--mm-color-background); + } + + #{$mm_module}_tabs, + #{$mm_module}_tabs ~ #{$mm_module} { + @if ($mm_IE11Fallbacks) { + background: $mm_emphasizedBackgroundColor; + } + + background: var(--mm-color-background-emphasis); + } + } + } +} diff --git a/src/addons/navbars/_navbar.tabs.ts b/src/addons/navbars/_navbar.tabs.ts new file mode 100644 index 0000000..142d90b --- /dev/null +++ b/src/addons/navbars/_navbar.tabs.ts @@ -0,0 +1,48 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; + +export default function(this: Mmenu, navbar: HTMLElement) { + navbar.classList.add('mm-navbar_tabs'); + navbar.parentElement.classList.add('mm-navbars_has-tabs'); + + var anchors = DOM.children(navbar, 'a'); + + navbar.addEventListener('click', evnt => { + var anchor = evnt.target as HTMLElement; + if (!anchor.matches('a')) { + return; + } + if (anchor.matches('.mm-navbar__tab_selected')) { + evnt.stopImmediatePropagation(); + return; + } + + try { + this.openPanel( + this.node.menu.querySelector(anchor.getAttribute('href')), + false + ); + evnt.stopImmediatePropagation(); + } catch (err) {} + }); + + function selectTab(this: Mmenu, panel: HTMLElement) { + anchors.forEach(anchor => { + anchor.classList.remove('mm-navbar__tab_selected'); + }); + + var anchor = anchors.filter(anchor => + anchor.matches('[href="#' + panel.id + '"]') + )[0]; + if (anchor) { + anchor.classList.add('mm-navbar__tab_selected'); + } else { + var parent: HTMLElement = panel['mmParent']; + if (parent) { + selectTab.call(this, parent.closest('.mm-panel')); + } + } + } + + this.bind('openPanel:start', selectTab); +} diff --git a/src/addons/navbars/_navbar.title.ts b/src/addons/navbars/_navbar.title.ts new file mode 100644 index 0000000..89e6e21 --- /dev/null +++ b/src/addons/navbars/_navbar.title.ts @@ -0,0 +1,74 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; + +export default function(this: Mmenu, navbar: HTMLElement) { + // Add content to the navbar. + let title = DOM.create('a.mm-navbar__title'); + let titleText = DOM.create('span'); + + title.append(titleText); + navbar.append(title); + + // Update the title to the opened panel. + var _url, _txt; + var original: HTMLElement; + + this.bind('openPanel:start', (panel: HTMLElement) => { + // Do nothing in a vertically expanding panel. + if (panel.parentElement.matches('.mm-listitem_vertical')) { + return; + } + + // Find the original title in the opened panel. + original = panel.querySelector( + '.' + this.conf.classNames.navbars.panelTitle + ); + if (!original) { + original = panel.querySelector('.mm-navbar__title span'); + } + + // Get the URL for the title. + _url = + original && original.closest('a') + ? original.closest('a').getAttribute('href') + : ''; + + if (_url) { + title.setAttribute('href', _url); + } else { + title.removeAttribute('href'); + } + + // Get the text for the title. + _txt = original ? original.innerHTML : ''; + titleText.innerHTML = _txt; + }); + + // Add screenreader / aria support + var prev: HTMLElement; + + this.bind('openPanel:start:sr-aria', (panel: HTMLElement) => { + if (this.opts.screenReader.text) { + if (!prev) { + var navbars = DOM.children( + this.node.menu, + '.mm-navbars_top, .mm-navbars_bottom' + ); + navbars.forEach(navbar => { + let btn = navbar.querySelector('.mm-btn_prev'); + if (btn) { + prev = btn as HTMLElement; + } + }); + } + + if (prev) { + var hidden = true; + if (this.opts.navbar.titleLink == 'parent') { + hidden = !prev.matches('.mm-hidden'); + } + Mmenu.sr_aria(title, 'hidden', hidden); + } + } + }); +} diff --git a/src/addons/navbars/_options.ts b/src/addons/navbars/_options.ts new file mode 100644 index 0000000..4ab7c56 --- /dev/null +++ b/src/addons/navbars/_options.ts @@ -0,0 +1,39 @@ +const options : mmOptionsNavbarsNavbar[] = []; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsNavbarsNavbar +) : mmOptionsNavbarsNavbar { + + if ( typeof options == 'boolean' && options ) { + options = {}; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + if ( typeof options.content == 'undefined' ) { + options.content = [ 'prev', 'title' ]; + } + + if ( !( options.content instanceof Array ) ) { + options.content = [ options.content ]; + } + + if ( typeof options.use == 'undefined' ) { + options.use = true; + } + + if ( typeof options.use == 'boolean' && options.use ) { + options.use = true; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/navbars/_typings.d.ts b/src/addons/navbars/_typings.d.ts new file mode 100644 index 0000000..e55fcd5 --- /dev/null +++ b/src/addons/navbars/_typings.d.ts @@ -0,0 +1,36 @@ +/** "navbar" options for the navbars add-on. */ +interface mmOptionsNavbarsNavbar { + + /** An array of HTML elements or strings (for text or HTML or the keywords: "breadcrumbs", "close", "next", "prev", "searchfield", "title"). */ + content ?: string[] | HTMLElement[] + + /** The size of the navbar. */ + height ?: 1 | 2 | 3 | 4 + + /** The position for the navbar. */ + position ?: 'top' | 'bottom' + + /** Whether or not to enable the navbar. */ + use ?: boolean | string | number + + /** The type of navbar. */ + type ?: 'tabs' +} + + +/** Configuration for the navbars add-on. */ +interface mmConfigsNavbars { + + /** Creadcrumbs configuration. */ + breadcrumbs ?: mmConfigsNavbarsBreadcrumbs +} + +/** Breadcrumbs configuration for the navbars add-on. */ +interface mmConfigsNavbarsBreadcrumbs { + + /** The separator between two breadcrumbs. */ + separator ?: string + + /** Whether or not to remove the first breadcrumb. */ + removeFirst ?: boolean +} diff --git a/src/addons/navbars/mmenu.navbars.scss b/src/addons/navbars/mmenu.navbars.scss new file mode 100644 index 0000000..712d2b3 --- /dev/null +++ b/src/addons/navbars/mmenu.navbars.scss @@ -0,0 +1,34 @@ +@import '../../mixins', '../../includes', '../../variables'; + +%mm_navbars { +} + +@if ($mm_include_navbars_top) { + .mm-navbars_top { + flex-shrink: 0; + + .mm-navbar:not(:last-child) { + border-bottom: none; + } + } +} + +@if ($mm_include_navbars_bottom) { + .mm-navbars_bottom { + flex-shrink: 0; + + .mm-navbar { + border-bottom: none; + + &:first-child { + @if ($mm_IE11Fallbacks) { + border-top: 1px solid $mm_borderColor; + } + + border-top: 1px solid var(--mm-color-border); + } + } + } +} + +@import 'navbar.searchfield', 'navbar.breadcrumbs', 'navbar.tabs'; diff --git a/src/addons/navbars/mmenu.navbars.ts b/src/addons/navbars/mmenu.navbars.ts new file mode 100644 index 0000000..7fc1070 --- /dev/null +++ b/src/addons/navbars/mmenu.navbars.ts @@ -0,0 +1,147 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as media from '../../_modules/matchmedia'; + +// Add the options and configs. +Mmenu.options.navbars = options; +Mmenu.configs.navbars = configs; + +// Add the classnames. +Mmenu.configs.classNames.navbars = { + panelPrev: 'Prev', + panelTitle: 'Title' +}; + +import breadcrumbs from './_navbar.breadcrumbs'; +import close from './_navbar.close'; +import prev from './_navbar.prev'; +import searchfield from './_navbar.searchfield'; +import title from './_navbar.title'; + +Navbars.navbarContents = { + breadcrumbs, + close, + prev, + searchfield, + title +}; + +import tabs from './_navbar.tabs'; + +Navbars.navbarTypes = { + tabs +}; + +export default function Navbars(this: Mmenu) { + var navs = this.opts.navbars; + + if (typeof navs == 'undefined') { + return; + } + + if (!(navs instanceof Array)) { + navs = [navs]; + } + + var navbars = {}; + + if (!navs.length) { + return; + } + + navs.forEach(options => { + options = extendShorthandOptions(options); + + if (!options.use) { + return false; + } + + // Create the navbar element. + var navbar = DOM.create('div.mm-navbar'); + + // Get the position for the navbar. + var position = options.position; + + // Restrict the position to either "bottom" or "top" (default). + if (position !== 'bottom') { + position = 'top'; + } + + // Create the wrapper for the navbar position. + if (!navbars[position]) { + navbars[position] = DOM.create('div.mm-navbars_' + position); + } + navbars[position].append(navbar); + + // Add content to the navbar. + for (let c = 0, l = options.content.length; c < l; c++) { + let ctnt = options.content[c]; + + // The content is a string. + if (typeof ctnt == 'string') { + let func = Navbars.navbarContents[ctnt]; + + // The content refers to one of the navbar-presets ("prev", "title", etc). + if (typeof func == 'function') { + // Call the preset function. + func.call(this, navbar); + + // The content is just HTML. + } else { + // Add the HTML. + + // Wrap the HTML in a single node + let node = DOM.create('span'); + node.innerHTML = ctnt; + + // If there was only a single node, use that. + let children = DOM.children(node); + if (children.length == 1) { + node = children[0]; + } + + navbar.append(node); + } + + // The content is not a string, it must be an element. + } else { + navbar.append(ctnt); + } + } + + // The type option is set. + if (typeof options.type == 'string') { + // The function refers to one of the navbar-presets ("tabs"). + let func = Navbars.navbarTypes[options.type]; + if (typeof func == 'function') { + // Call the preset function. + func.call(this, navbar); + } + } + + // En-/disable the navbar. + let enable = () => { + navbar.classList.remove('mm-hidden'); + Mmenu.sr_aria(navbar, 'hidden', false); + }; + let disable = () => { + navbar.classList.add('mm-hidden'); + Mmenu.sr_aria(navbar, 'hidden', true); + }; + if (typeof options.use != 'boolean') { + media.add(options.use, enable, disable); + } + }); + + // Add to menu. + this.bind('initMenu:after', () => { + for (let position in navbars) { + this.node.menu[position == 'bottom' ? 'append' : 'prepend']( + navbars[position] + ); + } + }); +} diff --git a/src/addons/pagescroll/_configs.ts b/src/addons/pagescroll/_configs.ts new file mode 100644 index 0000000..33ea44d --- /dev/null +++ b/src/addons/pagescroll/_configs.ts @@ -0,0 +1,5 @@ +const configs: mmConfigsPagescroll = { + scrollOffset: 0, + updateOffset: 50 +}; +export default configs; diff --git a/src/addons/pagescroll/_options.ts b/src/addons/pagescroll/_options.ts new file mode 100644 index 0000000..8888f5e --- /dev/null +++ b/src/addons/pagescroll/_options.ts @@ -0,0 +1,28 @@ +const options : mmOptionsPagescroll = { + scroll: false, + update: false +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsPagescroll +) : mmOptionsPagescroll { + + if ( typeof options == 'boolean' ) { + options = { + scroll: options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/pagescroll/_typings.d.ts b/src/addons/pagescroll/_typings.d.ts new file mode 100644 index 0000000..d12922e --- /dev/null +++ b/src/addons/pagescroll/_typings.d.ts @@ -0,0 +1,17 @@ +/** Options for the pageScroll add-on. */ +interface mmOptionsPagescroll { + /** Whether or not to smoothly scroll to a section on the page after clicking a menu item. */ + scroll?: boolean; + + /** Whether or not to automatically make a menu item appear "selected" when scrolling through the section it is linked to. */ + update?: boolean; +} + +/** Configuration for the pageScroll add-on. */ +interface mmConfigsPagescroll { + /** Amount of pixels to scroll past the top of a section after clicking a menu item. */ + scrollOffset?: number; + + /** Amount of pixels to scroll past the top of a section before its menu item will appear "selected". */ + updateOffset?: number; +} diff --git a/src/addons/pagescroll/mmenu.pagescroll.ts b/src/addons/pagescroll/mmenu.pagescroll.ts new file mode 100644 index 0000000..942dbc2 --- /dev/null +++ b/src/addons/pagescroll/mmenu.pagescroll.ts @@ -0,0 +1,136 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; + +// Add the options and configs. +Mmenu.options.pageScroll = options; +Mmenu.configs.pageScroll = configs; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.pageScroll); + this.opts.pageScroll = extend(options, Mmenu.options.pageScroll); + + var configs = this.conf.pageScroll; + + /** The currently "active" section */ + var section: HTMLElement; + + function scrollTo() { + if (section) { + // section.scrollIntoView({ behavior: 'smooth' }); + window.scrollTo({ + top: + section.getBoundingClientRect().top + + document.scrollingElement.scrollTop - + configs.scrollOffset, + behavior: 'smooth' + }); + } + section = null; + } + function anchorInPage(href: string) { + try { + if (href != '#' && href.slice(0, 1) == '#') { + return Mmenu.node.page.querySelector(href) as HTMLElement; + } + return null; + } catch (err) { + return null; + } + } + + // Scroll to section after clicking menu item. + if (options.scroll) { + this.bind('close:finish', () => { + scrollTo(); + }); + } + + // Add click behavior. + // Prevents default behavior when clicking an anchor. + if (this.opts.offCanvas && options.scroll) { + this.clck.push((anchor: HTMLElement, args: mmClickArguments) => { + section = null; + + // Don't continue if the clicked anchor is not in the menu. + if (!args.inMenu) { + return; + } + + // Don't continue if the targeted section is not on the page. + var href = anchor.getAttribute('href'); + + section = anchorInPage(href); + if (!section) { + return; + } + + // If the sidebar add-on is "expanded"... + if ( + this.node.menu.matches('.mm-menu_sidebar-expanded') && + this.node.wrpr.matches('.mm-wrapper_sidebar-expanded') + ) { + // ... scroll the page to the section. + scrollTo(); + + // ... otherwise... + } else { + // ... close the menu. + return { + close: true + }; + } + }); + } + + // Update selected menu item after scrolling. + if (options.update) { + let scts: HTMLElement[] = []; + + this.bind('initListview:after', (listview: HTMLElement) => { + let listitems = DOM.children(listview, '.mm-listitem'); + DOM.filterLIA(listitems).forEach(anchor => { + var href = anchor.getAttribute('href'); + var section = anchorInPage(href); + + if (section) { + scts.unshift(section); + } + }); + }); + + let _selected = -1; + + window.addEventListener('scroll', evnt => { + var scrollTop = window.scrollY; + + for (var s = 0; s < scts.length; s++) { + if (scts[s].offsetTop < scrollTop + configs.updateOffset) { + if (_selected !== s) { + _selected = s; + + let panel = DOM.children( + this.node.pnls, + '.mm-panel_opened' + )[0]; + + let listitems = DOM.find(panel, '.mm-listitem'); + let anchors = DOM.filterLIA(listitems); + + anchors = anchors.filter(anchor => + anchor.matches('[href="#' + scts[s].id + '"]') + ); + + if (anchors.length) { + this.setSelected(anchors[0].parentElement); + } + } + break; + } + } + }); + } +} diff --git a/src/addons/searchfield/_configs.ts b/src/addons/searchfield/_configs.ts new file mode 100644 index 0000000..5ae0a0f --- /dev/null +++ b/src/addons/searchfield/_configs.ts @@ -0,0 +1,7 @@ +const configs : mmConfigsSearchfield = { + clear: false, + form: false, + input: false, + submit: false +}; +export default configs; \ No newline at end of file diff --git a/src/addons/searchfield/_includes.scss b/src/addons/searchfield/_includes.scss new file mode 100644 index 0000000..0569e20 --- /dev/null +++ b/src/addons/searchfield/_includes.scss @@ -0,0 +1,3 @@ +$mm_include_searchfield: true !default; +$mm_include_searchfield_btn: $mm_include_searchfield !default; +$mm_include_searchfield_searchpanel: $mm_include_searchfield !default; diff --git a/src/addons/searchfield/_options.ts b/src/addons/searchfield/_options.ts new file mode 100644 index 0000000..d30ad0a --- /dev/null +++ b/src/addons/searchfield/_options.ts @@ -0,0 +1,65 @@ +const options : mmOptionsSearchfield = { + add: false, + addTo: 'panels', + cancel: false, + noResults: 'No results found.', + placeholder: 'Search', + panel: { + add: false, + dividers: true, + fx: 'none', + id: null, + splash: null, + title: 'Search' + }, + search: true, + showTextItems: false, + showSubPanels: true +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsSearchfield +) : mmOptionsSearchfield { + + if ( typeof options == 'boolean' ) { + options = { + add: options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + if ( typeof options.panel == 'boolean' ) { + options.panel = { + add: options.panel + }; + } + + if ( typeof options.panel != 'object' ) { + options.panel = {}; + } + + // Extend logical options. + if ( options.addTo == 'panel' ) { + options.panel.add = true; + } + + if ( options.panel.add ) { + options.showSubPanels = false; + + if ( options.panel.splash ) { + options.cancel = true; + } + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/searchfield/_typings.d.ts b/src/addons/searchfield/_typings.d.ts new file mode 100644 index 0000000..0061f09 --- /dev/null +++ b/src/addons/searchfield/_typings.d.ts @@ -0,0 +1,69 @@ +/** Options for the searchfield add-on. */ +interface mmOptionsSearchfield { + + /** Whether or not to automatically prepend a searchfield to the menu or (some of the) panels. */ + add ?: boolean + + /** Where to add the searchfield(s). */ + addTo ?: string | HTMLElement[] + + /** Whether or not to add a cancel button after the searchfield. */ + cancel ?: boolean + + /** The text to show when no results are found. */ + noResults ?: string + + /** The placeholder text for the searchfield. */ + placeholder ?: string + + /** Panel options */ + panel ?: mmOptionsSearchfieldPanel + + /** Whether or not to immediately search through the listitems while typing. */ + search ?: boolean + + /** Whether or not to show its sub-panels if a listitem matches the search. */ + showTextItems ?: boolean + + /** Whether or not to show listitems without an anchor in the results. */ + showSubPanels ?: boolean +} + +/** Panel options for the searchfield add-on. */ +interface mmOptionsSearchfieldPanel { + + /** Whether or not to add a search panel for showing the search results. */ + add ?: boolean + + /** Whether or not to add dividers to divide the results per panel. */ + dividers ?: boolean + + /** Effect for opening and closing the search panel. */ + fx ?: string | boolean + + /** The ID to add to the search panel. */ + id ?: string + + /** HTML to show in the search panel before searching. */ + splash ?: string + + /** The title in the navbar for the search panel. */ + title ?: string +} + + +/** Configuration for the searchfield add-on. */ +interface mmConfigsSearchfield { + + /** Wraps the searchfield in a FORM element with the specified keys/values as attributes. */ + form ?: mmLooseObject | boolean + + /** Adds the specified keys/values as attributes to the searchfield. */ + input ?: mmLooseObject | boolean + + /** Whether or not to add a clear button to the searchfield. */ + clear ?: boolean + + /** Whether or not to add a submit button to the searchfield. */ + submit ?: boolean +} diff --git a/src/addons/searchfield/mmenu.searchfield.scss b/src/addons/searchfield/mmenu.searchfield.scss new file mode 100644 index 0000000..a1ab062 --- /dev/null +++ b/src/addons/searchfield/mmenu.searchfield.scss @@ -0,0 +1,135 @@ +@import '../../mixins', '../../includes', '../../variables'; + +$mm_module: '.mm-searchfield'; + +#{$mm_module} { + @if ($mm_IE11Fallbacks) { + height: $mm_navbarSize; + + input { + height: $mm_navbarSize * 0.7; + line-height: $mm_navbarSize * 0.7; + + &, + &:hover, + &:focus { + background: $mm_highlightedBackgroundColor; + color: $mm_textColor; + } + } + } + + display: flex; + flex-grow: 1; + height: var(--mm-navbar-size); + padding: 0; + overflow: hidden; + + input { + display: block; + width: 100%; + max-width: 100%; + height: calc(var(--mm-navbar-size) * 0.7); + min-height: unset; + max-height: unset; + margin: 0; + padding: 0 $mm_padding; + box-sizing: border-box; + border: none !important; + border-radius: 4px; + line-height: calc(var(--mm-navbar-size) * 0.7); + box-shadow: none !important; + outline: none !important; + font: inherit; + font-size: inherit; + + &, + &:hover, + &:focus { + background: var(--mm-color-background-highlight); + color: var(--mm-color-text); + } + } + + input::-ms-clear { + display: none; + } +} + +#{$mm_module}__input { + display: flex; + flex: 1; + align-items: center; + position: relative; + width: 100%; + max-width: 100%; + padding: 0 $mm_padding; + box-sizing: border-box; +} + +.mm-panel__noresultsmsg { + @if ($mm_IE11Fallbacks) { + color: $mm_dimmedTextColor; + } + + padding: $mm_btnSize 0; + color: var(--mm-color-text-dimmed); + text-align: center; + font-size: 150%; +} + +@if ($mm_include_searchfield_btn) { + #{$mm_module}__btn { + position: absolute; + right: 0; + top: 0; + bottom: 0; + } +} + +@if ($mm_include_searchfield_searchpanel) { + .mm-panel_search { + left: 0 !important; + right: 0 !important; + width: 100% !important; + border-left: none !important; + } + + #{$mm_module}__cancel { + @if ($mm_IE11Fallbacks) { + line-height: $mm_navbarSize; + } + + display: block; + padding-right: $mm_padding; + margin-right: -100px; + line-height: var(--mm-navbar-size); + text-decoration: none; + + transition: margin $mm_transitionDuration $mm_transitionFunction; + } + + #{$mm_module}__cancel-active { + margin-right: 0; + } +} + +// Listitem with no search results in the child panel. +.mm-listitem_nosubitems { + > .mm-listitem__btn { + display: none; + } + + > .mm-listitem__text { + padding-right: $mm_padding; + } +} + +// Listitem with only search results in the child panel (not in the listitem itself). +.mm-listitem_onlysubitems { + > .mm-listitem__text:not(.mm-listitem__btn) { + // This should (sort of) disable the anchor in the listitem. + z-index: -1; + pointer-events: none; + } +} diff --git a/src/addons/searchfield/mmenu.searchfield.ts b/src/addons/searchfield/mmenu.searchfield.ts new file mode 100644 index 0000000..96f04aa --- /dev/null +++ b/src/addons/searchfield/mmenu.searchfield.ts @@ -0,0 +1,661 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import translate from './translations/translate'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as events from '../../_modules/eventlisteners'; +import { type, extend } from '../../_modules/helpers'; + +// Add the translations. +translate(); + +// Add the options and configs. +Mmenu.options.searchfield = options; +Mmenu.configs.searchfield = configs; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.searchfield); + this.opts.searchfield = extend(options, Mmenu.options.searchfield); + + var configs = this.conf.searchfield; + + if (!options.add) { + return; + } + + // Blur searchfield + this.bind('close:start', () => { + DOM.find(this.node.menu, '.mm-searchfield').forEach(input => { + input.blur(); + }); + }); + + this.bind('initPanel:after', (panel: HTMLElement) => { + var searchpanel: HTMLElement = null; + + // Add the search panel + if (options.panel.add) { + searchpanel = initSearchPanel.call(this); + } + + // Add the searchfield + var addTo: HTMLElement[] = null; + switch (options.addTo) { + case 'panels': + addTo = [panel]; + break; + + case 'panel': + addTo = [searchpanel]; + break; + + default: + if (typeof options.addTo == 'string') { + addTo = DOM.find(this.node.menu, options.addTo); + } else if (type(options.addTo) == 'array') { + addTo = options.addTo; + } + break; + } + + addTo.forEach(form => { + form = initSearchfield.call(this, form); + if (options.search && form) { + initSearching.call(this, form); + } + }); + + // Add the no-results message + if (options.noResults) { + initNoResultsMsg.call( + this, + options.panel.add ? searchpanel : panel + ); + } + }); + + // Add click behavior. + // Prevents default behavior when clicking an anchor + this.clck.push((anchor: HTMLElement, args: mmClickArguments) => { + if (args.inMenu) { + if (anchor.matches('.mm-searchfield__btn')) { + // Clicking the clear button + if (anchor.matches('.mm-btn_close')) { + let form = anchor.closest('.mm-searchfield') as HTMLElement, + input = DOM.find(form, 'input')[0] as HTMLInputElement; + + input.value = ''; + this.search(input); + + return true; + } + + // Clicking the submit button + if (anchor.matches('.mm-btn_next')) { + let form = anchor.closest('form'); + if (form) { + form.submit(); + } + + return true; + } + } + } + }); +} + +const initSearchPanel = function(this: Mmenu): HTMLElement { + var options = this.opts.searchfield, + configs = this.conf.searchfield; + + var searchpanel = DOM.children(this.node.pnls, '.mm-panel_search')[0]; + + // Only once + if (searchpanel) { + return searchpanel; + } + + searchpanel = DOM.create('div.mm-panel.mm-panel_search.mm-hidden'); + + if (options.panel.id) { + searchpanel.id = options.panel.id; + } + + if (options.panel.title) { + searchpanel.setAttribute('data-mm-title', options.panel.title); + // searchpanel.dataset.mmTitle = options.panel.title; // IE10 has no dataset :( + } + + var listview = DOM.create('ul'); + searchpanel.append(listview); + + this.node.pnls.append(searchpanel); + + this.initListview(listview); + this._initNavbar(searchpanel); + + switch (options.panel.fx) { + case false: + break; + + case 'none': + searchpanel.classList.add('mm-panel_noanimation'); + break; + + default: + searchpanel.classList.add('mm-panel_fx-' + options.panel.fx); + break; + } + + // Add splash content + if (options.panel.splash) { + let splash = DOM.create('div.mm-panel__content'); + splash.innerHTML = options.panel.splash; + + searchpanel.append(splash); + } + + searchpanel.classList.add('mm-panel'); + searchpanel.classList.add('mm-hidden'); + + this.node.pnls.append(searchpanel); + + return searchpanel; +}; + +const initSearchfield = function( + this: Mmenu, + wrapper: HTMLElement +): HTMLElement { + var options = this.opts.searchfield, + configs = this.conf.searchfield; + + // No searchfield in vertical submenus + if (wrapper.parentElement.matches('.mm-listitem_vertical')) { + return null; + } + + // Only one searchfield per panel + var form = DOM.find(wrapper, '.mm-searchfield')[0]; + if (form) { + return form; + } + + function addAttributes( + element: HTMLElement, + attr: mmLooseObject | boolean + ) { + if (attr) { + for (var a in attr as mmLooseObject) { + element.setAttribute(a, attr[a]); + } + } + } + + var form = DOM.create((configs.form ? 'form' : 'div') + '.mm-searchfield'), + field = DOM.create('div.mm-searchfield__input'), + input = DOM.create('input') as HTMLInputElement; + + input.type = 'text'; + input.autocomplete = 'off'; + input.placeholder = this.i18n(options.placeholder) as string; + + field.append(input); + form.append(field); + + wrapper.prepend(form); + + // Add attributes to the input + addAttributes(input, configs.input); + + // Add the clear button + if (configs.clear) { + let anchor = DOM.create('a.mm-btn.mm-btn_close.mm-searchfield__btn'); + anchor.setAttribute('href', '#'); + + field.append(anchor); + } + + // Add attributes and submit to the form + addAttributes(form, configs.form); + if (configs.form && configs.submit && !configs.clear) { + let anchor = DOM.create('a.mm-btn.mm-btn_next.mm-searchfield__btn'); + anchor.setAttribute('href', '#'); + + field.append(anchor); + } + + if (options.cancel) { + let anchor = DOM.create('a.mm-searchfield__cancel'); + anchor.setAttribute('href', '#'); + anchor.textContent = this.i18n('cancel') as string; + + form.append(anchor); + } + + return form; +}; + +const initSearching = function(this: Mmenu, form: HTMLElement) { + var options = this.opts.searchfield, + configs = this.conf.searchfield; + + var data: mmLooseObject = {}; + + // In the searchpanel. + if (form.closest('.mm-panel_search')) { + data.panels = DOM.find(this.node.pnls, '.mm-panel'); + data.noresults = [form.closest('.mm-panel')]; + + // In a panel + } else if (form.closest('.mm-panel')) { + data.panels = [form.closest('.mm-panel')]; + data.noresults = data.panels; + + // Not in a panel, global + } else { + data.panels = DOM.find(this.node.pnls, '.mm-panel'); + data.noresults = [this.node.menu]; + } + + // Filter out search panel + data.panels = data.panels.filter( + panel => !panel.matches('.mm-panel_search') + ); + + // Filter out vertical submenus + data.panels = data.panels.filter( + panel => !panel.parentElement.matches('.mm-listitem_vertical') + ); + + // Find listitems and dividers. + data.listitems = []; + data.dividers = []; + data.panels.forEach(panel => { + data.listitems.push(...DOM.find(panel, '.mm-listitem')); + data.dividers.push(...DOM.find(panel, '.mm-divider')); + }); + + var searchpanel = DOM.children(this.node.pnls, '.mm-panel_search')[0], + input = DOM.find(form, 'input')[0], + cancel = DOM.find(form, '.mm-searchfield__cancel')[0]; + + input['mmSearchfield'] = data; + + // Open the splash panel when focussing the input. + if (options.panel.add && options.panel.splash) { + events.off(input, 'focus.splash'); + events.on(input, 'focus.splash', evnt => { + this.openPanel(searchpanel); + }); + } + + if (options.cancel) { + // Show the cancel button when focussing the input. + events.off(input, 'focus.cancel'); + events.on(input, 'focus.cancel', evnt => { + cancel.classList.add('mm-searchfield__cancel-active'); + }); + + // Close the splash panel when clicking the cancel button. + events.off(cancel, 'click.splash'); + events.on(cancel, 'click.splash', evnt => { + evnt.preventDefault(); + cancel.classList.remove('mm-searchfield__cancel-active'); + + if (searchpanel.matches('.mm-panel_opened')) { + let parents = DOM.children( + this.node.pnls, + '.mm-panel_opened-parent' + ); + if (parents.length) { + this.openPanel(parents[parents.length - 1]); + } + } + }); + } + + // Focus the input in the searchpanel when opening the searchpanel. + if (options.panel.add && options.addTo == 'panel') { + this.bind('openPanel:finish', (panel: HTMLElement) => { + if (panel === searchpanel) { + input.focus(); + } + }); + } + + // Search while typing. + events.off(input, 'input.search'); + events.on(input, 'input.search', (evnt: KeyboardEvent) => { + switch (evnt.keyCode) { + case 9: // tab + case 16: // shift + case 17: // control + case 18: // alt + case 37: // left + case 38: // top + case 39: // right + case 40: // bottom + break; + + default: + this.search(input); + break; + } + }); + + // Search initially. + this.search(input); +}; + +const initNoResultsMsg = function(this: Mmenu, wrapper: HTMLElement) { + if (!wrapper) { + return; + } + + var options = this.opts.searchfield, + configs = this.conf.searchfield; + + // Not in a panel + if (!wrapper.closest('.mm-panel')) { + wrapper = DOM.children(this.node.pnls, '.mm-panel')[0]; + } + + // Only once + if (DOM.children(wrapper, '.mm-panel__noresultsmsg').length) { + return; + } + + // Add no-results message + var message = DOM.create('div.mm-panel__noresultsmsg.mm-hidden'); + message.innerHTML = this.i18n(options.noResults) as string; + + wrapper.append(message); +}; + +Mmenu.prototype.search = function( + this: Mmenu, + input: HTMLInputElement, + query: string +) { + var options = this.opts.searchfield, + configs = this.conf.searchfield; + + query = query || '' + input.value; + query = query.toLowerCase().trim(); + + var data = input['mmSearchfield']; + var form: HTMLElement = input.closest('.mm-searchfield') as HTMLElement, + buttons: HTMLElement[] = DOM.find(form as HTMLElement, '.mm-btn'), + searchpanel: HTMLElement = DOM.children( + this.node.pnls, + '.mm-panel_search' + )[0]; + + /** The panels. */ + var panels: HTMLElement[] = data.panels; + + /** The "no results" messages in a cloned array. */ + var noresults: HTMLElement[] = data.noresults; + + /** The listitems in a cloned array. */ + var listitems: HTMLElement[] = data.listitems; + + /** Tje dividers in a cloned array. */ + var dividers: HTMLElement[] = data.dividers; + + // Reset previous results + listitems.forEach(listitem => { + listitem.classList.remove('mm-listitem_nosubitems'); + listitem.classList.remove('mm-listitem_onlysubitems'); + listitem.classList.remove('mm-hidden'); + }); + + if (searchpanel) { + DOM.children(searchpanel, '.mm-listview')[0].innerHTML = ''; + } + + panels.forEach(panel => { + panel.scrollTop = 0; + }); + + // Search + if (query.length) { + // Initially hide all dividers. + dividers.forEach(divider => { + divider.classList.add('mm-hidden'); + }); + + // Hide listitems that do not match. + listitems.forEach(listitem => { + var text = DOM.children(listitem, '.mm-listitem__text')[0]; + var add = false; + + // The listitem should be shown if: + // 1) The text matches the query and + // 2a) The text is a open-button and + // 2b) the option showSubPanels is set to true. + // or 3a) The text is not an anchor and + // 3b) the option showTextItems is set to true. + // or 4) The text is an anchor. + + // 1 + if ( + text && + DOM.text(text) + .toLowerCase() + .indexOf(query) > -1 + ) { + // 2a + if (text.matches('.mm-listitem__btn')) { + // 2b + if (options.showSubPanels) { + add = true; + } + } + // 3a + else if (!text.matches('a')) { + // 3b + if (options.showTextItems) { + add = true; + } + } + // 4 + else { + add = true; + } + } + + if (!add) { + listitem.classList.add('mm-hidden'); + } + }); + + /** Whether or not the query yielded results. */ + var hasResults = listitems.filter( + listitem => !listitem.matches('.mm-hidden') + ).length; + + // Show all mached listitems in the search panel + if (options.panel.add) { + // Clone all matched listitems into the search panel + let allitems: HTMLElement[] = []; + panels.forEach(panel => { + let listitems = DOM.filterLI(DOM.find(panel, '.mm-listitem')); + listitems = listitems.filter( + listitem => !listitem.matches('.mm-hidden') + ); + + if (listitems.length) { + // Add a divider to indicate in what panel the listitems were. + if (options.panel.dividers) { + let divider = DOM.create('li.mm-divider'); + let title = DOM.find(panel, '.mm-navbar__title')[0]; + if (title) { + divider.innerHTML = title.innerHTML; + allitems.push(divider); + } + } + + listitems.forEach(listitem => { + allitems.push(listitem.cloneNode(true) as HTMLElement); + }); + } + }); + + // Remove toggles and checks. + allitems.forEach(listitem => { + listitem + .querySelectorAll('.mm-toggle, .mm-check') + .forEach(element => { + element.remove(); + }); + }); + + // Add to the search panel. + DOM.children(searchpanel, '.mm-listview')[0].append(...allitems); + + // Open the search panel. + this.openPanel(searchpanel); + } else { + // Also show listitems in sub-panels for matched listitems + if (options.showSubPanels) { + panels.forEach(panel => { + let listitems = DOM.find(panel, '.mm-listitem'); + + DOM.filterLI(listitems).forEach(listitem => { + let child: HTMLElement = listitem['mmChild']; + if (child) { + DOM.find(child, '.mm-listitem').forEach( + listitem => { + listitem.classList.remove('mm-hidden'); + } + ); + } + }); + }); + } + + // Update parent for sub-panel + // .reverse() mutates the original array, therefor we "clone" it first using [...panels]. + [...panels].reverse().forEach((panel, p) => { + let parent: HTMLElement = panel['mmParent']; + + if (parent) { + // The current panel has mached listitems + let listitems = DOM.find(panel, '.mm-listitem'); + if (DOM.filterLI(listitems).length) { + // Show parent + if (parent.matches('.mm-hidden')) { + parent.classList.remove('mm-hidden'); + } + parent.classList.add('mm-listitem_onlysubitems'); + } else if (!input.closest('.mm-panel')) { + if ( + panel.matches('.mm-panel_opened') || + panel.matches('.mm-panel_opened-parent') + ) { + // Compensate the timeout for the opening animation + setTimeout(() => { + this.openPanel( + parent.closest('.mm-panel') as HTMLElement + ); + }, (p + 1) * (this.conf.openingInterval * 1.5)); + } + parent.classList.add('mm-listitem_nosubitems'); + } + } + }); + + // Show parent panels of vertical submenus + panels.forEach(panel => { + let listitems = DOM.find(panel, '.mm-listitem'); + DOM.filterLI(listitems).forEach(listitem => { + DOM.parents(listitem, '.mm-listitem_vertical').forEach( + parent => { + if (parent.matches('.mm-hidden')) { + parent.classList.remove('mm-hidden'); + parent.classList.add( + 'mm-listitem_onlysubitems' + ); + } + } + ); + }); + }); + + // Show first preceeding divider of parent + panels.forEach(panel => { + let listitems = DOM.find(panel, '.mm-listitem'); + DOM.filterLI(listitems).forEach(listitem => { + let divider = DOM.prevAll(listitem, '.mm-divider')[0]; + if (divider) { + divider.classList.remove('mm-hidden'); + } + }); + }); + } + + // Show submit / clear button + buttons.forEach(button => button.classList.remove('mm-hidden')); + + // Show/hide no results message + noresults.forEach(wrapper => { + DOM.find(wrapper, '.mm-panel__noresultsmsg').forEach(message => + message.classList[hasResults ? 'add' : 'remove']('mm-hidden') + ); + }); + + if (options.panel.add) { + // Hide splash + if (options.panel.splash) { + DOM.find(searchpanel, '.mm-panel__content').forEach(splash => + splash.classList.add('mm-hidden') + ); + } + + // Re-show original listitems when in search panel + listitems.forEach(listitem => + listitem.classList.remove('mm-hidden') + ); + dividers.forEach(divider => divider.classList.remove('mm-hidden')); + } + + // Don't search + } else { + // Show all items + listitems.forEach(listitem => listitem.classList.remove('mm-hidden')); + dividers.forEach(divider => divider.classList.remove('mm-hidden')); + + // Hide submit / clear button + buttons.forEach(button => button.classList.add('mm-hidden')); + + // Hide no results message + noresults.forEach(wrapper => { + DOM.find(wrapper, '.mm-panel__noresultsmsg').forEach(message => + message.classList.add('mm-hidden') + ); + }); + + if (options.panel.add) { + // Show splash + if (options.panel.splash) { + DOM.find(searchpanel, '.mm-panel__content').forEach(splash => + splash.classList.remove('mm-hidden') + ); + + // Close panel + } else if (!input.closest('.mm-panel_search')) { + let opened = DOM.children( + this.node.pnls, + '.mm-panel_opened-parent' + ); + this.openPanel(opened.slice(-1)[0]); + } + } + } + + // Update for other addons + this.trigger('updateListview'); +}; diff --git a/src/addons/searchfield/translations/de.ts b/src/addons/searchfield/translations/de.ts new file mode 100644 index 0000000..64bb721 --- /dev/null +++ b/src/addons/searchfield/translations/de.ts @@ -0,0 +1,5 @@ +export default { + Search: 'Suche', + 'No results found.': 'Keine Ergebnisse gefunden.', + cancel: 'beenden' +}; diff --git a/src/addons/searchfield/translations/fa.ts b/src/addons/searchfield/translations/fa.ts new file mode 100755 index 0000000..c13a6e0 --- /dev/null +++ b/src/addons/searchfield/translations/fa.ts @@ -0,0 +1,5 @@ +export default { + Search: 'جستجو', + 'No results found.': 'نتیجه‌ای یافت نشد.', + cancel: 'انصراف' +}; diff --git a/src/addons/searchfield/translations/nl.ts b/src/addons/searchfield/translations/nl.ts new file mode 100644 index 0000000..440ec0e --- /dev/null +++ b/src/addons/searchfield/translations/nl.ts @@ -0,0 +1,5 @@ +export default { + Search: 'Zoeken', + 'No results found.': 'Geen resultaten gevonden.', + cancel: 'annuleren' +}; diff --git a/src/addons/searchfield/translations/ru.ts b/src/addons/searchfield/translations/ru.ts new file mode 100644 index 0000000..47438bd --- /dev/null +++ b/src/addons/searchfield/translations/ru.ts @@ -0,0 +1,5 @@ +export default { + Search: 'Найти', + 'No results found.': 'Ничего не найдено.', + cancel: 'отменить' +}; diff --git a/src/addons/searchfield/translations/translate.ts b/src/addons/searchfield/translations/translate.ts new file mode 100644 index 0000000..a167297 --- /dev/null +++ b/src/addons/searchfield/translations/translate.ts @@ -0,0 +1,13 @@ +import { add } from '../../../_modules/i18n'; + +import nl from './nl'; +import fa from './fa'; +import de from './de'; +import ru from './ru'; + +export default function() { + add(nl, 'nl'); + add(fa, 'fa'); + add(de, 'de'); + add(ru, 'ru'); +} diff --git a/src/addons/sectionindexer/_includes.scss b/src/addons/sectionindexer/_includes.scss new file mode 100644 index 0000000..031d7d5 --- /dev/null +++ b/src/addons/sectionindexer/_includes.scss @@ -0,0 +1 @@ +$mm_include_sectionindexer: true !default; diff --git a/src/addons/sectionindexer/_options.ts b/src/addons/sectionindexer/_options.ts new file mode 100644 index 0000000..ede0c8f --- /dev/null +++ b/src/addons/sectionindexer/_options.ts @@ -0,0 +1,28 @@ +const options : mmOptionsSectionindexer = { + add: false, + addTo: 'panels' +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsSectionindexer +) : mmOptionsSectionindexer { + + if ( typeof options == 'boolean' ) { + options = { + add: options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/sectionindexer/_typings.d.ts b/src/addons/sectionindexer/_typings.d.ts new file mode 100644 index 0000000..2295942 --- /dev/null +++ b/src/addons/sectionindexer/_typings.d.ts @@ -0,0 +1,9 @@ +/** Options for the sectionIndexer add-on. */ +interface mmOptionsSectionindexer { + + /** Whether or not to automatically append a section indexer to the menu. */ + add ?: boolean + + /** Where to add the section indexer(s). */ + addTo ?: string +} diff --git a/src/addons/sectionindexer/_variables.scss b/src/addons/sectionindexer/_variables.scss new file mode 100644 index 0000000..4a65909 --- /dev/null +++ b/src/addons/sectionindexer/_variables.scss @@ -0,0 +1 @@ +$mm_sectionIndexerSize: 20px !default; diff --git a/src/addons/sectionindexer/mmenu.sectionindexer.scss b/src/addons/sectionindexer/mmenu.sectionindexer.scss new file mode 100644 index 0000000..4f7ccdb --- /dev/null +++ b/src/addons/sectionindexer/mmenu.sectionindexer.scss @@ -0,0 +1,47 @@ +@import '../../mixins', '../../includes', '../../variables'; + +$mm_module: '.mm-sectionindexer'; + +#{$mm_module} { + background: inherit; + text-align: center; + font-size: 12px; + + box-sizing: border-box; + width: $mm_sectionIndexerSize; + + position: absolute; + top: 0; + bottom: 0; + right: -$mm_sectionIndexerSize; + z-index: 5; + + transition: right $mm_transitionDuration $mm_transitionFunction; + + display: flex; + flex-direction: column; + justify-content: space-evenly; + + a { + @if ($mm_IE11Fallbacks) { + color: $mm_dimmedTextColor; + } + + color: var(--mm-color-text-dimmed); + line-height: 1; + text-decoration: none; + display: block; + } + + ~ .mm-panel { + padding-right: 0; + } + + &_active { + right: 0; + + ~ .mm-panel { + padding-right: $mm_sectionIndexerSize; + } + } +} diff --git a/src/addons/sectionindexer/mmenu.sectionindexer.ts b/src/addons/sectionindexer/mmenu.sectionindexer.ts new file mode 100644 index 0000000..44b3b54 --- /dev/null +++ b/src/addons/sectionindexer/mmenu.sectionindexer.ts @@ -0,0 +1,92 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as support from '../../_modules/support'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.sectionIndexer = options; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.sectionIndexer); + this.opts.sectionIndexer = extend(options, Mmenu.options.sectionIndexer); + + if (!options.add) { + return; + } + + this.bind('initPanels:after', () => { + // Add the indexer, only if it does not allready excists + if (!this.node.indx) { + let buttons = ''; + 'abcdefghijklmnopqrstuvwxyz'.split('').forEach(letter => { + buttons += '' + letter + ''; + }); + + let indexer = DOM.create('div.mm-sectionindexer'); + indexer.innerHTML = buttons; + + this.node.pnls.prepend(indexer); + this.node.indx = indexer; + + // Prevent default behavior when clicking an anchor + this.node.indx.addEventListener('click', evnt => { + var anchor = evnt.target as HTMLElement; + + if (anchor.matches('a')) { + evnt.preventDefault(); + } + }); + + // Scroll onMouseOver / onTouchStart + let mouseOverEvent = evnt => { + if (!evnt.target.matches('a')) { + return; + } + + var letter = evnt.target.textContent, + panel = DOM.children(this.node.pnls, '.mm-panel_opened')[0]; + + var newTop = -1, + oldTop = panel.scrollTop; + + panel.scrollTop = 0; + DOM.find(panel, '.mm-divider') + .filter(divider => !divider.matches('.mm-hidden')) + .forEach(divider => { + if ( + newTop < 0 && + letter == + divider.textContent + .trim() + .slice(0, 1) + .toLowerCase() + ) { + newTop = divider.offsetTop; + } + }); + + panel.scrollTop = newTop > -1 ? newTop : oldTop; + }; + + if (support.touch) { + this.node.indx.addEventListener('touchstart', mouseOverEvent); + this.node.indx.addEventListener('touchmove', mouseOverEvent); + } else { + this.node.indx.addEventListener('mouseover', mouseOverEvent); + } + } + + // Show or hide the indexer + this.bind('openPanel:start', (panel: HTMLElement) => { + var active = DOM.find(panel, '.mm-divider').filter( + divider => !divider.matches('.mm-hidden') + ).length; + + this.node.indx.classList[active ? 'add' : 'remove']( + 'mm-sectionindexer_active' + ); + }); + }); +} diff --git a/src/addons/setselected/_includes.scss b/src/addons/setselected/_includes.scss new file mode 100644 index 0000000..dfbeded --- /dev/null +++ b/src/addons/setselected/_includes.scss @@ -0,0 +1 @@ +$mm_include_setselected: true !default; diff --git a/src/addons/setselected/_options.ts b/src/addons/setselected/_options.ts new file mode 100644 index 0000000..832fe74 --- /dev/null +++ b/src/addons/setselected/_options.ts @@ -0,0 +1,30 @@ +const options : mmOptionsSetselected = { + current: true, + hover: false, + parent: false +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsSetselected +) : mmOptionsSetselected { + + if ( typeof options == 'boolean' ) { + options = { + hover : options, + parent : options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; \ No newline at end of file diff --git a/src/addons/setselected/_typings.d.ts b/src/addons/setselected/_typings.d.ts new file mode 100644 index 0000000..292e0f0 --- /dev/null +++ b/src/addons/setselected/_typings.d.ts @@ -0,0 +1,12 @@ +/** Options for the setSelected add-on. */ +interface mmOptionsSetselected { + + /** Whether or not to make the current menu item appear "selected". */ + current ?: boolean | 'detect' + + /** Whether or not to make menu item appear "selected" onMouseOver. */ + hover ?: boolean + + /** Whether or not to make menu item appear "selected" while its subpanel is opened. */ + parent ?: boolean +} diff --git a/src/addons/setselected/mmenu.setselected.scss b/src/addons/setselected/mmenu.setselected.scss new file mode 100644 index 0000000..bc1532d --- /dev/null +++ b/src/addons/setselected/mmenu.setselected.scss @@ -0,0 +1,48 @@ +@import '../../mixins', '../../includes', '../../variables'; + +.mm-menu_selected { + &-hover, + &-parent { + .mm-listitem__text, + .mm-listitem__btn { + transition: background-color $mm_transitionDuration + $mm_transitionFunction; + } + } + + &-hover { + .mm-listview:hover > .mm-listitem_selected { + > .mm-listitem__text { + background: none; + } + } + .mm-listitem__text, + .mm-listitem__btn { + &:hover { + @if ($mm_IE11Fallbacks) { + background: $mm_emphasizedBackgroundColor; + } + + background: var(--mm-color-background-emphasis); + } + } + } + + &-parent { + .mm-panel_opened-parent .mm-listitem:not(.mm-listitem_selected-parent) { + > .mm-listitem__text { + background: none; + } + } + .mm-listitem_selected-parent { + > .mm-listitem__text, + > .mm-listitem__btn { + @if ($mm_IE11Fallbacks) { + background: $mm_emphasizedBackgroundColor; + } + + background: var(--mm-color-background-emphasis); + } + } + } +} diff --git a/src/addons/setselected/mmenu.setselected.ts b/src/addons/setselected/mmenu.setselected.ts new file mode 100644 index 0000000..247215c --- /dev/null +++ b/src/addons/setselected/mmenu.setselected.ts @@ -0,0 +1,79 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.setSelected = options; + +export default function(this: Mmenu) { + var options = extendShorthandOptions(this.opts.setSelected); + this.opts.setSelected = extend(options, Mmenu.options.setSelected); + + // Find current by URL + if (options.current == 'detect') { + const findCurrent = (url: string) => { + url = url.split('?')[0].split('#')[0]; + + var anchor = this.node.menu.querySelector( + 'a[href="' + url + '"], a[href="' + url + '/"]' + ); + if (anchor) { + this.setSelected(anchor.parentElement); + } else { + var arr = url.split('/').slice(0, -1); + if (arr.length) { + findCurrent(arr.join('/')); + } + } + }; + this.bind('initMenu:after', () => { + findCurrent.call(this, window.location.href); + }); + + // Remove current selected item + } else if (!options.current) { + this.bind('initListview:after', (listview: HTMLElement) => { + DOM.children(listview, '.mm-listitem_selected').forEach( + listitem => { + listitem.classList.remove('mm-listitem_selected'); + } + ); + }); + } + + // Add :hover effect on items + if (options.hover) { + this.bind('initMenu:after', () => { + this.node.menu.classList.add('mm-menu_selected-hover'); + }); + } + + // Set parent item selected for submenus + if (options.parent) { + this.bind('openPanel:finish', (panel: HTMLElement) => { + // Remove all + DOM.find(this.node.pnls, '.mm-listitem_selected-parent').forEach( + listitem => { + listitem.classList.remove('mm-listitem_selected-parent'); + } + ); + + // Move up the DOM tree + var parent: HTMLElement = panel['mmParent']; + while (parent) { + if (!parent.matches('.mm-listitem_vertical')) { + parent.classList.add('mm-listitem_selected-parent'); + } + + parent = parent.closest('.mm-panel') as HTMLElement; + parent = parent['mmParent']; + } + }); + + this.bind('initMenu:after', () => { + this.node.menu.classList.add('mm-menu_selected-parent'); + }); + } +} diff --git a/src/addons/sidebar/_includes.scss b/src/addons/sidebar/_includes.scss new file mode 100644 index 0000000..411c2df --- /dev/null +++ b/src/addons/sidebar/_includes.scss @@ -0,0 +1,4 @@ +$mm_include_sidebar: true !default; +$mm_include_sidebar_collapsed: $mm_include_sidebar !default; +$mm_include_sidebar_expanded: $mm_include_sidebar !default; +$mm_include_sidebar_blocker: $mm_include_sidebar !default; diff --git a/src/addons/sidebar/_options.ts b/src/addons/sidebar/_options.ts new file mode 100644 index 0000000..6a9d731 --- /dev/null +++ b/src/addons/sidebar/_options.ts @@ -0,0 +1,79 @@ +const options: mmOptionsSidebar = { + collapsed: { + use: false, + blockMenu: true, + hideDivider: false, + hideNavbar: true + }, + expanded: { + use: false, + initial: 'open' + } +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options: mmOptionsSidebar +): mmOptionsSidebar { + if ( + typeof options == 'string' || + (typeof options == 'boolean' && options) || + typeof options == 'number' + ) { + options = { + expanded: options + }; + } + + if (typeof options != 'object') { + options = {}; + } + + // Extend collapsed shorthand options. + if (typeof options.collapsed == 'boolean' && options.collapsed) { + options.collapsed = { + use: true + }; + } + + if ( + typeof options.collapsed == 'string' || + typeof options.collapsed == 'number' + ) { + options.collapsed = { + use: options.collapsed + }; + } + + if (typeof options.collapsed != 'object') { + options.collapsed = {}; + } + + // Extend expanded shorthand options. + if (typeof options.expanded == 'boolean' && options.expanded) { + options.expanded = { + use: true + }; + } + + if ( + typeof options.expanded == 'string' || + typeof options.expanded == 'number' + ) { + options.expanded = { + use: options.expanded + }; + } + + if (typeof options.expanded != 'object') { + options.expanded = {}; + } + + return options; +} diff --git a/src/addons/sidebar/_sidebar.rtl.scss b/src/addons/sidebar/_sidebar.rtl.scss new file mode 100644 index 0000000..f18d8d2 --- /dev/null +++ b/src/addons/sidebar/_sidebar.rtl.scss @@ -0,0 +1,27 @@ +@if ( $mm_include_rtl ) { + @if ( $mm_include_sidebar_collapsed ) { + [dir="rtl"] { + &.mm-wrapper_sidebar-collapsed { + .mm-slideout { + transform: translate3d( 0, 0, 0 ); + } + } + } + } + + @if ( $mm_include_sidebar_expanded ) { + [dir="rtl"] { + &.mm-wrapper_sidebar-expanded .mm-slideout { + transform: translate3d( 0, 0, 0 ); + } + + &.mm-wrapper_sidebar-expanded:not( .mm-wrapper_sidebar-closed ) { + .mm-menu_sidebar-expanded.mm-menu_opened { + ~ .mm-slideout { + transform: translate3d( 0, 0, 0 ); + } + } + } + } + } +} diff --git a/src/addons/sidebar/_typings.d.ts b/src/addons/sidebar/_typings.d.ts new file mode 100644 index 0000000..1ff13b4 --- /dev/null +++ b/src/addons/sidebar/_typings.d.ts @@ -0,0 +1,32 @@ +/** Options for the sidebar add-on. */ +interface mmOptionsSidebar { + /** Collapsed options */ + collapsed?: mmOptionsSidebarCollapsed; + + /** Expanded options */ + expanded?: mmOptionsSidebarExpanded; +} + +/** Collapsed options for the searchfield add-on. */ +interface mmOptionsSidebarCollapsed { + /** Whether or not to enable the collapsed menu. */ + use?: boolean | string | number; + + /** Whether or not to block the collapsed menu from interaction. */ + blockMenu?: boolean; + + /** Whether or not to hide dividers in a collapsed menu, showing only the listitems. */ + hideDivider?: boolean; + + /** Whether or not to hide navbars in a collapsed menu, showing only the listviews. */ + hideNavbar?: boolean; +} + +/** "expanded" options for the searchfield add-on. */ +interface mmOptionsSidebarExpanded { + /** Whether or not to enable the expanded menu. */ + use?: boolean | string | number; + + /** The initial state */ + initial?: 'open' | 'closed' | 'remember'; +} diff --git a/src/addons/sidebar/_variables.scss b/src/addons/sidebar/_variables.scss new file mode 100644 index 0000000..7d850a2 --- /dev/null +++ b/src/addons/sidebar/_variables.scss @@ -0,0 +1,2 @@ +$mm_sidebarCollapsedSize: $mm_btnSize !default; +$mm_sidebarExpandedSize: $mm_menuMaxWidth !default; diff --git a/src/addons/sidebar/mmenu.sidebar.scss b/src/addons/sidebar/mmenu.sidebar.scss new file mode 100644 index 0000000..2d3d204 --- /dev/null +++ b/src/addons/sidebar/mmenu.sidebar.scss @@ -0,0 +1,138 @@ +@import '../../mixins', '../../includes', '../../variables'; + +@if ($mm_include_sidebar_collapsed or $mm_include_sidebar_expanded) { + :root { + --mm-sidebar-collapsed-size: #{$mm_sidebarCollapsedSize}; + --mm-sidebar-expanded-size: #{$mm_sidebarExpandedSize}; + } + + .mm-wrapper_sidebar { + &-collapsed, + &-expanded { + body { + position: relative; + } + + .mm-slideout { + transition-property: width, transform; + } + + .mm-page { + background: inherit; + box-sizing: border-box; + min-height: 100vh; + } + } + + &-collapsed .mm-menu_sidebar-collapsed, + &-expanded .mm-menu_sidebar-expanded { + display: flex !important; + top: 0 !important; + right: auto !important; + bottom: 0 !important; + left: 0 !important; + } + } +} + +@if ($mm_include_sidebar_collapsed) { + .mm-wrapper_sidebar { + &-collapsed { + .mm-slideout { + @if ($mm_IE11Fallbacks) { + width: calc(100% - #{$mm_sidebarCollapsedSize}); + transform: translate3d($mm_sidebarCollapsedSize, 0, 0); + } + + width: calc(100% - var(--mm-sidebar-collapsed-size)); + transform: translate3d(var(--mm-sidebar-collapsed-size), 0, 0); + } + + &:not(.mm-wrapper_opening) { + .mm-menu_hidenavbar .mm-navbar, + .mm-menu_hidedivider .mm-divider { + opacity: 0; + } + } + } + } +} + +@if ($mm_include_sidebar_expanded) { + .mm-wrapper_sidebar { + &-expanded { + .mm-menu_sidebar-expanded { + @if ($mm_IE11Fallbacks) { + width: $mm_sidebarExpandedSize; + } + + width: var(--mm-sidebar-expanded-size); + min-width: 0 !important; + max-width: 100000px !important; + border-right-width: 1px; + border-right-style: solid; + + @if ($mm_include_shadows_page) { + &.mm-menu_pageshadow:after { + content: none; + display: none; + } + } + } + + @if ($mm_include_offcanvas_blocker) { + &.mm-wrapper_blocking { + &, + body { + overflow: visible; + } + } + + .mm-wrapper__blocker { + display: none !important; + } + } + + &:not(.mm-wrapper_sidebar-closed) { + .mm-menu_sidebar-expanded.mm-menu_opened { + ~ .mm-slideout { + @if ($mm_IE11Fallbacks) { + width: calc(100% - #{$mm_sidebarExpandedSize}); + transform: translate3d( + $mm_sidebarExpandedSize, + 0, + 0 + ); + } + + width: calc(100% - var(--mm-sidebar-expanded-size)); + transform: translate3d( + var(--mm-sidebar-expanded-size), + 0, + 0 + ); + } + } + } + } + } +} + +@if ($mm_include_sidebar_blocker) { + .mm-menu__blocker { + background: rgba(3, 2, 1, 0); + display: block; + position: absolute; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 3; + + .mm-menu_opened & { + display: none; + } + } +} + +@import 'sidebar.rtl'; diff --git a/src/addons/sidebar/mmenu.sidebar.ts b/src/addons/sidebar/mmenu.sidebar.ts new file mode 100644 index 0000000..e9f637e --- /dev/null +++ b/src/addons/sidebar/mmenu.sidebar.ts @@ -0,0 +1,135 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as media from '../../_modules/matchmedia'; +import { extend } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.sidebar = options; + +export default function(this: Mmenu) { + if (!this.opts.offCanvas) { + return; + } + + var options = extendShorthandOptions(this.opts.sidebar); + this.opts.sidebar = extend(options, Mmenu.options.sidebar); + + // Collapsed + if (options.collapsed.use) { + // Make the menu collapsable. + this.bind('initMenu:after', () => { + this.node.menu.classList.add('mm-menu_sidebar-collapsed'); + + if ( + options.collapsed.blockMenu && + this.opts.offCanvas && + !DOM.children(this.node.menu, '.mm-menu__blocker')[0] + ) { + let anchor = DOM.create('a.mm-menu__blocker'); + anchor.setAttribute('href', '#' + this.node.menu.id); + + this.node.menu.prepend(anchor); + } + + if (options.collapsed.hideNavbar) { + this.node.menu.classList.add('mm-menu_hidenavbar'); + } + + if (options.collapsed.hideDivider) { + this.node.menu.classList.add('mm-menu_hidedivider'); + } + }); + + // En-/disable the collapsed sidebar. + let enable = () => { + this.node.wrpr.classList.add('mm-wrapper_sidebar-collapsed'); + }; + let disable = () => { + this.node.wrpr.classList.remove('mm-wrapper_sidebar-collapsed'); + }; + if (typeof options.collapsed.use == 'boolean') { + this.bind('initMenu:after', enable); + } else { + media.add(options.collapsed.use, enable, disable); + } + } + + // Expanded + if (options.expanded.use) { + // Make the menu expandable + this.bind('initMenu:after', () => { + this.node.menu.classList.add('mm-menu_sidebar-expanded'); + }); + + // En-/disable the expanded sidebar. + let enable = () => { + this.node.wrpr.classList.add('mm-wrapper_sidebar-expanded'); + if (!this.node.wrpr.matches('.mm-wrapper_sidebar-closed')) { + this.open(); + } + }; + let disable = () => { + this.node.wrpr.classList.remove('mm-wrapper_sidebar-expanded'); + this.close(); + }; + if (typeof options.expanded.use == 'boolean') { + this.bind('initMenu:after', enable); + } else { + media.add(options.expanded.use, enable, disable); + } + + // Manually en-/disable the expanded sidebar (open / close the menu) + this.bind('close:start', () => { + if (this.node.wrpr.matches('.mm-wrapper_sidebar-expanded')) { + this.node.wrpr.classList.add('mm-wrapper_sidebar-closed'); + + if (options.expanded.initial == 'remember') { + window.localStorage.setItem('mmenuExpandedState', 'closed'); + } + } + }); + + this.bind('open:start', () => { + if (this.node.wrpr.matches('.mm-wrapper_sidebar-expanded')) { + this.node.wrpr.classList.remove('mm-wrapper_sidebar-closed'); + + if (options.expanded.initial == 'remember') { + window.localStorage.setItem('mmenuExpandedState', 'open'); + } + } + }); + + // Set the initial state + var initialState = options.expanded.initial; + + if (options.expanded.initial == 'remember') { + let state = window.localStorage.getItem('mmenuExpandedState'); + switch (state) { + case 'open': + case 'closed': + initialState = state; + break; + } + } + + if (initialState == 'closed') { + this.bind('initMenu:after', () => { + this.node.wrpr.classList.add('mm-wrapper_sidebar-closed'); + }); + } + + // Add click behavior. + // Prevents default behavior when clicking an anchor + this.clck.push((anchor: HTMLElement, args: mmClickArguments) => { + if (args.inMenu && args.inListview) { + if (this.node.wrpr.matches('.mm-wrapper_sidebar-expanded')) { + return { + close: options.expanded.initial == 'closed' + }; + } + } + }); + } +} diff --git a/src/addons/toggles/_includes.scss b/src/addons/toggles/_includes.scss new file mode 100644 index 0000000..2fb0a6a --- /dev/null +++ b/src/addons/toggles/_includes.scss @@ -0,0 +1,2 @@ +$mm_include_toggles: true !default; +$mm_include_checks: true !default; diff --git a/src/addons/toggles/_toggles.rtl.scss b/src/addons/toggles/_toggles.rtl.scss new file mode 100644 index 0000000..b9e3b49 --- /dev/null +++ b/src/addons/toggles/_toggles.rtl.scss @@ -0,0 +1,7 @@ +@if ( $mm_include_rtl ) { + @if ( $mm_include_toggles ) { + [dir="rtl"] input.mm-toggle:checked ~ label.mm-toggle:before { + float: left; + } + } +} diff --git a/src/addons/toggles/_variables.scss b/src/addons/toggles/_variables.scss new file mode 100644 index 0000000..e97ba64 --- /dev/null +++ b/src/addons/toggles/_variables.scss @@ -0,0 +1,5 @@ +$mm_toggleCheckedColor: #4bd963 !default; +$mm_toggleHeight: $mm_listitemSize - $mm_padding !default; +$mm_toggleWidth: ($mm_toggleHeight * 2) - $mm_padding !default; +$mm_checkHeight: $mm_btnSize - $mm_padding !default; +$mm_checkWidth: $mm_btnSize - $mm_padding !default; diff --git a/src/addons/toggles/mmenu.toggles.scss b/src/addons/toggles/mmenu.toggles.scss new file mode 100644 index 0000000..c08c94d --- /dev/null +++ b/src/addons/toggles/mmenu.toggles.scss @@ -0,0 +1,86 @@ +@import '../../mixins', '../../includes', '../../variables'; + +@if ($mm_include_toggles) { + input.mm-toggle { + @if ($mm_IE11Fallbacks) { + margin-top: ($mm_listitemSize - $mm_toggleHeight) / 2; + background: $mm_borderColor; + + &:before { + background: $mm_backgroundColor; + } + } + + display: inline-block; + min-width: $mm_toggleWidth; + width: $mm_toggleWidth; + height: $mm_toggleHeight; + margin: 0 $mm_padding; + margin-top: calc((var(--mm-listitem-size) - #{$mm_toggleHeight}) / 2); + border: none !important; + background: var(--mm-color-border); + border-radius: $mm_toggleHeight; + appearance: none !important; + cursor: pointer; + transition: background-color 0.2s ease; + + &:before { + content: ''; + display: block; + width: $mm_toggleHeight - 2; + height: $mm_toggleHeight - 2; + margin: 1px; + border-radius: $mm_toggleHeight; + background: var(--mm-color-background); + transition: transform 0.2s ease; + } + + &:checked { + background: $mm_toggleCheckedColor; + + &:before { + transform: translateX($mm_toggleWidth - $mm_toggleHeight); + } + } + } +} + +@if ($mm_include_checks) { + input.mm-check { + @if ($mm_IE11Fallbacks) { + margin-top: ($mm_listitemSize - $mm_checkHeight) / 2; + } + + appearance: none !important; + border: none !important; + background: none !important; + cursor: pointer; + display: inline-block; + width: $mm_checkWidth; + height: $mm_checkHeight; + margin: 0 $mm_padding; + margin-top: calc((var(--mm-listitem-size) - #{$mm_checkHeight}) / 2); + + &:before { + content: ''; + display: block; + width: 40%; + height: 20%; + margin: 25% 0 0 20%; + border-left: 3px solid; + border-bottom: 3px solid; + border-color: var(--mm-color-text); + opacity: 0.3; + transform: rotate(-45deg); + transition: opacity 0.2s ease; + } + + &:checked { + &:before { + opacity: 1; + } + } + } +} + +@import 'toggles.rtl'; diff --git a/src/addons/toggles/mmenu.toggles.ts b/src/addons/toggles/mmenu.toggles.ts new file mode 100644 index 0000000..bc75e49 --- /dev/null +++ b/src/addons/toggles/mmenu.toggles.ts @@ -0,0 +1,22 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; + +// Add the classnames. +Mmenu.configs.classNames.toggles = { + toggle: 'Toggle', + check: 'Check' +}; + +export default function() { + this.bind('initPanel:after', (panel: HTMLElement) => { + // Refactor toggle classes + DOM.find(panel, 'input').forEach(input => { + DOM.reClass( + input, + this.conf.classNames.toggles.toggle, + 'mm-toggle' + ); + DOM.reClass(input, this.conf.classNames.toggles.check, 'mm-check'); + }); + }); +} diff --git a/src/core/offcanvas/_configs.ts b/src/core/offcanvas/_configs.ts new file mode 100644 index 0000000..822feec --- /dev/null +++ b/src/core/offcanvas/_configs.ts @@ -0,0 +1,13 @@ +const configs: mmConfigsOffcanvas = { + clone: false, + menu: { + insertMethod: 'prepend', + insertSelector: 'body' + }, + page: { + nodetype: 'div', + selector: null, + noSelector: [] + } +}; +export default configs; diff --git a/src/core/offcanvas/_includes.scss b/src/core/offcanvas/_includes.scss new file mode 100644 index 0000000..73bcbf2 --- /dev/null +++ b/src/core/offcanvas/_includes.scss @@ -0,0 +1,2 @@ +$mm_include_offcanvas: true !default; +$mm_include_offcanvas_blocker: $mm_include_offcanvas !default; diff --git a/src/core/offcanvas/_mixins.scss b/src/core/offcanvas/_mixins.scss new file mode 100644 index 0000000..aa166e9 --- /dev/null +++ b/src/core/offcanvas/_mixins.scss @@ -0,0 +1,32 @@ +@mixin mm_offcanvas_size( $cls: ".mm-menu_offcanvas", + $width: $mm_menuWidth, $minWidth: $mm_menuMinWidth, $maxWidth: $mm_menuMaxWidth +) { + #{$cls} { + width: percentage( $width ); + min-width: $minWidth; + max-width: $maxWidth; + } + + .mm-wrapper_opening { + #{$cls} ~ .mm-slideout { + transform: translate3d( #{$width * 100}vw, 0, 0 ); + } + } + + // adjust for min- and max-width + @media all and ( max-width: $minWidth / $width ) { + .mm-wrapper_opening { + #{$cls} ~ .mm-slideout { + transform: translate3d( $minWidth, 0, 0 ); + } + } + } + + @media all and ( min-width: $maxWidth / $width ) { + .mm-wrapper_opening { + #{$cls} ~ .mm-slideout { + transform: translate3d( $maxWidth, 0, 0 ); + } + } + } +} diff --git a/src/core/offcanvas/_offcanvas.rtl.scss b/src/core/offcanvas/_offcanvas.rtl.scss new file mode 100644 index 0000000..84f6b12 --- /dev/null +++ b/src/core/offcanvas/_offcanvas.rtl.scss @@ -0,0 +1,6 @@ +@if ( $mm_include_rtl ) { + [dir="rtl"] .mm-menu_offcanvas { + /*left: unset; + right: 0;*/ + } +} diff --git a/src/core/offcanvas/_options.ts b/src/core/offcanvas/_options.ts new file mode 100644 index 0000000..81b5bea --- /dev/null +++ b/src/core/offcanvas/_options.ts @@ -0,0 +1,23 @@ +const options : mmOptionsOffcanvas = { + blockUI: true, + moveBackground: true +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsOffcanvas +) : mmOptionsOffcanvas { + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; + \ No newline at end of file diff --git a/src/core/offcanvas/_typings.d.ts b/src/core/offcanvas/_typings.d.ts new file mode 100644 index 0000000..e3e71a0 --- /dev/null +++ b/src/core/offcanvas/_typings.d.ts @@ -0,0 +1,37 @@ +// Add-on options interface. +interface mmOptionsOffcanvas { + /** Whether or not (and how) to block the UI while the menu is opened. */ + blockUI?: true | false | 'modal'; + + /** Whether or not to have the "page" inherit its background (from its parent element). */ + moveBackground?: boolean; +} + +// Add-on configs interfaces. +interface mmConfigsOffcanvas { + /** Whether or not the menu should be cloned (and the original menu kept intact). */ + clone?: boolean; + + /** Menu configuration for the off-canvas add-on. */ + menu?: mmConfigsOffcanvasMenu; + + /** Page configuration for the off-canvas add-on. */ + page?: mmConfigsOffcanvasPage; +} +interface mmConfigsOffcanvasMenu { + /** How to insert the menu into the DOM. */ + insertMethod?: 'prepend' | 'append'; + + /** Where to insert the menu into the DOM. */ + insertSelector?: string; +} +interface mmConfigsOffcanvasPage { + /** The nodetype for the page. */ + nodetype?: string; + + /** The selector for the page. */ + selector?: string; + + /** List of selectors for nodes to exclude from the page. */ + noSelector?: string[]; +} diff --git a/src/core/offcanvas/_variables.scss b/src/core/offcanvas/_variables.scss new file mode 100644 index 0000000..ccf3e78 --- /dev/null +++ b/src/core/offcanvas/_variables.scss @@ -0,0 +1,6 @@ +$mm_menuWidth: 0.8 !default; +$mm_menuMinWidth: 240px !default; +$mm_menuMaxWidth: 440px !default; +$mm_menuHeight: 0.8 !default; +$mm_menuMinHeight: 140px !default; +$mm_menuMaxHeight: 880px !default; diff --git a/src/core/offcanvas/mmenu.offcanvas.scss b/src/core/offcanvas/mmenu.offcanvas.scss new file mode 100644 index 0000000..d837d0a --- /dev/null +++ b/src/core/offcanvas/mmenu.offcanvas.scss @@ -0,0 +1,70 @@ +@import '../../mixins', '../../includes', '../../variables'; + +// Animations +.mm-page { + box-sizing: border-box; + position: relative; +} + +.mm-slideout { + transition: transform $mm_transitionDuration $mm_transitionFunction; + z-index: 1; +} + +// Wrapper +.mm-wrapper { + &_opened { + overflow-x: hidden; + position: relative; + + .mm-page { + min-height: 100vh; + } + } + &_background { + .mm-page { + background: inherit; + } + } +} + +// Menu +.mm-menu_offcanvas { + position: fixed; + right: auto; + z-index: 0; + + &:not(.mm-menu_opened) { + display: none; + } +} + +@include mm_offcanvas_size; + +@if ($mm_include_offcanvas_blocker) { + .mm-wrapper__blocker { + background: rgba(3, 2, 1, 0); + overflow: hidden; + display: none; + position: fixed; + top: 0; + right: 0; + bottom: 0; + left: 0; + z-index: 2; + } + + .mm-wrapper_blocking { + overflow: hidden; + + body { + overflow: hidden; + } + + .mm-wrapper__blocker { + display: block; + } + } +} + +@import 'offcanvas.rtl'; diff --git a/src/core/offcanvas/mmenu.offcanvas.ts b/src/core/offcanvas/mmenu.offcanvas.ts new file mode 100644 index 0000000..87f60c0 --- /dev/null +++ b/src/core/offcanvas/mmenu.offcanvas.ts @@ -0,0 +1,422 @@ +import Mmenu from './../oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as events from '../../_modules/eventlisteners'; +import { + extend, + transitionend, + uniqueId, + originalId +} from '../../_modules/helpers'; + +// Add the options and configs. +Mmenu.options.offCanvas = options; +Mmenu.configs.offCanvas = configs; + +export default function(this: Mmenu) { + if (!this.opts.offCanvas) { + return; + } + + var options = extendShorthandOptions(this.opts.offCanvas); + this.opts.offCanvas = extend(options, Mmenu.options.offCanvas); + + var configs = this.conf.offCanvas; + + // Add methods to the API. + this._api.push('open', 'close', 'setPage'); + + // Setup the menu. + this.vars.opened = false; + + // Add off-canvas behavior. + this.bind('initMenu:before', () => { + // Clone if needed. + if (configs.clone) { + // Clone the original menu and store it. + this.node.menu = this.node.menu.cloneNode(true) as HTMLElement; + + // Prefix all ID's in the cloned menu. + if (this.node.menu.id) { + this.node.menu.id = 'mm-' + this.node.menu.id; + } + DOM.find(this.node.menu, '[id]').forEach(elem => { + elem.id = 'mm-' + elem.id; + }); + } + + this.node.wrpr = document.body; + + // Prepend to the + document + .querySelector(configs.menu.insertSelector) + [configs.menu.insertMethod](this.node.menu); + }); + this.bind('initMenu:after', () => { + // Setup the UI blocker. + initBlocker.call(this); + + // Setup the page. + this.setPage(Mmenu.node.page); + + // Setup window events. + initWindow.call(this); + + // Setup the menu. + this.node.menu.classList.add('mm-menu_offcanvas'); + + // Open if url hash equals menu id (usefull when user clicks the hamburger icon before the menu is created) + let hash = window.location.hash; + if (hash) { + let id = originalId(this.node.menu.id); + if (id && id == hash.slice(1)) { + setTimeout(() => { + this.open(); + }, 1000); + } + } + }); + + // Sync the blocker to target the page. + this.bind('setPage:after', (page: HTMLElement) => { + if (Mmenu.node.blck) { + DOM.children(Mmenu.node.blck, 'a').forEach(anchor => { + anchor.setAttribute('href', '#' + page.id); + }); + } + }); + + // Add screenreader / aria support + this.bind('open:start:sr-aria', () => { + Mmenu.sr_aria(this.node.menu, 'hidden', false); + }); + this.bind('close:finish:sr-aria', () => { + Mmenu.sr_aria(this.node.menu, 'hidden', true); + }); + this.bind('initMenu:after:sr-aria', () => { + Mmenu.sr_aria(this.node.menu, 'hidden', true); + }); + + // Add screenreader / text support + this.bind('initBlocker:after:sr-text', () => { + DOM.children(Mmenu.node.blck, 'a').forEach(anchor => { + anchor.innerHTML = Mmenu.sr_text( + this.i18n(this.conf.screenReader.text.closeMenu) + ); + }); + }); + + // Add click behavior. + // Prevents default behavior when clicking an anchor + this.clck.push((anchor: HTMLElement, args: mmClickArguments) => { + // Open menu if the clicked anchor links to the menu + let id = originalId(this.node.menu.id); + if (id) { + if (anchor.matches('[href="#' + id + '"]')) { + // Opening this menu from within this menu + // -> Open menu + if (args.inMenu) { + this.open(); + return true; + } + + // Opening this menu from within a second menu + // -> Close the second menu before opening this menu + var menu = anchor.closest('.mm-menu') as HTMLElement; + if (menu) { + var api: mmApi = menu['mmApi']; + if (api && api.close) { + api.close(); + transitionend( + menu, + () => { + this.open(); + }, + this.conf.transitionDuration + ); + return true; + } + } + + // Opening this menu + this.open(); + + return true; + } + } + + // Close menu + id = Mmenu.node.page.id; + if (id) { + if (anchor.matches('[href="#' + id + '"]')) { + this.close(); + return true; + } + } + + return; + }); +} + +/** + * Open the menu. + */ +Mmenu.prototype.open = function(this: Mmenu) { + // Invoke "before" hook. + this.trigger('open:before'); + + if (this.vars.opened) { + return; + } + + this._openSetup(); + + // Without the timeout, the animation won't work because the menu had display: none; + setTimeout(() => { + this._openStart(); + }, this.conf.openingInterval); + + // Invoke "after" hook. + this.trigger('open:after'); +}; + +Mmenu.prototype._openSetup = function(this: Mmenu) { + var options = this.opts.offCanvas; + + // Close other menus + this.closeAllOthers(); + + // Store style and position + Mmenu.node.page['mmStyle'] = Mmenu.node.page.getAttribute('style') || ''; + + // Trigger window-resize to measure height + events.trigger(window, 'resize.page', { force: true }); + + var clsn = ['mm-wrapper_opened']; + + // Add options + if (options.blockUI) { + clsn.push('mm-wrapper_blocking'); + } + if (options.blockUI == 'modal') { + clsn.push('mm-wrapper_modal'); + } + if (options.moveBackground) { + clsn.push('mm-wrapper_background'); + } + + // IE11: + clsn.forEach(classname => { + this.node.wrpr.classList.add(classname); + }); + + // Better browsers: + // this.node.wrpr.classList.add(...clsn); + + // Open + // Without the timeout, the animation won't work because the menu had display: none; + setTimeout(() => { + this.vars.opened = true; + }, this.conf.openingInterval); + + this.node.menu.classList.add('mm-menu_opened'); +}; + +/** + * Finish opening the menu. + */ +Mmenu.prototype._openStart = function(this: Mmenu) { + // Callback when the page finishes opening. + transitionend( + Mmenu.node.page, + () => { + this.trigger('open:finish'); + }, + this.conf.transitionDuration + ); + + // Opening + this.trigger('open:start'); + this.node.wrpr.classList.add('mm-wrapper_opening'); +}; + +Mmenu.prototype.close = function(this: Mmenu) { + // Invoke "before" hook. + this.trigger('close:before'); + + if (!this.vars.opened) { + return; + } + + // Callback when the page finishes closing. + transitionend( + Mmenu.node.page, + () => { + this.node.menu.classList.remove('mm-menu_opened'); + + var classnames = [ + 'mm-wrapper_opened', + 'mm-wrapper_blocking', + 'mm-wrapper_modal', + 'mm-wrapper_background' + ]; + + // IE11: + classnames.forEach(classname => { + this.node.wrpr.classList.remove(classname); + }); + + // Better browsers: + // this.node.wrpr.classList.remove(...classnames); + + // Restore style and position + Mmenu.node.page.setAttribute('style', Mmenu.node.page['mmStyle']); + + this.vars.opened = false; + this.trigger('close:finish'); + }, + this.conf.transitionDuration + ); + + // Closing + this.trigger('close:start'); + + this.node.wrpr.classList.remove('mm-wrapper_opening'); + + // Invoke "after" hook. + this.trigger('close:after'); +}; + +/** + * Close all other menus. + */ +Mmenu.prototype.closeAllOthers = function(this: Mmenu) { + DOM.find(document.body, '.mm-menu_offcanvas').forEach(menu => { + if (menu !== this.node.menu) { + let api: mmApi = menu['mmApi']; + if (api && api.close) { + api.close(); + } + } + }); +}; + +/** + * Set the "page" node. + * + * @param {HTMLElement} page Element to set as the page. + */ +Mmenu.prototype.setPage = function(this: Mmenu, page: HTMLElement) { + // Invoke "before" hook. + this.trigger('setPage:before', [page]); + + var configs = this.conf.offCanvas; + + // If no page was specified, find it. + if (!page) { + /** Array of elements that are / could be "the page". */ + let pages = + typeof configs.page.selector == 'string' + ? DOM.find(document.body, configs.page.selector) + : DOM.children(document.body, configs.page.nodetype); + + // Filter out elements that are absolutely not "the page". + pages = pages.filter( + page => !page.matches('.mm-menu, .mm-wrapper__blocker') + ); + + // Filter out elements that are configured to not be "the page". + if (configs.page.noSelector.length) { + pages = pages.filter( + page => !page.matches(configs.page.noSelector.join(', ')) + ); + } + + // Wrap multiple pages in a single element. + if (pages.length > 1) { + let wrapper = DOM.create('div'); + pages[0].before(wrapper); + pages.forEach(page => { + wrapper.append(page); + }); + + pages = [wrapper]; + } + + page = pages[0]; + } + page.classList.add('mm-page'); + page.classList.add('mm-slideout'); + + page.id = page.id || uniqueId(); + + Mmenu.node.page = page; + + // Invoke "after" hook. + this.trigger('setPage:after', [page]); +}; + +/** + * Initialize the window. + */ +const initWindow = function(this: Mmenu) { + // Prevent tabbing + // Because when tabbing outside the menu, the element that gains focus will be centered on the screen. + // In other words: The menu would move out of view. + events.off(document.body, 'keydown.tabguard'); + events.on(document.body, 'keydown.tabguard', (evnt: KeyboardEvent) => { + if (evnt.keyCode == 9) { + if (this.node.wrpr.matches('.mm-wrapper_opened')) { + evnt.preventDefault(); + } + } + }); +}; + +/** + * Initialize "blocker" node + */ +const initBlocker = function(this: Mmenu) { + // Invoke "before" hook. + this.trigger('initBlocker:before'); + + var options = this.opts.offCanvas, + configs = this.conf.offCanvas; + + if (!options.blockUI) { + return; + } + + // Create the blocker node. + if (!Mmenu.node.blck) { + let blck = DOM.create('div.mm-wrapper__blocker.mm-slideout'); + blck.innerHTML = ''; + + // Append the blocker node to the body. + document.querySelector(configs.menu.insertSelector).append(blck); + + // Store the blocker node. + Mmenu.node.blck = blck; + } + + // Close the menu when + // 1) clicking, + // 2) touching or + // 3) dragging the blocker node. + var closeMenu = (evnt: Event) => { + evnt.preventDefault(); + evnt.stopPropagation(); + + if (!this.node.wrpr.matches('.mm-wrapper_modal')) { + this.close(); + } + }; + Mmenu.node.blck.addEventListener('mousedown', closeMenu); // 1 + Mmenu.node.blck.addEventListener('touchstart', closeMenu); // 2 + Mmenu.node.blck.addEventListener('touchmove', closeMenu); // 3 + + // Invoke "after" hook. + this.trigger('initBlocker:after'); +}; diff --git a/src/core/oncanvas/_configs.ts b/src/core/oncanvas/_configs.ts new file mode 100644 index 0000000..b48b43d --- /dev/null +++ b/src/core/oncanvas/_configs.ts @@ -0,0 +1,15 @@ +const configs: mmConfigs = { + classNames: { + inset: 'Inset', + nolistview: 'NoListview', + nopanel: 'NoPanel', + panel: 'Panel', + selected: 'Selected', + vertical: 'Vertical' + }, + language: null, + openingInterval: 25, + panelNodetype: ['ul', 'ol', 'div'], + transitionDuration: 400 +}; +export default configs; diff --git a/src/core/oncanvas/_includes.scss b/src/core/oncanvas/_includes.scss new file mode 100644 index 0000000..c60a24f --- /dev/null +++ b/src/core/oncanvas/_includes.scss @@ -0,0 +1,4 @@ +$mm_include_rtl: true !default; +$mm_include_vertical: true !default; + +$mm_IE11Fallbacks: true !default; diff --git a/src/core/oncanvas/_mixins.scss b/src/core/oncanvas/_mixins.scss new file mode 100644 index 0000000..63e5c11 --- /dev/null +++ b/src/core/oncanvas/_mixins.scss @@ -0,0 +1,28 @@ +// Arrow buttons +@mixin mm_btn_arrow_prev { + transform: rotate( -45deg ); + left: $mm_listitemIndent + 3; + right: auto; +} + +@mixin mm_btn_arrow_next { + transform: rotate( 135deg ); + right: $mm_listitemIndent + 3; + left: auto; +} + + +// Misc +@mixin mm_ellipsis() { + text-overflow: ellipsis; + white-space: nowrap; + overflow: hidden; +} + +@mixin mm_clearfix() { + &:after { + content: ''; + display: block; + clear: both; + } +} \ No newline at end of file diff --git a/src/core/oncanvas/_oncanvas.buttons.rtl.scss b/src/core/oncanvas/_oncanvas.buttons.rtl.scss new file mode 100644 index 0000000..a538227 --- /dev/null +++ b/src/core/oncanvas/_oncanvas.buttons.rtl.scss @@ -0,0 +1,31 @@ +$mm_module: '.mm-btn'; + +@if ( $mm_include_rtl ) { + [dir="rtl"] { + #{$mm_module} { + &_next:after { + @include mm_btn_arrow_prev; + } + + + &_prev:before { + @include mm_btn_arrow_next; + } + + &_close { + &:before, + &:after { + right: auto; + } + + &:before { + left: $mm_listitemIndent + 5; + } + + &:after { + left: $mm_listitemIndent - 2; + } + } + } + } +} diff --git a/src/core/oncanvas/_oncanvas.buttons.scss b/src/core/oncanvas/_oncanvas.buttons.scss new file mode 100644 index 0000000..59fa760 --- /dev/null +++ b/src/core/oncanvas/_oncanvas.buttons.scss @@ -0,0 +1,72 @@ +$mm_module: '.mm-btn'; + +#{$mm_module} { + flex-grow: 0; + flex-shrink: 0; + position: relative; + box-sizing: border-box; + width: $mm_btnSize; + padding: 0; + + &:before, + &:after { + @if ($mm_IE11Fallbacks) { + border: 2px solid $mm_dimmedTextColor; + } + + border: 2px solid var(--mm-color-button); + } +} + +%mm_btn_arrow { + content: ''; + border-bottom: none; + border-right: none; + box-sizing: content-box; + display: block; + width: 8px; + height: 8px; + margin: auto; + position: absolute; + top: 0; + bottom: 0; +} + +#{$mm_module} { + &_prev:before { + @extend %mm_btn_arrow; + @include mm_btn_arrow_prev; + } + + &_next:after { + @extend %mm_btn_arrow; + @include mm_btn_arrow_next; + } + + &_close { + &:before, + &:after { + content: ''; + box-sizing: content-box; + display: block; + width: 5px; + height: 5px; + margin: auto; + position: absolute; + top: 0; + bottom: 0; + + transform: rotate(-45deg); + } + &:before { + border-right: none; + border-bottom: none; + right: $mm_listitemIndent - 2; + } + &:after { + border-left: none; + border-top: none; + right: $mm_listitemIndent + 5; + } + } +} diff --git a/src/core/oncanvas/_oncanvas.listviews.rtl.scss b/src/core/oncanvas/_oncanvas.listviews.rtl.scss new file mode 100644 index 0000000..cd317a3 --- /dev/null +++ b/src/core/oncanvas/_oncanvas.listviews.rtl.scss @@ -0,0 +1,31 @@ +$mm_module: '.mm-listitem'; + +@if ( $mm_include_rtl ) { + [dir="rtl"] { + + // invert the indent on the border + #{$mm_module}:after { + left: 0; + right: $mm_listitemIndent; + } + + #{$mm_module}__text { + padding-left: $mm_padding; + padding-right: $mm_listitemIndent; + } + + #{$mm_module}__btn { + padding-left: $mm_subopenWidth; + border-left-width: 0; + border-left-style: none; + + &:not( #{$mm_module}__text ) { + padding-right: 0; + + border-right-width: 1px; + border-right-style: solid; + } + } + } +} + diff --git a/src/core/oncanvas/_oncanvas.listviews.scss b/src/core/oncanvas/_oncanvas.listviews.scss new file mode 100644 index 0000000..a6c9dcf --- /dev/null +++ b/src/core/oncanvas/_oncanvas.listviews.scss @@ -0,0 +1,104 @@ +$mm_module: '.mm-listitem'; + +.mm-listview { + list-style: none; + display: block; + padding: 0; + margin: 0; +} + +#{$mm_module} { + @if ($mm_IE11Fallbacks) { + color: $mm_textColor; + border-color: $mm_borderColor; + } + + color: var(--mm-color-text); + border-color: var(--mm-color-border); + + list-style: none; + display: block; + padding: 0; + margin: 0; + + position: relative; + display: flex; + flex-wrap: wrap; + + &:after { + content: ''; + border-color: inherit; + border-bottom-width: 1px; + border-bottom-style: solid; + display: block; + position: absolute; + left: $mm_listitemIndent; + right: 0; + bottom: 0; + } + + a, + a:hover { + text-decoration: none; + } +} + +%mm_listitem_content { + @if ($mm_IE11Fallbacks) { + padding: ($mm_listitemSize - $mm_lineHeight) / 2; + } + + display: block; + padding: calc((var(--mm-listitem-size) - var(--mm-line-height)) / 2); + padding-left: 0; + padding-right: 0; + color: inherit; +} + +#{$mm_module}__text { + @extend %mm_listitem_content; + @include mm_ellipsis; + + padding-left: $mm_listitemIndent; + padding-right: $mm_padding; + flex-grow: 1; + flex-basis: 10%; +} + +#{$mm_module}__btn { + @extend %mm_listitem_content; + + background: rgba(3, 2, 1, 0); + border-color: inherit; + width: auto; + padding-right: $mm_subopenWidth; + position: relative; + + &:not(.mm-listitem__text) { + border-left-width: 1px; + border-left-style: solid; + } +} + +#{$mm_module} { + &_selected { + > #{$mm_module}__text { + @if ($mm_IE11Fallbacks) { + background: $mm_emphasizedBackgroundColor; + } + + background: var(--mm-color-background-emphasis); + } + } + + &_opened { + > #{$mm_module}__btn, + > .mm-panel { + @if ($mm_IE11Fallbacks) { + background: $mm_highlightedBackgroundColor; + } + + background: var(--mm-color-background-highlight); + } + } +} diff --git a/src/core/oncanvas/_oncanvas.menu.rtl.scss b/src/core/oncanvas/_oncanvas.menu.rtl.scss new file mode 100644 index 0000000..e62de5f --- /dev/null +++ b/src/core/oncanvas/_oncanvas.menu.rtl.scss @@ -0,0 +1,5 @@ +@if ( $mm_include_rtl ) { + [dir="rtl"] .mm-menu { + direction: rtl; + } +} \ No newline at end of file diff --git a/src/core/oncanvas/_oncanvas.menu.scss b/src/core/oncanvas/_oncanvas.menu.scss new file mode 100644 index 0000000..32ae980 --- /dev/null +++ b/src/core/oncanvas/_oncanvas.menu.scss @@ -0,0 +1,45 @@ +.mm-menu { + @if ($mm_IE11Fallbacks) { + top: $mm_offsetTop; + right: $mm_offsetRight; + bottom: $mm_offsetBottom; + left: $mm_offsetLeft; + + background: $mm_backgroundColor; + border-color: $mm_borderColor; + color: $mm_textColor; + line-height: $mm_lineHeight; + } + + display: flex; + flex-direction: column; + padding: 0; + margin: 0; + box-sizing: border-box; + + position: absolute; + top: var(--mm-offset-top); + right: var(--mm-offset-right); + bottom: var(--mm-offset-bottom); + left: var(--mm-offset-left); + z-index: 0; + + background: var(--mm-color-background); + border-color: var(--mm-color-border); + color: var(--mm-color-text); + line-height: var(--mm-line-height); + + -webkit-tap-highlight-color: var(--mm-color-background-emphasis); + + -webkit-font-smoothing: antialiased; + -moz-osx-font-smoothing: grayscale; + + a, + a:link, + a:active, + a:visited, + a:hover { + text-decoration: none; + color: inherit; + } +} diff --git a/src/core/oncanvas/_oncanvas.navbar.rtl.scss b/src/core/oncanvas/_oncanvas.navbar.rtl.scss new file mode 100644 index 0000000..0242375 --- /dev/null +++ b/src/core/oncanvas/_oncanvas.navbar.rtl.scss @@ -0,0 +1,9 @@ +$mm_module: '.mm-navbar'; + +@if ($mm_include_rtl) { + [dir='rtl'] { + #{$mm_module} { + flex-direction: row-reverse; + } + } +} diff --git a/src/core/oncanvas/_oncanvas.navbar.scss b/src/core/oncanvas/_oncanvas.navbar.scss new file mode 100644 index 0000000..12b7158 --- /dev/null +++ b/src/core/oncanvas/_oncanvas.navbar.scss @@ -0,0 +1,71 @@ +$mm_module: '.mm-navbar'; + +#{$mm_module} { + @if ($mm_IE11Fallbacks) { + min-height: $mm_navbarSize; + border-bottom: 1px solid $mm_borderColor; + background: $mm_backgroundColor; + color: $mm_dimmedTextColor; + + > * { + min-height: $mm_navbarSize; + } + } + + display: flex; + min-height: var(--mm-navbar-size); + border-bottom: 1px solid var(--mm-color-border); + background: var(--mm-color-background); + color: var(--mm-color-text-dimmed); + text-align: center; + + opacity: 1; + transition: opacity $mm_transitionDuration $mm_transitionFunction; + + @supports (position: sticky) { + &_sticky { + position: sticky; + top: 0; + z-index: 1; + } + } + + > * { + flex-grow: 1; + display: flex; + align-items: center; + justify-content: center; + box-sizing: border-box; + } +} + +#{$mm_module}__btn { + flex-grow: 0; +} + +#{$mm_module}__title { + + flex: 1 1 50%; + display: flex; + padding-left: $mm_panelPadding; + padding-right: $mm_panelPadding; + overflow: hidden; + + // Center the content. + &:not(:last-child) { + padding-right: 0; + } + + > span { + @include mm_ellipsis; + } + + #{$mm_module}__btn:not(.mm-hidden) + & { + padding-left: 0; + + &:last-child { + padding-right: $mm_btnSize; + } + } + // /Center +} diff --git a/src/core/oncanvas/_oncanvas.panels.rtl.scss b/src/core/oncanvas/_oncanvas.panels.rtl.scss new file mode 100644 index 0000000..542c648 --- /dev/null +++ b/src/core/oncanvas/_oncanvas.panels.rtl.scss @@ -0,0 +1,11 @@ +@if ($mm_include_rtl) { + [dir='rtl'] .mm-panel { + &:not(.mm-panel_opened) { + transform: translate3d(-100%, 0, 0); + } + + &.mm-panel_opened-parent { + transform: translate3d(30%, 0, 0); + } + } +} diff --git a/src/core/oncanvas/_oncanvas.panels.scss b/src/core/oncanvas/_oncanvas.panels.scss new file mode 100644 index 0000000..4cf9422 --- /dev/null +++ b/src/core/oncanvas/_oncanvas.panels.scss @@ -0,0 +1,91 @@ +$mm_module: '.mm-panel'; + +#{$mm_module} { + @if ($mm_IE11Fallbacks) { + background: $mm_backgroundColor; + border-color: $mm_borderColor; + color: $mm_textColor; + + &:after { + height: $mm_listitemSize; + } + } + + z-index: 0; + box-sizing: border-box; + width: 100%; + + -webkit-overflow-scrolling: touch; + overflow: scroll; + overflow-x: hidden; + overflow-y: auto; + + background: var(--mm-color-background); + border-color: var(--mm-color-border); + color: var(--mm-color-text); + + transform: translate3d(100%, 0, 0); + transition: transform $mm_transitionDuration $mm_transitionFunction; + + // Fixes css from other styles hiding submenus + &:not(.mm-hidden) { + display: block; + } + + // Because padding-bottom is ignored when a DIV is scrollable + &:after { + content: ''; + display: block; + height: var(--mm-listitem-size); + } + + &_opened { + z-index: 1; + transform: translate3d(0%, 0, 0); + } + + &_opened-parent { + transform: translate3d(-$mm_subpanelOffset, 0, 0); + } + + &_highest { + z-index: 2; + } + + &_noanimation { + transition: none !important; + + &#{$mm_module}_opened-parent { + transform: translate3d(0, 0, 0); + } + } + + .mm-panels > & { + position: absolute; + left: 0; + right: 0; + top: 0; + bottom: 0; + } +} + +#{$mm_module}__content { + padding: $mm_panelPadding $mm_panelPadding 0; +} + +.mm-panels { + @if ($mm_IE11Fallbacks) { + background: $mm_backgroundColor; + border-color: $mm_borderColor; + color: $mm_textColor; + } + + position: relative; + height: 100%; + flex-grow: 1; + overflow: hidden; + + background: var(--mm-color-background); + border-color: var(--mm-color-border); + color: var(--mm-color-text); +} diff --git a/src/core/oncanvas/_oncanvas.vertical.scss b/src/core/oncanvas/_oncanvas.vertical.scss new file mode 100644 index 0000000..5e29fca --- /dev/null +++ b/src/core/oncanvas/_oncanvas.vertical.scss @@ -0,0 +1,41 @@ +@if ($mm_include_vertical) { + .mm-listitem_vertical > .mm-panel { + display: none; + width: 100%; + padding: $mm_padding 0 $mm_padding $mm_padding; + + transform: none !important; + + &:before, + &:after { + content: none; + display: none; + } + } + + .mm-listitem_opened > .mm-panel { + display: block; + } + + .mm-listitem_vertical { + > .mm-listitem__btn { + @if ($mm_IE11Fallbacks) { + height: $mm_listitemSize; + } + + height: var(--mm-listitem-size); + bottom: auto; + } + + .mm-listitem:last-child:after { + border-color: transparent; + } + } + + .mm-listitem_opened { + > .mm-listitem__btn:after { + transform: rotate(225deg); + right: $mm_listitemIndent - 1; + } + } +} diff --git a/src/core/oncanvas/_options.ts b/src/core/oncanvas/_options.ts new file mode 100644 index 0000000..745e23f --- /dev/null +++ b/src/core/oncanvas/_options.ts @@ -0,0 +1,18 @@ +const options: mmOptions = { + hooks: {}, + extensions: [], + wrappers: [], + navbar: { + add: true, + sticky: true, + title: 'Menu', + titleLink: 'parent' + }, + onClick: { + close: null, + preventDefault: null, + setSelected: true + }, + slidingSubmenus: true +}; +export default options; diff --git a/src/core/oncanvas/_typings.d.ts b/src/core/oncanvas/_typings.d.ts new file mode 100644 index 0000000..28f0aaf --- /dev/null +++ b/src/core/oncanvas/_typings.d.ts @@ -0,0 +1,229 @@ +/** An object with any value. */ +interface mmLooseObject { + [key: string]: any; +} + +/** An object with string values. */ +interface mmStringObject { + [key: string]: string; +} + +/** An object with boolean values. */ +interface mmBooleanObject { + [key: string]: boolean; +} + +/** An object with function values. */ +interface mmFunctionObject { + [key: string]: Function; +} + +/** An object with even listeners. */ +interface mmEventObject { + [key: string]: EventListener; +} + +/** An object with HTMLElement values. */ +interface mmHtmlObject { + [key: string]: HTMLElement; +} + +/** The menu API. */ +interface mmApi { + bind: Function; + initPanel: Function; + openPanel: Function; + closePanel: Function; + closeAllPanels: Function; + setSelected: Function; + + // offCanvas add-on + open: Function; + close: Function; + setPage: Function; + + // searchfield add-on + search: Function; +} + +// Class methods interfaces. +interface mmMethodUniqueid { + (): string; +} +interface mmMethodI18n { + (text?: object, language?: string): object; + (text?: string, language?: string): string; + (text?: undefined, language?: string): object; +} + +/** Options for the menu. */ +interface mmOptions { + /** A collection of extensions to enable for the menu. */ + extensions?: mmOptionsExensions | string[]; + + /** A collection of functions to hook into the API methods before the menu is initialised. */ + hooks?: mmFunctionObject; + + /** Options for the navbar. */ + navbar?: mmOptionsNavbar; + + /** Options for clicking a listitem. */ + onClick?: mmOptionsOnclick; + + /** Whether or not submenus should come sliding in from the right. */ + slidingSubmenus?: boolean; + + /** A collection of framework wrappers to enable for the menu. */ + wrappers?: string[]; + + // Core add-ons + + /** Options for the off-canvas add-on. */ + offCanvas?: mmOptionsOffcanvas; + + /** Options for the screen reader add-on. */ + screenReader?: mmOptionsScreenreader; + + /** Options for the scroll bug fix add-on. */ + scrollBugFix?: mmOptionsScrollbugfix; + + // Add-ons + + /** Options for the auto height add-on. */ + autoHeight?: mmOptionsAutoheight; + + /** Options for the back button add-on. */ + backButton?: mmOptionsBackbutton; + + /** Options for the columns add-on. */ + columns?: mmOptionsColumns; + + /** Options for the counters add-on. */ + counters?: mmOptionsCounters; + + /** Options for the dividers add-on. */ + dividers?: mmOptionsDividers; + + /** Options for the drag add-on. */ + drag?: mmOptionsDrag; + + /** Options for the dropdown add-on. */ + dropdown?: mmOptionsDropdown; + + /** Options for the iconbar add-on. */ + iconbar?: mmOptionsIconbar; + + /** Options for the icon panels add-on. */ + iconPanels?: mmOptionsIconpanels; + + /** Options for the keyboard navigation add-on. */ + keyboardNavigation?: mmOptionsKeyboardnavigation; + + /** Options for the lazy submenus add-on. */ + lazySubmenus?: mmOptionsLazysubmenus; + + /** List of navbar options for the navbars add-on. */ + navbars?: mmOptionsNavbarsNavbar[]; + + /** Options for the page scroll add-on. */ + pageScroll?: mmOptionsPagescroll; + + /** Options for the searchfield add-on. */ + searchfield?: mmOptionsSearchfield; + + /** Options for the section indexer add-on. */ + sectionIndexer?: mmOptionsSectionindexer; + + /** Options for the set selected add-on. */ + setSelected?: mmOptionsSetselected; + + /** Options for the sidebar add-on. */ + sidebar?: mmOptionsSidebar; +} + +/** Extensions for the menu. */ +interface mmOptionsExensions { + [key: string]: mmOptionsExensions | string[]; +} + +/** Navbar options for the menu. */ +interface mmOptionsNavbar { + /** Whether or not to add a navbar above the panels. */ + add?: boolean; + + /** Whether or not the navbars should be sticky. */ + sticky?: boolean; + + /** The title above the panels. */ + title?: string; + + /** The type of link to set for the title. */ + titleLink?: 'parent' | 'anchor' | 'none'; +} + +/** onClick options for the menu. */ +interface mmOptionsOnclick { + /** Whether or not the menu should close after clicking a link inside it. */ + close?: boolean; + + /** Whether or not to prevent the default behavior for the clicked link. */ + preventDefault?: boolean; + + /** Whether or not the clicked link should appear as "selected". */ + setSelected?: boolean; +} + +/** Configuration for the menu. */ +interface mmConfigs { + /** Object with classnames to refactor. */ + classNames?: mmLooseObject; + + /** The language to translate the menu to. */ + language?: 'en' | 'nl' | 'de' | 'ru' | 'fa'; + + /** The number of milliseconds between opening/closing the menu and panels, needed to force CSS transitions. */ + openingInterval?: number; + + /** List of possible node-type of panels. */ + panelNodetype?: string[]; + + /** The number of milliseconds used in the CSS transitions. */ + transitionDuration?: number; + + // Core add-ons + + /** Configuration for the off-canvas add-on. */ + offCanvas?: mmConfigsOffcanvas; + + /** Configuration for the screen reader add-on. */ + screenReader?: mmConfigsScreenreader; + + // Add-ons + + /** Configuration for the dropdown add-on. */ + dropdown?: mmConfigsDropdown; + + /** Configuration for the fixed elements add-on. */ + fixedElements?: mmConfigsFixedelements; + + /** Configuration for the navbars add-on. */ + navbars?: mmConfigsNavbars; + + /** Configuration for the page scroll add-on. */ + pageScroll?: mmConfigsPagescroll; + + /** Configuration for the searchfield add-on. */ + searchfield?: mmConfigsSearchfield; +} + +/** Arguments for the onClick handlers. */ +interface mmClickArguments { + /** Whether or not the anchor is inside the menu. */ + inMenu: boolean; + + /** Whether or not the anchor is inside a listview. */ + inListview: boolean; + + /** Whether or not the anchor references to an external page. */ + toExternal: boolean; +} diff --git a/src/core/oncanvas/_variables.scss b/src/core/oncanvas/_variables.scss new file mode 100644 index 0000000..c6c02c8 --- /dev/null +++ b/src/core/oncanvas/_variables.scss @@ -0,0 +1,31 @@ +// Animations +$mm_transitionDuration: 0.4s !default; +$mm_transitionDelay: 0.4s !default; +$mm_transitionFunction: ease !default; + +// Colors +$mm_backgroundColor: #f3f3f3 !default; +$mm_borderColor: rgba(#000, 0.1) !default; +$mm_dimmedTextColor: rgba(#000, 0.3) !default; +$mm_emphasizedBackgroundColor: rgba(#fff, 0.4) !default; +$mm_highlightedBackgroundColor: rgba(#000, 0.05) !default; +$mm_navbarColor: rgba(#000, 0.3) !default; +$mm_textColor: rgba(#000, 0.75) !default; + +// Positioning +$mm_offsetTop: 0 !default; +$mm_offsetRight: 0 !default; +$mm_offsetBottom: 0 !default; +$mm_offsetLeft: 0 !default; + +// Sizes +$mm_listitemSize: 44px !default; +$mm_btnSize: 50px !default; +$mm_padding: 10px !default; +$mm_lineHeight: 20px !default; + +$mm_listitemIndent: $mm_padding * 2 !default; +$mm_navbarSize: $mm_listitemSize !default; +$mm_panelPadding: $mm_padding * 2 !default; +$mm_subopenWidth: $mm_btnSize !default; +$mm_subpanelOffset: 30% !default; diff --git a/src/core/oncanvas/mmenu.oncanvas.scss b/src/core/oncanvas/mmenu.oncanvas.scss new file mode 100644 index 0000000..9c87c0b --- /dev/null +++ b/src/core/oncanvas/mmenu.oncanvas.scss @@ -0,0 +1,41 @@ +@import '../../mixins', '../../includes', '../../variables'; + +// Variables +:root { + // sizes + --mm-line-height: #{$mm_lineHeight}; + --mm-listitem-size: #{$mm_listitemSize}; + --mm-navbar-size: #{$mm_navbarSize}; + + // positioning + --mm-offset-top: #{$mm_offsetTop}; + --mm-offset-right: #{$mm_offsetRight}; + --mm-offset-bottom: #{$mm_offsetBottom}; + --mm-offset-left: #{$mm_offsetLeft}; + + // colors + --mm-color-border: #{$mm_borderColor}; + --mm-color-button: #{$mm_dimmedTextColor}; + --mm-color-text: #{$mm_textColor}; + --mm-color-text-dimmed: #{$mm_dimmedTextColor}; + --mm-color-background: #{$mm_backgroundColor}; + --mm-color-background-highlight: #{$mm_highlightedBackgroundColor}; + --mm-color-background-emphasis: #{$mm_emphasizedBackgroundColor}; + + // misc + --mm-shadow: 0 0 10px rgba(0, 0, 0, 0.3); +} + +.mm-hidden { + display: none !important; +} + +.mm-wrapper { + overflow-x: hidden; + position: relative; +} + +@import 'oncanvas.menu', 'oncanvas.menu.rtl', 'oncanvas.panels', + 'oncanvas.panels.rtl', 'oncanvas.vertical', 'oncanvas.buttons', + 'oncanvas.buttons.rtl', 'oncanvas.navbar', 'oncanvas.navbar.rtl', + 'oncanvas.listviews', 'oncanvas.listviews.rtl'; diff --git a/src/core/oncanvas/mmenu.oncanvas.ts b/src/core/oncanvas/mmenu.oncanvas.ts new file mode 100644 index 0000000..1085cc0 --- /dev/null +++ b/src/core/oncanvas/mmenu.oncanvas.ts @@ -0,0 +1,1066 @@ +import version from '../../_version'; +import options from './_options'; +import configs from './_configs'; +import translate from './translations/translate'; +import * as DOM from '../../_modules/dom'; +import * as i18n from '../../_modules/i18n'; +import * as media from '../../_modules/matchmedia'; +import { + type, + extend, + transitionend, + uniqueId, + valueOrFn +} from '../../_modules/helpers'; + +// Add the translations. +translate(); + +/** + * Class for a mobile menu. + */ +export default class Mmenu { + /** Plugin version. */ + static version: string = version; + + /** Default options for menus. */ + static options: mmOptions = options; + + /** Default configuration for menus. */ + static configs: mmConfigs = configs; + + /** Available add-ons for the plugin. */ + static addons: mmLooseObject = {}; + + /** Available wrappers for the plugin. */ + static wrappers: mmFunctionObject = {}; + + /** Globally used HTML elements. */ + static node: mmHtmlObject = {}; + + /** Globally used variables. */ + static vars: mmLooseObject = {}; + + /** Options for the menu. */ + opts: mmOptions; + + /** Configuration for the menu. */ + conf: mmConfigs; + + /** Array of method names to expose in the API. */ + _api: string[]; + + /** The API. */ + API: mmApi; + + /** HTML elements used for the menu. */ + node: mmHtmlObject; + + /** Variables used for the menu. */ + vars: mmLooseObject; + + /** Callback hooks used for the menu. */ + hook: mmLooseObject; + + /** Click handlers used for the menu. */ + clck: Function[]; + + /** Log deprecated warnings when using the debugger. */ + _deprecatedWarnings: Function; + + // screenReader add-on + static sr_aria: Function; + static sr_role: Function; + static sr_text: Function; + + // offCanvas add-on + + /** Open the menu. */ + open: Function; + + /** Setup the menu so it can be opened. */ + _openSetup: Function; + + /** The menu starts opening. */ + _openStart: Function; + + /** Close the menu. */ + close: Function; + + /** Close all other menus. */ + closeAllOthers: Function; + + /** Set the page HTML element. */ + setPage: Function; + + // searchfield add-on + + /** Search the menu */ + search: Function; + + /** + * Create a mobile menu. + * @param {HTMLElement|string} menu The menu node. + * @param {object} [options=Mmenu.options] Options for the menu. + * @param {object} [configs=Mmenu.configs] Configuration options for the menu. + */ + constructor( + menu: HTMLElement | string, + options?: mmOptions, + configs?: mmConfigs + ) { + // Extend options and configuration from defaults. + this.opts = extend(options, Mmenu.options); + this.conf = extend(configs, Mmenu.configs); + + // Methods to expose in the API. + this._api = [ + 'bind', + 'initPanel', + 'initListview', + 'openPanel', + 'closePanel', + 'closeAllPanels', + 'setSelected' + ]; + + // Storage objects for nodes, variables, hooks and click handlers. + this.node = {}; + this.vars = {}; + this.hook = {}; + this.clck = []; + + // Get menu node from string or element. + this.node.menu = + typeof menu == 'string' ? document.querySelector(menu) : menu; + + if (typeof this._deprecatedWarnings == 'function') { + this._deprecatedWarnings(); + } + + this._initWrappers(); + this._initAddons(); + this._initExtensions(); + + this._initHooks(); + this._initAPI(); + + this._initMenu(); + this._initPanels(); + this._initOpened(); + this._initAnchors(); + + media.watch(); + + return this; + } + + /** + * Open a panel. + * @param {HTMLElement} panel Panel to open. + * @param {boolean} [animation=true] Whether or not to open the panel with an animation. + */ + openPanel(panel: HTMLElement, animation?: boolean) { + // Invoke "before" hook. + this.trigger('openPanel:before', [panel]); + + // Find panel. + if (!panel) { + return; + } + if (!panel.matches('.mm-panel')) { + panel = panel.closest('.mm-panel') as HTMLElement; + } + if (!panel) { + return; + } + // /Find panel. + + if (typeof animation != 'boolean') { + animation = true; + } + + // Open a "vertical" panel. + if (panel.parentElement.matches('.mm-listitem_vertical')) { + // Open current and all vertical parent panels. + DOM.parents(panel, '.mm-listitem_vertical').forEach(listitem => { + listitem.classList.add('mm-listitem_opened'); + DOM.children(listitem, '.mm-panel').forEach(panel => { + panel.classList.remove('mm-hidden'); + }); + }); + + // Open first non-vertical parent panel. + let parents = DOM.parents(panel, '.mm-panel').filter( + panel => !panel.parentElement.matches('.mm-listitem_vertical') + ); + + this.trigger('openPanel:start', [panel]); + + if (parents.length) { + this.openPanel(parents[0]); + } + + this.trigger('openPanel:finish', [panel]); + + // Open a "horizontal" panel. + } else { + if (panel.matches('.mm-panel_opened')) { + return; + } + + let panels = DOM.children(this.node.pnls, '.mm-panel'), + current = DOM.children(this.node.pnls, '.mm-panel_opened')[0]; + + // Close all child panels. + panels + .filter(parent => parent !== panel) + .forEach(parent => { + parent.classList.remove('mm-panel_opened-parent'); + }); + + // Open all parent panels. + let parent: HTMLElement = panel['mmParent']; + while (parent) { + parent = parent.closest('.mm-panel') as HTMLElement; + if (parent) { + if ( + !parent.parentElement.matches('.mm-listitem_vertical') + ) { + parent.classList.add('mm-panel_opened-parent'); + } + parent = parent['mmParent']; + } + } + + // Add classes for animation. + panels.forEach(panel => { + panel.classList.remove('mm-panel_highest'); + }); + + panels + .filter(hidden => hidden !== current) + .filter(hidden => hidden !== panel) + .forEach(hidden => { + hidden.classList.add('mm-hidden'); + }); + + panel.classList.remove('mm-hidden'); + + /** Start opening the panel. */ + let openPanelStart = () => { + if (current) { + current.classList.remove('mm-panel_opened'); + } + panel.classList.add('mm-panel_opened'); + + if (panel.matches('.mm-panel_opened-parent')) { + if (current) { + current.classList.add('mm-panel_highest'); + } + panel.classList.remove('mm-panel_opened-parent'); + } else { + if (current) { + current.classList.add('mm-panel_opened-parent'); + } + panel.classList.add('mm-panel_highest'); + } + + // Invoke "start" hook. + this.trigger('openPanel:start', [panel]); + }; + + /** Finish opening the panel. */ + let openPanelFinish = () => { + if (current) { + current.classList.remove('mm-panel_highest'); + current.classList.add('mm-hidden'); + } + panel.classList.remove('mm-panel_highest'); + + // Invoke "finish" hook. + this.trigger('openPanel:finish', [panel]); + }; + + if (animation && !panel.matches('.mm-panel_noanimation')) { + // Without the timeout the animation will not work because the element had display: none; + setTimeout(() => { + // Callback + transitionend( + panel, + () => { + openPanelFinish(); + }, + this.conf.transitionDuration + ); + + openPanelStart(); + }, this.conf.openingInterval); + } else { + openPanelStart(); + openPanelFinish(); + } + } + + // Invoke "after" hook. + this.trigger('openPanel:after', [panel]); + } + + /** + * Close a panel. + * @param {HTMLElement} panel Panel to close. + */ + closePanel(panel: HTMLElement) { + // Invoke "before" hook. + this.trigger('closePanel:before', [panel]); + + var li = panel.parentElement; + + // Only works for "vertical" panels. + if (li.matches('.mm-listitem_vertical')) { + li.classList.remove('mm-listitem_opened'); + panel.classList.add('mm-hidden'); + + // Invoke main hook. + this.trigger('closePanel', [panel]); + } + + // Invoke "after" hook. + this.trigger('closePanel:after', [panel]); + } + + /** + * Close all opened panels. + * @param {HTMLElement} panel Panel to open after closing all other panels. + */ + closeAllPanels(panel?: HTMLElement) { + // Invoke "before" hook. + this.trigger('closeAllPanels:before'); + + // Close all "vertical" panels. + let listitems = this.node.pnls.querySelectorAll('.mm-listitem'); + listitems.forEach(listitem => { + listitem.classList.remove('mm-listitem_selected'); + listitem.classList.remove('mm-listitem_opened'); + }); + + // Close all "horizontal" panels. + var panels = DOM.children(this.node.pnls, '.mm-panel'), + opened = panel ? panel : panels[0]; + + DOM.children(this.node.pnls, '.mm-panel').forEach(panel => { + if (panel !== opened) { + panel.classList.remove('mm-panel_opened'); + panel.classList.remove('mm-panel_opened-parent'); + panel.classList.remove('mm-panel_highest'); + panel.classList.add('mm-hidden'); + } + }); + + // Open first panel. + this.openPanel(opened, false); + + // Invoke "after" hook. + this.trigger('closeAllPanels:after'); + } + + /** + * Toggle a panel opened/closed. + * @param {HTMLElement} panel Panel to open or close. + */ + togglePanel(panel: HTMLElement) { + let listitem = panel.parentElement; + + // Only works for "vertical" panels. + if (listitem.matches('.mm-listitem_vertical')) { + this[ + listitem.matches('.mm-listitem_opened') + ? 'closePanel' + : 'openPanel' + ](panel); + } + } + + /** + * Display a listitem as being "selected". + * @param {HTMLElement} listitem Listitem to mark. + */ + setSelected(listitem: HTMLElement) { + // Invoke "before" hook. + this.trigger('setSelected:before', [listitem]); + + // First, remove the selected class from all listitems. + DOM.find(this.node.menu, '.mm-listitem_selected').forEach(li => { + li.classList.remove('mm-listitem_selected'); + }); + + // Next, add the selected class to the provided listitem. + listitem.classList.add('mm-listitem_selected'); + + // Invoke "after" hook. + this.trigger('setSelected:after', [listitem]); + } + + /** + * Bind functions to a hook (subscriber). + * @param {string} hook The hook. + * @param {function} func The function. + */ + bind(hook: string, func: Function) { + // Create an array for the hook if it does not yet excist. + this.hook[hook] = this.hook[hook] || []; + + // Push the function to the array. + this.hook[hook].push(func); + } + + /** + * Invoke the functions bound to a hook (publisher). + * @param {string} hook The hook. + * @param {array} [args] Arguments for the function. + */ + trigger(hook: string, args?: any[]) { + if (this.hook[hook]) { + for (var h = 0, l = this.hook[hook].length; h < l; h++) { + this.hook[hook][h].apply(this, args); + } + } + } + + /** + * Create the API. + */ + _initAPI() { + // We need this=that because: + // 1) the "arguments" object can not be referenced in an arrow function in ES3 and ES5. + var that = this; + + (this.API as mmLooseObject) = {}; + + this._api.forEach(fn => { + this.API[fn] = function() { + var re = that[fn].apply(that, arguments); // 1) + return typeof re == 'undefined' ? that.API : re; + }; + }); + + // Store the API in the HTML node for external usage. + this.node.menu['mmApi'] = this.API; + } + + /** + * Bind the hooks specified in the options (publisher). + */ + _initHooks() { + for (let hook in this.opts.hooks) { + this.bind(hook, this.opts.hooks[hook]); + } + } + + /** + * Initialize the wrappers specified in the options. + */ + _initWrappers() { + // Invoke "before" hook. + this.trigger('initWrappers:before'); + + for (let w = 0; w < this.opts.wrappers.length; w++) { + let wrpr = Mmenu.wrappers[this.opts.wrappers[w]]; + if (typeof wrpr == 'function') { + wrpr.call(this); + } + } + + // Invoke "after" hook. + this.trigger('initWrappers:after'); + } + + /** + * Initialize all available add-ons. + */ + _initAddons() { + // Invoke "before" hook. + this.trigger('initAddons:before'); + + for (let addon in Mmenu.addons) { + Mmenu.addons[addon].call(this); + } + + // Invoke "after" hook. + this.trigger('initAddons:after'); + } + + /** + * Initialize the extensions specified in the options. + */ + _initExtensions() { + // Invoke "before" hook. + this.trigger('initExtensions:before'); + + // Convert array to object with array. + if (type(this.opts.extensions) == 'array') { + this.opts.extensions = { + all: this.opts.extensions + }; + } + + // Loop over object. + Object.keys(this.opts.extensions).forEach(query => { + let classnames = this.opts.extensions[query].map( + extension => 'mm-menu_' + extension + ); + + if (classnames.length) { + media.add( + query, + () => { + // IE11: + classnames.forEach(classname => { + this.node.menu.classList.add(classname); + }); + + // Better browsers: + // this.node.menu.classList.add(...classnames); + }, + () => { + // IE11: + classnames.forEach(classname => { + this.node.menu.classList.remove(classname); + }); + + // Better browsers: + // this.node.menu.classList.remove(...classnames); + } + ); + } + }); + + // Invoke "after" hook. + this.trigger('initExtensions:after'); + } + + /** + * Initialize the menu. + */ + _initMenu() { + // Invoke "before" hook. + this.trigger('initMenu:before'); + + // Add class to the wrapper. + this.node.wrpr = this.node.wrpr || this.node.menu.parentElement; + this.node.wrpr.classList.add('mm-wrapper'); + + // Add an ID to the menu if it does not yet have one. + this.node.menu.id = this.node.menu.id || uniqueId(); + + // Wrap the panels in a node. + let panels = DOM.create('div.mm-panels'); + + DOM.children(this.node.menu).forEach(panel => { + if ( + this.conf.panelNodetype.indexOf(panel.nodeName.toLowerCase()) > + -1 + ) { + panels.append(panel); + } + }); + + this.node.menu.append(panels); + this.node.pnls = panels; + + // Add class to the menu. + this.node.menu.classList.add('mm-menu'); + + // Invoke "after" hook. + this.trigger('initMenu:after'); + } + + /** + * Initialize panels. + */ + _initPanels() { + // Invoke "before" hook. + this.trigger('initPanels:before'); + + // Open / close panels. + this.clck.push((anchor: HTMLElement, args: mmClickArguments) => { + if (args.inMenu) { + var href = anchor.getAttribute('href'); + if (href && href.length > 1 && href.slice(0, 1) == '#') { + try { + let panel = DOM.find(this.node.menu, href)[0]; + if (panel && panel.matches('.mm-panel')) { + if ( + anchor.parentElement.matches( + '.mm-listitem_vertical' + ) + ) { + this.togglePanel(panel); + } else { + this.openPanel(panel); + } + return true; + } + } catch (err) {} + } + } + }); + + /** The panels to initiate */ + const panels = DOM.children(this.node.pnls); + + panels.forEach(panel => { + this.initPanel(panel); + }); + + // Invoke "after" hook. + this.trigger('initPanels:after'); + } + + /** + * Initialize a single panel and its children. + * @param {HTMLElement} panel The panel to initialize. + */ + initPanel(panel: HTMLElement) { + /** Query selector for possible node-types for panels. */ + var panelNodetype = this.conf.panelNodetype.join(', '); + + if (panel.matches(panelNodetype)) { + // Only once + if (!panel.matches('.mm-panel')) { + panel = this._initPanel(panel); + } + + if (panel) { + /** The sub panels. */ + let children: HTMLElement[] = []; + + // Find panel > panel + children.push( + ...DOM.children(panel, '.' + this.conf.classNames.panel) + ); + + // Find panel listitem > panel + DOM.children(panel, '.mm-listview').forEach(listview => { + DOM.children(listview, '.mm-listitem').forEach(listitem => { + children.push(...DOM.children(listitem, panelNodetype)); + }); + }); + + // Initiate subpanel(s). + children.forEach(child => { + this.initPanel(child); + }); + } + } + } + + /** + * Initialize a single panel. + * @param {HTMLElement} panel Panel to initialize. + * @return {HTMLElement|null} Initialized panel. + */ + _initPanel(panel: HTMLElement): HTMLElement { + // Invoke "before" hook. + this.trigger('initPanel:before', [panel]); + + // Refactor panel classnames + DOM.reClass(panel, this.conf.classNames.panel, 'mm-panel'); + DOM.reClass(panel, this.conf.classNames.nopanel, 'mm-nopanel'); + DOM.reClass(panel, this.conf.classNames.inset, 'mm-listview_inset'); + + if (panel.matches('.mm-listview_inset')) { + panel.classList.add('mm-nopanel'); + } + + // Stop if not supposed to be a panel. + if (panel.matches('.mm-nopanel')) { + return null; + } + + /** The original ID on the node. */ + var id = panel.id || uniqueId(); + + // Vertical panel. + var vertical = + panel.matches('.' + this.conf.classNames.vertical) || + !this.opts.slidingSubmenus; + + panel.classList.remove(this.conf.classNames.vertical); + + // Wrap UL/OL in DIV + if (panel.matches('ul, ol')) { + panel.removeAttribute('id'); + + /** The panel. */ + let wrapper = DOM.create('div'); + + // Wrap the listview in the panel. + panel.before(wrapper); + wrapper.append(panel); + panel = wrapper; + } + + panel.id = id; + panel.classList.add('mm-panel'); + panel.classList.add('mm-hidden'); + + /** The parent listitem. */ + var parent = [panel.parentElement].filter(listitem => + listitem.matches('li') + )[0]; + + if (vertical) { + if (parent) { + parent.classList.add('mm-listitem_vertical'); + } + } else { + this.node.pnls.append(panel); + } + + if (parent) { + // Store parent/child relation. + parent['mmChild'] = panel; + panel['mmParent'] = parent; + + // Add open link to parent listitem + if (parent && parent.matches('.mm-listitem')) { + if (!DOM.children(parent, '.mm-btn').length) { + /** The text node. */ + let item = DOM.children(parent, '.mm-listitem__text')[0]; + + if (item) { + /** The open link. */ + let button = DOM.create( + 'a.mm-btn.mm-btn_next.mm-listitem__btn' + ); + button.setAttribute('href', '#' + panel.id); + + // If the item has no link, + // Replace the item with the open link. + if (item.matches('span')) { + button.classList.add('mm-listitem__text'); + button.innerHTML = item.innerHTML; + parent.insertBefore( + button, + item.nextElementSibling + ); + item.remove(); + } + + // Otherwise, insert the button after the text. + else { + parent.insertBefore( + button, + DOM.children(parent, '.mm-panel')[0] + ); + } + } + } + } + } + + this._initNavbar(panel); + + DOM.children(panel, 'ul, ol').forEach(listview => { + this.initListview(listview); + }); + + // Invoke "after" hook. + this.trigger('initPanel:after', [panel]); + + return panel; + } + + /** + * Initialize a navbar. + * @param {HTMLElement} panel Panel for the navbar. + */ + _initNavbar(panel: HTMLElement) { + // Invoke "before" hook. + this.trigger('initNavbar:before', [panel]); + + // Only one navbar per panel. + if (DOM.children(panel, '.mm-navbar').length) { + return; + } + + /** The parent listitem. */ + let parentListitem: HTMLElement = null; + + /** The parent panel. */ + let parentPanel: HTMLElement = null; + + // The parent panel was specified in the data-mm-parent attribute. + if (panel.getAttribute('data-mm-parent')) { + parentPanel = DOM.find( + this.node.pnls, + panel.getAttribute('data-mm-parent') + )[0]; + } + // if (panel.dataset.mmParent) { // IE10 has no dataset + // parentPanel = DOM.find(this.node.pnls, panel.dataset.mmParent)[0]; + // } + + // The parent panel from a listitem. + else { + parentListitem = panel['mmParent']; + + if (parentListitem) { + parentPanel = parentListitem.closest( + '.mm-panel' + ) as HTMLElement; + } + } + + // No navbar needed for vertical submenus. + if (parentListitem && parentListitem.matches('.mm-listitem_vertical')) { + return; + } + + /** The navbar element. */ + let navbar = DOM.create('div.mm-navbar'); + + // Hide navbar if specified in options. + if (!this.opts.navbar.add) { + navbar.classList.add('mm-hidden'); + } + + // Sticky navbars. + else if (this.opts.navbar.sticky) { + navbar.classList.add('mm-navbar_sticky'); + } + + // Add the back button. + if (parentPanel) { + /** The back button. */ + let prev = DOM.create('a.mm-btn.mm-btn_prev.mm-navbar__btn'); + prev.setAttribute('href', '#' + parentPanel.id); + + navbar.append(prev); + } + + /** The anchor that opens the panel. */ + let opener: HTMLElement = null; + + // The anchor is in a listitem. + if (parentListitem) { + opener = DOM.children(parentListitem, '.mm-listitem__text')[0]; + } + + // The anchor is in a panel. + else if (parentPanel) { + opener = DOM.find(parentPanel, 'a[href="#' + panel.id + '"]')[0]; + } + + // Add the title. + let title = DOM.create('a.mm-navbar__title'); + let titleText = DOM.create('span'); + title.append(titleText); + titleText.innerHTML = + // panel.dataset.mmTitle || // IE10 has no dataset :( + panel.getAttribute('data-mm-title') || + (opener ? opener.textContent : '') || + this.i18n(this.opts.navbar.title) || + this.i18n('Menu'); + + switch (this.opts.navbar.titleLink) { + case 'anchor': + if (opener) { + title.setAttribute('href', opener.getAttribute('href')); + } + break; + + case 'parent': + if (parentPanel) { + title.setAttribute('href', '#' + parentPanel.id); + } + break; + } + + navbar.append(title); + + panel.prepend(navbar); + + // Invoke "after" hook. + this.trigger('initNavbar:after', [panel]); + } + + /** + * Initialize a listview. + * @param {HTMLElement} listview Listview to initialize. + */ + initListview(listview: HTMLElement) { + // Invoke "before" hook. + this.trigger('initListview:before', [listview]); + + DOM.reClass(listview, this.conf.classNames.nolistview, 'mm-nolistview'); + + if (!listview.matches('.mm-nolistview')) { + listview.classList.add('mm-listview'); + + DOM.children(listview).forEach(listitem => { + listitem.classList.add('mm-listitem'); + + DOM.reClass( + listitem, + this.conf.classNames.selected, + 'mm-listitem_selected' + ); + + DOM.children(listitem, 'a, span').forEach(item => { + if (!item.matches('.mm-btn')) { + item.classList.add('mm-listitem__text'); + } + }); + }); + } + + // Invoke "after" hook. + this.trigger('initListview:after', [listview]); + } + + /** + * Find and open the correct panel after creating the menu. + */ + _initOpened() { + // Invoke "before" hook. + this.trigger('initOpened:before'); + + /** The selected listitem(s). */ + let listitems = this.node.pnls.querySelectorAll( + '.mm-listitem_selected' + ); + + /** The last selected listitem. */ + let lastitem = null; + + // Deselect the listitems. + listitems.forEach(listitem => { + lastitem = listitem; + listitem.classList.remove('mm-listitem_selected'); + }); + + // Re-select the last listitem. + if (lastitem) { + lastitem.classList.add('mm-listitem_selected'); + } + + /** The current opened panel. */ + let current = lastitem + ? lastitem.closest('.mm-panel') + : DOM.children(this.node.pnls, '.mm-panel')[0]; + + // Open the current opened panel. + this.openPanel(current, false); + + // Invoke "after" hook. + this.trigger('initOpened:after'); + } + + /** + * Initialize anchors in / for the menu. + */ + _initAnchors() { + // Invoke "before" hook. + this.trigger('initAnchors:before'); + + document.addEventListener( + 'click', + evnt => { + /** The clicked element. */ + var target = (evnt.target as HTMLElement).closest( + 'a[href]' + ) as HTMLElement; + if (!target) { + return; + } + + /** Arguments passed to the bound methods. */ + var args: mmClickArguments = { + inMenu: target.closest('.mm-menu') === this.node.menu, + inListview: target.matches('.mm-listitem > a'), + toExternal: + target.matches('[rel="external"]') || + target.matches('[target="_blank"]') + }; + + var onClick: mmOptionsOnclick = { + close: null, + setSelected: null, + preventDefault: + target.getAttribute('href').slice(0, 1) == '#' + }; + + // Find hooked behavior. + for (let c = 0; c < this.clck.length; c++) { + let click = this.clck[c].call(this, target, args); + + if (click) { + if (typeof click == 'boolean') { + evnt.preventDefault(); + return; + } + if (type(click) == 'object') { + onClick = extend(click, onClick); + } + } + } + + // Default behavior for anchors in lists. + if (args.inMenu && args.inListview && !args.toExternal) { + // Set selected item, Default: true + if ( + valueOrFn( + target, + this.opts.onClick.setSelected, + onClick.setSelected + ) + ) { + this.setSelected(target.parentElement); + } + + // Prevent default / don't follow link. Default: false. + if ( + valueOrFn( + target, + this.opts.onClick.preventDefault, + onClick.preventDefault + ) + ) { + evnt.preventDefault(); + } + + // Close menu. Default: false + if ( + valueOrFn( + target, + this.opts.onClick.close, + onClick.close + ) + ) { + if ( + this.opts.offCanvas && + typeof this.close == 'function' + ) { + this.close(); + } + } + } + }, + true + ); + + // Invoke "after" hook. + this.trigger('initAnchors:after'); + } + + /** + * Get the translation for a text. + * @param {string} text Text to translate. + * @return {string} The translated text. + */ + i18n(text: string): string { + return i18n.get(text, this.conf.language); + } +} diff --git a/src/core/oncanvas/translations/de.ts b/src/core/oncanvas/translations/de.ts new file mode 100644 index 0000000..348871e --- /dev/null +++ b/src/core/oncanvas/translations/de.ts @@ -0,0 +1,3 @@ +export default { + 'Menu': 'Menü' +}; \ No newline at end of file diff --git a/src/core/oncanvas/translations/fa.ts b/src/core/oncanvas/translations/fa.ts new file mode 100755 index 0000000..3fb23bb --- /dev/null +++ b/src/core/oncanvas/translations/fa.ts @@ -0,0 +1,3 @@ +export default { + 'Menu': 'منو' +}; diff --git a/src/core/oncanvas/translations/nl.ts b/src/core/oncanvas/translations/nl.ts new file mode 100644 index 0000000..00f1ffc --- /dev/null +++ b/src/core/oncanvas/translations/nl.ts @@ -0,0 +1,3 @@ +export default { + 'Menu': 'Menu' +}; \ No newline at end of file diff --git a/src/core/oncanvas/translations/ru.ts b/src/core/oncanvas/translations/ru.ts new file mode 100644 index 0000000..c2ec41e --- /dev/null +++ b/src/core/oncanvas/translations/ru.ts @@ -0,0 +1,3 @@ +export default { + 'Menu': 'Меню' +}; \ No newline at end of file diff --git a/src/core/oncanvas/translations/translate.ts b/src/core/oncanvas/translations/translate.ts new file mode 100644 index 0000000..a167297 --- /dev/null +++ b/src/core/oncanvas/translations/translate.ts @@ -0,0 +1,13 @@ +import { add } from '../../../_modules/i18n'; + +import nl from './nl'; +import fa from './fa'; +import de from './de'; +import ru from './ru'; + +export default function() { + add(nl, 'nl'); + add(fa, 'fa'); + add(de, 'de'); + add(ru, 'ru'); +} diff --git a/src/core/screenreader/_configs.ts b/src/core/screenreader/_configs.ts new file mode 100644 index 0000000..4cabd1a --- /dev/null +++ b/src/core/screenreader/_configs.ts @@ -0,0 +1,9 @@ +const configs : mmConfigsScreenreader = { + text: { + closeMenu: 'Close menu', + closeSubmenu: 'Close submenu', + openSubmenu: 'Open submenu', + toggleSubmenu: 'Toggle submenu' + } +}; +export default configs; \ No newline at end of file diff --git a/src/core/screenreader/_includes.scss b/src/core/screenreader/_includes.scss new file mode 100644 index 0000000..780865b --- /dev/null +++ b/src/core/screenreader/_includes.scss @@ -0,0 +1 @@ +$mm_include_screenreader: true !default; diff --git a/src/core/screenreader/_options.ts b/src/core/screenreader/_options.ts new file mode 100644 index 0000000..a6bc7e2 --- /dev/null +++ b/src/core/screenreader/_options.ts @@ -0,0 +1,29 @@ +const options : mmOptionsScreenreader = { + aria: true, + text: true +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsScreenreader +) : mmOptionsScreenreader { + + if ( typeof options == 'boolean' ) { + options = { + aria: options, + text: options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; \ No newline at end of file diff --git a/src/core/screenreader/_typings.d.ts b/src/core/screenreader/_typings.d.ts new file mode 100644 index 0000000..92810c8 --- /dev/null +++ b/src/core/screenreader/_typings.d.ts @@ -0,0 +1,16 @@ +// Add-on options interface. +interface mmOptionsScreenreader { + aria ?: boolean + text ?: boolean +} + +// Add-on configs interfaces. +interface mmConfigsScreenreader { + text ?: mmConfigsScreenreaderText +} +interface mmConfigsScreenreaderText { + closeMenu ?: string + closeSubmenu ?: string + openSubmenu ?: string + toggleSubmenu ?: string +} diff --git a/src/core/screenreader/_variables.scss b/src/core/screenreader/_variables.scss new file mode 100644 index 0000000..533c107 --- /dev/null +++ b/src/core/screenreader/_variables.scss @@ -0,0 +1 @@ +$mm_opt_screenreader : true !default; diff --git a/src/core/screenreader/mmenu.screenreader.scss b/src/core/screenreader/mmenu.screenreader.scss new file mode 100644 index 0000000..bc33434 --- /dev/null +++ b/src/core/screenreader/mmenu.screenreader.scss @@ -0,0 +1,19 @@ +@import + '../../mixins', + '../../includes', + '../../variables'; + + +.mm-sronly { + border: 0 !important; + clip: rect(1px, 1px, 1px, 1px) !important; + clip-path: inset(50%) !important; + white-space: nowrap !important; + width: 1px !important; + min-width: 1px !important; + height: 1px !important; + min-height: 1px !important; + padding: 0 !important; + overflow: hidden !important; + position: absolute !important; +} \ No newline at end of file diff --git a/src/core/screenreader/mmenu.screenreader.ts b/src/core/screenreader/mmenu.screenreader.ts new file mode 100644 index 0000000..aa168cc --- /dev/null +++ b/src/core/screenreader/mmenu.screenreader.ts @@ -0,0 +1,252 @@ +import Mmenu from './../oncanvas/mmenu.oncanvas'; +import options from './_options'; +import configs from './_configs'; +import translate from './translations/translate'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import { extend } from '../../_modules/helpers'; + +// Add the translations. +translate(); + +// Add the options and configs. +Mmenu.options.screenReader = options; +Mmenu.configs.screenReader = configs; + +export default function(this: Mmenu) { + // Extend options. + var options = extendShorthandOptions(this.opts.screenReader); + this.opts.screenReader = extend(options, Mmenu.options.screenReader); + + // Extend configs. + var configs = this.conf.screenReader; + + // Add Aria-* attributes + if (options.aria) { + // Add screenreader / aria hooks for add-ons + // In orde to keep this list short, only extend hooks that are actually used by other add-ons. + this.bind('initAddons:after', () => { + this.bind('initMenu:after', function(this: Mmenu) { + this.trigger( + 'initMenu:after:sr-aria', + [].slice.call(arguments) + ); + }); + this.bind('initNavbar:after', function(this: Mmenu) { + this.trigger( + 'initNavbar:after:sr-aria', + [].slice.call(arguments) + ); + }); + this.bind('openPanel:start', function(this: Mmenu) { + this.trigger( + 'openPanel:start:sr-aria', + [].slice.call(arguments) + ); + }); + this.bind('close:start', function(this: Mmenu) { + this.trigger('close:start:sr-aria', [].slice.call(arguments)); + }); + this.bind('close:finish', function(this: Mmenu) { + this.trigger('close:finish:sr-aria', [].slice.call(arguments)); + }); + this.bind('open:start', function(this: Mmenu) { + this.trigger('open:start:sr-aria', [].slice.call(arguments)); + }); + this.bind('initOpened:after', function(this: Mmenu) { + this.trigger( + 'initOpened:after:sr-aria', + [].slice.call(arguments) + ); + }); + }); + + // Update aria-hidden for hidden / visible listitems + this.bind('updateListview', () => { + this.node.pnls + .querySelectorAll('.mm-listitem') + .forEach(listitem => { + Mmenu.sr_aria( + listitem, + 'hidden', + listitem.matches('.mm-hidden') + ); + }); + }); + + // Update aria-hidden for the panels when opening and closing a panel. + this.bind('openPanel:start', (panel: HTMLElement) => { + /** Panels that should be considered "hidden". */ + var hidden: HTMLElement[] = DOM.find(this.node.pnls, '.mm-panel') + .filter(hide => hide !== panel) + .filter(hide => !hide.parentElement.matches('.mm-panel')); + + /** Panels that should be considered "visible". */ + var visible: HTMLElement[] = [panel]; + DOM.find( + panel, + '.mm-listitem_vertical .mm-listitem_opened' + ).forEach(listitem => { + visible.push(...DOM.children(listitem, '.mm-panel')); + }); + + // Set the panels to be considered "hidden" or "visible". + hidden.forEach(panel => { + Mmenu.sr_aria(panel, 'hidden', true); + }); + visible.forEach(panel => { + Mmenu.sr_aria(panel, 'hidden', false); + }); + }); + + this.bind('closePanel', (panel: HTMLElement) => { + Mmenu.sr_aria(panel, 'hidden', true); + }); + + // Add aria-haspopup and aria-owns to prev- and next buttons. + this.bind('initPanel:after', (panel: HTMLElement) => { + DOM.find(panel, '.mm-btn').forEach(button => { + Mmenu.sr_aria(button, 'haspopup', true); + + let href = button.getAttribute('href'); + if (href) { + Mmenu.sr_aria(button, 'owns', href.replace('#', '')); + } + }); + }); + + // Add aria-hidden for navbars in panels. + this.bind('initNavbar:after', (panel: HTMLElement) => { + /** The navbar in the panel. */ + var navbar = DOM.children(panel, '.mm-navbar')[0]; + + /** Whether or not the navbar should be considered "hidden". */ + var hidden = navbar.matches('.mm-hidden'); + + // Set the navbar to be considered "hidden" or "visible". + Mmenu.sr_aria(navbar, 'hidden', hidden); + }); + + // Text + if (options.text) { + // Add aria-hidden to titles in navbars + if (this.opts.navbar.titleLink == 'parent') { + this.bind('initNavbar:after', (panel: HTMLElement) => { + /** The navbar in the panel. */ + var navbar = DOM.children(panel, '.mm-navbar')[0]; + + /** Whether or not the navbar should be considered "hidden". */ + var hidden = navbar.querySelector('.mm-btn_prev') + ? true + : false; + + // Set the navbar-title to be considered "hidden" or "visible". + Mmenu.sr_aria( + DOM.find(navbar, '.mm-navbar__title')[0], + 'hidden', + hidden + ); + }); + } + } + } + + // Add screenreader text + if (options.text) { + // Add screenreader / text hooks for add-ons + // In orde to keep this list short, only extend hooks that are actually used by other add-ons. + this.bind('initAddons:after', () => { + this.bind('setPage:after', function() { + this.trigger('setPage:after:sr-text', [].slice.call(arguments)); + }); + this.bind('initBlocker:after', function() { + this.trigger( + 'initBlocker:after:sr-text', + [].slice.call(arguments) + ); + }); + }); + + // Add text to the prev-buttons. + this.bind('initNavbar:after', (panel: HTMLElement) => { + let navbar = DOM.children(panel, '.mm-navbar')[0]; + if (navbar) { + let button = DOM.children(navbar, '.mm-btn_prev')[0]; + if (button) { + button.innerHTML = Mmenu.sr_text( + this.i18n(configs.text.closeSubmenu) + ); + } + } + }); + + // Add text to the next-buttons. + this.bind('initListview:after', (listview: HTMLElement) => { + let parent: HTMLElement = listview.closest('.mm-panel')['mmParent']; + if (parent) { + let next = DOM.children(parent, '.mm-btn_next')[0]; + if (next) { + let text = this.i18n( + configs.text[ + next.parentElement.matches('.mm-listitem_vertical') + ? 'toggleSubmenu' + : 'openSubmenu' + ] + ); + next.innerHTML += Mmenu.sr_text(text); + } + } + }); + } +} + +// Methods +(function() { + var attr = function( + element: HTMLElement, + attr: string, + value: string | boolean + ) { + element[attr] = value; + if (value) { + element.setAttribute(attr, value.toString()); + } else { + element.removeAttribute(attr); + } + }; + + /** + * Add aria (property and) attribute to a HTML element. + * + * @param {HTMLElement} element The node to add the attribute to. + * @param {string} name The (non-aria-prefixed) attribute name. + * @param {string|boolean} value The attribute value. + */ + Mmenu.sr_aria = function( + element: HTMLElement, + name: string, + value: string | boolean + ) { + attr(element, 'aria-' + name, value); + }; + + /** + * Add role attribute to a HTML element. + * + * @param {HTMLElement} element The node to add the attribute to. + * @param {string|boolean} value The attribute value. + */ + Mmenu.sr_role = function(element: HTMLElement, value: string | boolean) { + attr(element, 'role', value); + }; + + /** + * Wrap a text in a screen-reader-only node. + * + * @param {string} text The text to wrap. + * @return {string} The wrapped text. + */ + Mmenu.sr_text = function(text: string) { + return '' + text + ''; + }; +})(); diff --git a/src/core/screenreader/translations/de.ts b/src/core/screenreader/translations/de.ts new file mode 100644 index 0000000..9011118 --- /dev/null +++ b/src/core/screenreader/translations/de.ts @@ -0,0 +1,6 @@ +export default { + 'Close menu': 'Menü schließen', + 'Close submenu': 'Untermenü schließen', + 'Open submenu': 'Untermenü öffnen', + 'Toggle submenu': 'Untermenü wechseln' +}; diff --git a/src/core/screenreader/translations/fa.ts b/src/core/screenreader/translations/fa.ts new file mode 100755 index 0000000..da07a77 --- /dev/null +++ b/src/core/screenreader/translations/fa.ts @@ -0,0 +1,6 @@ +export default { + 'Close menu': 'بستن منو', + 'Close submenu': 'بستن زیرمنو', + 'Open submenu': 'بازکردن زیرمنو', + 'Toggle submenu': 'سوییچ زیرمنو' +}; diff --git a/src/core/screenreader/translations/nl.ts b/src/core/screenreader/translations/nl.ts new file mode 100644 index 0000000..8afcae7 --- /dev/null +++ b/src/core/screenreader/translations/nl.ts @@ -0,0 +1,6 @@ +export default { + 'Close menu': 'Menu sluiten', + 'Close submenu': 'Submenu sluiten', + 'Open submenu': 'Submenu openen', + 'Toggle submenu': 'Submenu wisselen' +}; diff --git a/src/core/screenreader/translations/ru.ts b/src/core/screenreader/translations/ru.ts new file mode 100644 index 0000000..b3dcd3c --- /dev/null +++ b/src/core/screenreader/translations/ru.ts @@ -0,0 +1,6 @@ +export default { + 'Close menu': 'Закрыть меню', + 'Close submenu': 'Закрыть подменю', + 'Open submenu': 'Открыть подменю', + 'Toggle submenu': 'Переключить подменю' +}; diff --git a/src/core/screenreader/translations/translate.ts b/src/core/screenreader/translations/translate.ts new file mode 100644 index 0000000..a167297 --- /dev/null +++ b/src/core/screenreader/translations/translate.ts @@ -0,0 +1,13 @@ +import { add } from '../../../_modules/i18n'; + +import nl from './nl'; +import fa from './fa'; +import de from './de'; +import ru from './ru'; + +export default function() { + add(nl, 'nl'); + add(fa, 'fa'); + add(de, 'de'); + add(ru, 'ru'); +} diff --git a/src/core/scrollbugfix/_options.ts b/src/core/scrollbugfix/_options.ts new file mode 100644 index 0000000..4a40a7d --- /dev/null +++ b/src/core/scrollbugfix/_options.ts @@ -0,0 +1,27 @@ +const options : mmOptionsScrollbugfix = { + fix: true +}; +export default options; + +/** + * Extend shorthand options. + * + * @param {object} options The options to extend. + * @return {object} The extended options. + */ +export function extendShorthandOptions( + options : mmOptionsScrollbugfix +) : mmOptionsScrollbugfix { + + if ( typeof options == 'boolean' ) { + options = { + fix: options + }; + } + + if ( typeof options != 'object' ) { + options = {}; + } + + return options; +}; \ No newline at end of file diff --git a/src/core/scrollbugfix/_typings.d.ts b/src/core/scrollbugfix/_typings.d.ts new file mode 100644 index 0000000..b0d1b9c --- /dev/null +++ b/src/core/scrollbugfix/_typings.d.ts @@ -0,0 +1,4 @@ +// Add-on options interface. +interface mmOptionsScrollbugfix { + fix ?: boolean +} diff --git a/src/core/scrollbugfix/mmenu.scrollbugfix.ts b/src/core/scrollbugfix/mmenu.scrollbugfix.ts new file mode 100644 index 0000000..9a72b2a --- /dev/null +++ b/src/core/scrollbugfix/mmenu.scrollbugfix.ts @@ -0,0 +1,112 @@ +import Mmenu from './../oncanvas/mmenu.oncanvas'; +import options from './_options'; +import { extendShorthandOptions } from './_options'; +import * as DOM from '../../_modules/dom'; +import * as support from '../../_modules/support'; +import { extend, touchDirection } from '../../_modules/helpers'; + +// Add the options. +Mmenu.options.scrollBugFix = options; + +export default function(this: Mmenu) { + // The scrollBugFix add-on fixes a scrolling bug + // 1) on touch devices + // 2) in an off-canvas menu + // 3) that -when opened- blocks the UI from interaction + if ( + !support.touch || // 1 + !this.opts.offCanvas || // 2 + !this.opts.offCanvas.blockUI // 3 + ) { + return; + } + + // Extend options. + var options = extendShorthandOptions(this.opts.scrollBugFix); + this.opts.scrollBugFix = extend(options, Mmenu.options.scrollBugFix); + + if (!options.fix) { + return; + } + + var touchDir = touchDirection(this.node.menu); + + /** + * Prevent an event from doing its default and stop its propagation. + * @param {ScrollBehavior} evnt The event to stop. + */ + function stop(evnt) { + evnt.preventDefault(); + evnt.stopPropagation(); + } + + // Prevent the page from scrolling when scrolling in the menu. + this.node.menu.addEventListener('scroll', stop, { + // Make sure to tell the browser the event will be prevented. + passive: false + }); + + // Prevent the page from scrolling when dragging in the menu. + this.node.menu.addEventListener( + 'touchmove', + evnt => { + var panel = (evnt.target as HTMLElement).closest( + '.mm-panel' + ) as HTMLElement; + + if (panel) { + // When dragging a non-scrollable panel, + // we can simple preventDefault and stopPropagation. + if (panel.scrollHeight === panel.offsetHeight) { + stop(evnt); + } + + // When dragging a scrollable panel, + // that is fully scrolled up (or down). + // It will not trigger the scroll event when dragging down (or up) (because you can't scroll up (or down)), + // so we need to match the dragging direction with the scroll position before preventDefault and stopPropagation, + // otherwise the panel would not scroll at all in any direction. + else if ( + // When scrolled up and dragging down + (panel.scrollTop == 0 && touchDir.get() == 'down') || + // When scrolled down and dragging up + (panel.scrollHeight == + panel.scrollTop + panel.offsetHeight && + touchDir.get() == 'up') + ) { + stop(evnt); + } + + // When dragging anything other than a panel. + } else { + stop(evnt); + } + }, + { + // Make sure to tell the browser the event can be prevented. + passive: false + } + ); + + // Some small additional improvements + + // Scroll the current opened panel to the top when opening the menu. + this.bind('open:start', () => { + var panel = DOM.children(this.node.pnls, '.mm-panel_opened')[0]; + if (panel) { + panel.scrollTop = 0; + } + }); + + // Fix issue after device rotation change. + window.addEventListener('orientationchange', evnt => { + var panel = DOM.children(this.node.pnls, '.mm-panel_opened')[0]; + if (panel) { + panel.scrollTop = 0; + + // Apparently, changing the overflow-scrolling property triggers some event :) + panel.style['-webkit-overflow-scrolling'] = 'auto'; + panel.style['-webkit-overflow-scrolling'] = 'touch'; + } + }); +} diff --git a/src/extensions/borderstyle/_includes.scss b/src/extensions/borderstyle/_includes.scss new file mode 100644 index 0000000..26424e5 --- /dev/null +++ b/src/extensions/borderstyle/_includes.scss @@ -0,0 +1,3 @@ +$mm_include_borderstyle: true !default; +$mm_include_borderstyle_none: $mm_include_borderstyle !default; +$mm_include_borderstyle_full: $mm_include_borderstyle !default; diff --git a/src/extensions/borderstyle/mmenu.borderstyle.scss b/src/extensions/borderstyle/mmenu.borderstyle.scss new file mode 100644 index 0000000..17424d5 --- /dev/null +++ b/src/extensions/borderstyle/mmenu.borderstyle.scss @@ -0,0 +1,17 @@ +@import '../../mixins', '../../includes', '../../variables'; + +@if ($mm_include_borderstyle_none) { + .mm-menu_border-none { + .mm-listitem:after { + content: none; + } + } +} + +@if ($mm_include_borderstyle_full) { + .mm-menu_border-full { + .mm-listitem:after { + left: 0 !important; + } + } +} diff --git a/src/extensions/effects/_includes.scss b/src/extensions/effects/_includes.scss new file mode 100644 index 0000000..c06c173 --- /dev/null +++ b/src/extensions/effects/_includes.scss @@ -0,0 +1,4 @@ +$mm_include_effects: true !default; +$mm_include_effects_menuslide: $mm_include_effects !default; +$mm_include_effects_panelsnone: $mm_include_effects !default; +$mm_include_effects_panelsslide: $mm_include_effects !default; diff --git a/src/extensions/effects/_mixins.scss b/src/extensions/effects/_mixins.scss new file mode 100644 index 0000000..854d3c1 --- /dev/null +++ b/src/extensions/effects/_mixins.scss @@ -0,0 +1,5 @@ +@mixin mm_effect_listitem_delay( $i ) { + &:nth-child( #{$i} ) { + transition-delay: ( $i * 50ms ); + } +} \ No newline at end of file diff --git a/src/extensions/effects/mmenu.effects.scss b/src/extensions/effects/mmenu.effects.scss new file mode 100644 index 0000000..1279cb5 --- /dev/null +++ b/src/extensions/effects/mmenu.effects.scss @@ -0,0 +1,51 @@ +@import '../../mixins', '../../includes', '../../variables'; + +@if ($mm_include_effects_menuslide) { + // Slide menu + $menu: '.mm-menu_fx-menu-slide'; + #{$menu} { + transition: transform $mm_transitionDuration $mm_transitionFunction; + } + + // Slide menu Left + .mm-wrapper_opened #{$menu} { + transform: translate3d(-$mm_subpanelOffset, 0, 0); + } + + .mm-wrapper_opening #{$menu} { + transform: translate3d(0%, 0, 0); + } + + // Slide menu Right + $menuright: '#{$menu}.mm-menu_position-right'; + .mm-wrapper_opened #{$menuright} { + transform: translate3d($mm_subpanelOffset, 0, 0); + } + + .mm-wrapper_opening #{$menuright} { + transform: translate3d(0%, 0, 0); + } +} + +@if ($mm_include_effects_panelsnone) { + // No effect panels + .mm-menu_fx-panels-none .mm-panel, + .mm-panel_fx-none { + transition-property: none; + + &.mm-panel_opened-parent { + transform: translate3d(0, 0, 0); + } + } +} + +@if ($mm_include_effects_panelsslide) { + // Slide panels + .mm-menu_fx-panels-slide-0 .mm-panel_opened-parent { + transform: translate3d(0, 0, 0); + } + + .mm-menu_fx-panels-slide-100 .mm-panel_opened-parent { + transform: translate3d(-100%, 0, 0); + } +} diff --git a/src/extensions/fullscreen/_includes.scss b/src/extensions/fullscreen/_includes.scss new file mode 100644 index 0000000..16f4477 --- /dev/null +++ b/src/extensions/fullscreen/_includes.scss @@ -0,0 +1 @@ +$mm_include_fullscreen: true !default; diff --git a/src/extensions/fullscreen/_variables.scss b/src/extensions/fullscreen/_variables.scss new file mode 100644 index 0000000..87ec5d2 --- /dev/null +++ b/src/extensions/fullscreen/_variables.scss @@ -0,0 +1,3 @@ +$mm_fullscreen_full: 1 !default; +$mm_fullscreen_min: 140px !default; +$mm_fullscreen_max: 10000px !default; diff --git a/src/extensions/fullscreen/mmenu.fullscreen.scss b/src/extensions/fullscreen/mmenu.fullscreen.scss new file mode 100644 index 0000000..791f547 --- /dev/null +++ b/src/extensions/fullscreen/mmenu.fullscreen.scss @@ -0,0 +1,31 @@ +@import '../../mixins', '../../includes', '../../variables'; + +@if ($mm_include_fullscreen) { + @include mm_offcanvas_size( + '.mm-menu_fullscreen', + $mm_fullscreen_full, + $mm_fullscreen_min, + $mm_fullscreen_max + ); + + @include mm_position_right( + '.mm-menu_fullscreen', + $mm_fullscreen_full, + $mm_fullscreen_min, + $mm_fullscreen_max + ); + + @include mm_position_top( + '.mm-menu_fullscreen', + $mm_fullscreen_full, + $mm_fullscreen_min, + $mm_fullscreen_max + ); + + @include mm_position_bottom( + '.mm-menu_fullscreen', + $mm_fullscreen_full, + $mm_fullscreen_min, + $mm_fullscreen_max + ); +} diff --git a/src/extensions/listview/_includes.scss b/src/extensions/listview/_includes.scss new file mode 100644 index 0000000..f6613b1 --- /dev/null +++ b/src/extensions/listview/_includes.scss @@ -0,0 +1,3 @@ +$mm_include_listview: true !default; +$mm_include_listview_justify: $mm_include_listview !default; +$mm_include_listview_inset: $mm_include_listview !default; diff --git a/src/extensions/listview/mmenu.listview.scss b/src/extensions/listview/mmenu.listview.scss new file mode 100644 index 0000000..f871a50 --- /dev/null +++ b/src/extensions/listview/mmenu.listview.scss @@ -0,0 +1,53 @@ +@import '../../mixins', '../../includes', '../../variables'; + +// Justified listviews +@if ($mm_include_listview_justify) { + .mm-menu_listview-justify .mm-panels > .mm-panel { + display: flex; + flex-direction: column; + + &:after { + content: none; + display: none; + } + + .mm-listview { + flex-grow: 1; + display: flex; + flex-direction: column; + + height: 100%; + margin-top: 0; + margin-bottom: 0; + } + + .mm-listitem { + flex: 1 0 auto; + min-height: $mm_btnSize; /* for Safari :( */ + } + + .mm-listitem__text { + box-sizing: border-box; + flex: 1 0 auto; + display: flex; + align-items: center; + } + } +} + +// Inset lists +@if ($mm_include_listview_inset) { + .mm-listview_inset { + list-style: inside disc; + width: 100%; + padding: 0 + ($mm_padding + $mm_listitemIndent) + ($mm_padding * 1.5) + ($mm_padding + $mm_listitemIndent); + margin: 0; + + .mm-listitem { + padding: ($mm_padding * 0.5) 0; + } + } +} diff --git a/src/extensions/multiline/_includes.scss b/src/extensions/multiline/_includes.scss new file mode 100644 index 0000000..e2db8bb --- /dev/null +++ b/src/extensions/multiline/_includes.scss @@ -0,0 +1 @@ +$mm_include_multiline: true !default; diff --git a/src/extensions/multiline/mmenu.multiline.scss b/src/extensions/multiline/mmenu.multiline.scss new file mode 100644 index 0000000..ddb205d --- /dev/null +++ b/src/extensions/multiline/mmenu.multiline.scss @@ -0,0 +1,8 @@ +@import '../../mixins', '../../includes', '../../variables'; + +.mm-menu_multiline { + .mm-listitem__text { + text-overflow: clip; + white-space: normal; + } +} diff --git a/src/extensions/pagedim/_includes.scss b/src/extensions/pagedim/_includes.scss new file mode 100644 index 0000000..67d59d8 --- /dev/null +++ b/src/extensions/pagedim/_includes.scss @@ -0,0 +1,4 @@ +$mm_include_pagedim: true !default; +$mm_include_pagedim_default: $mm_include_pagedim !default; +$mm_include_pagedim_black: $mm_include_pagedim !default; +$mm_include_pagedim_white: $mm_include_pagedim !default; diff --git a/src/extensions/pagedim/_variables.scss b/src/extensions/pagedim/_variables.scss new file mode 100644 index 0000000..d387f8d --- /dev/null +++ b/src/extensions/pagedim/_variables.scss @@ -0,0 +1,2 @@ +$mm_pagedimOpacity: 0.3 !default; +$mm_pagedimDelay: 0.4s !default; \ No newline at end of file diff --git a/src/extensions/pagedim/mmenu.pagedim.scss b/src/extensions/pagedim/mmenu.pagedim.scss new file mode 100644 index 0000000..95c379e --- /dev/null +++ b/src/extensions/pagedim/mmenu.pagedim.scss @@ -0,0 +1,40 @@ +@import + '../../mixins', + '../../includes', + '../../variables'; + + +@if ( $mm_include_pagedim_default or $mm_include_pagedim_black or $mm_include_pagedim_white ) { + [class*="mm-menu_pagedim"].mm-menu_opened { + ~ .mm-wrapper__blocker { + opacity: 0; + } + } + + .mm-wrapper_opening [class*="mm-menu_pagedim"].mm-menu_opened { + ~ .mm-wrapper__blocker { + opacity: $mm_pagedimOpacity; + transition: opacity $mm_transitionDuration $mm_transitionFunction $mm_pagedimDelay; + } + } + + .mm-menu_opened { + @if ( $mm_include_pagedim_default ) { + &.mm-menu_pagedim ~ .mm-wrapper__blocker { + background: inherit; + } + } + + @if ( $mm_include_pagedim_black ) { + &.mm-menu_pagedim-black ~ .mm-wrapper__blocker { + background: #000; + } + } + + @if ( $mm_include_pagedim_white ) { + &.mm-menu_pagedim-white ~ .mm-wrapper__blocker { + background: #fff; + } + } + } +} \ No newline at end of file diff --git a/src/extensions/popup/_includes.scss b/src/extensions/popup/_includes.scss new file mode 100644 index 0000000..dd8eba2 --- /dev/null +++ b/src/extensions/popup/_includes.scss @@ -0,0 +1 @@ +$mm_include_popup: true !default; diff --git a/src/extensions/popup/_variables.scss b/src/extensions/popup/_variables.scss new file mode 100644 index 0000000..5e82cf2 --- /dev/null +++ b/src/extensions/popup/_variables.scss @@ -0,0 +1 @@ +$mm_popupShadow: 0 2px 10px rgba( #000, 0.3 ) !default; \ No newline at end of file diff --git a/src/extensions/popup/mmenu.popup.scss b/src/extensions/popup/mmenu.popup.scss new file mode 100644 index 0000000..5ce04b6 --- /dev/null +++ b/src/extensions/popup/mmenu.popup.scss @@ -0,0 +1,35 @@ +@import '../../mixins', '../../includes', '../../variables'; + +.mm-menu_popup { + transition: opacity $mm_transitionDuration $mm_transitionFunction; + opacity: 0; + + box-shadow: $mm_popupShadow; + height: percentage($mm_menuHeight); + min-height: $mm_menuMinHeight; + max-height: $mm_menuMaxHeight; + + top: 50%; + left: 50%; + bottom: auto; + right: auto; + z-index: 2; + + transform: translate3d(-50%, -50%, 0); + + &.mm-menu_opened { + ~ .mm-slideout { + transform: none !important; + z-index: 0; + } + + ~ .mm-wrapper__blocker { + transition-delay: 0s !important; + z-index: 1; + } + } + + .mm-wrapper_opening & { + opacity: 1; + } +} diff --git a/src/extensions/positioning/_includes.scss b/src/extensions/positioning/_includes.scss new file mode 100644 index 0000000..c3d27df --- /dev/null +++ b/src/extensions/positioning/_includes.scss @@ -0,0 +1,5 @@ +$mm_include_positioning: true !default; +$mm_include_positioning_right: $mm_include_positioning !default; +$mm_include_positioning_top: $mm_include_positioning !default; +$mm_include_positioning_bottom: $mm_include_positioning !default; +$mm_include_positioning_front: $mm_include_positioning !default; diff --git a/src/extensions/positioning/_mixins.scss b/src/extensions/positioning/_mixins.scss new file mode 100644 index 0000000..1eb0ebe --- /dev/null +++ b/src/extensions/positioning/_mixins.scss @@ -0,0 +1,57 @@ +// Position right +@mixin mm_position_right( + $cls: '', + $width: $mm_menuWidth, + $minWidth: $mm_menuMinWidth, + $maxWidth: $mm_menuMaxWidth +) { + .mm-wrapper_opening { + #{$cls}.mm-menu_position-right.mm-menu_opened ~ .mm-slideout { + transform: translate3d(#{-$width * 100}vw, 0, 0); + } + } + + // adjust for min- and max-width + @media all and (max-width: $minWidth / $width) { + .mm-wrapper_opening { + #{$cls}.mm-menu_position-right.mm-menu_opened ~ .mm-slideout { + transform: translate3d(-$minWidth, 0, 0); + } + } + } + @media all and (min-width: $maxWidth / $width) { + .mm-wrapper_opening { + #{$cls}.mm-menu_position-right.mm-menu_opened ~ .mm-slideout { + transform: translate3d(-$maxWidth, 0, 0); + } + } + } +} + +// Position top +@mixin mm_position_top( + $cls: '', + $height: $mm_menuHeight, + $minHeight: $mm_menuMinHeight, + $maxHeight: $mm_menuMaxHeight +) { + #{$cls}.mm-menu_position-top { + height: #{$height * 100}vh; + min-height: $minHeight; + max-height: $maxHeight; + } +} + +// Position bottom +@mixin mm_position_bottom( + $cls: '', + $height: $mm_menuHeight, + $minHeight: $mm_menuMinHeight, + $maxHeight: $mm_menuMaxHeight +) { + #{$cls}.mm-menu_position-bottom { + height: #{$height * 100}vh; + min-height: $minHeight; + max-height: $maxHeight; + } +} diff --git a/src/extensions/positioning/mmenu.positioning.scss b/src/extensions/positioning/mmenu.positioning.scss new file mode 100644 index 0000000..f355f77 --- /dev/null +++ b/src/extensions/positioning/mmenu.positioning.scss @@ -0,0 +1,92 @@ +@import '../../mixins', '../../includes', '../../variables'; + +@if ($mm_include_positioning_right) { + .mm-menu_position { + &-right { + left: auto; + right: 0; + } + } + @include mm_position_right; +} + +@if ( + $mm_include_positioning_front or + $mm_include_positioning_top or + $mm_include_positioning_bottom +) { + .mm-menu_position { + &-front, + &-top, + &-bottom { + transition: transform $mm_transitionDuration $mm_transitionFunction; + + &.mm-menu_opened { + z-index: 2; + + ~ .mm-slideout { + transform: none !important; + z-index: 0; + } + + ~ .mm-wrapper__blocker { + z-index: 1; + } + } + } + } + + @if ($mm_include_positioning_front) { + .mm-menu_position { + &-front { + transform: translate3d(-100%, 0, 0); + + @if ($mm_include_positioning_right) { + &.mm-menu_position-right { + transform: translate3d(100%, 0, 0); + } + } + } + } + } + + @if ($mm_include_positioning_top or $mm_include_positioning_bottom) { + .mm-menu_position { + &-top, + &-bottom { + width: 100%; + min-width: 100%; + max-width: 100%; + } + } + } + + @if ($mm_include_positioning_top) { + .mm-menu_position { + &-top { + transform: translate3d(0, -100%, 0); + } + } + @include mm_position_top; + } + + @if ($mm_include_positioning_bottom) { + .mm-menu_position { + &-bottom { + transform: translate3d(0, 100%, 0); + top: auto; + } + } + @include mm_position_bottom; + } + + .mm-wrapper_opening { + .mm-menu_position { + &-front, + &-top, + &-bottom { + transform: translate3d(0, 0, 0); + } + } + } +} diff --git a/src/extensions/shadows/_includes.scss b/src/extensions/shadows/_includes.scss new file mode 100644 index 0000000..77e72d3 --- /dev/null +++ b/src/extensions/shadows/_includes.scss @@ -0,0 +1,4 @@ +$mm_include_shadows: true !default; +$mm_include_shadows_page: $mm_include_shadows !default; +$mm_include_shadows_menu: $mm_include_shadows !default; +$mm_include_shadows_panels: $mm_include_shadows !default; diff --git a/src/extensions/shadows/mmenu.shadows.scss b/src/extensions/shadows/mmenu.shadows.scss new file mode 100644 index 0000000..28d7118 --- /dev/null +++ b/src/extensions/shadows/mmenu.shadows.scss @@ -0,0 +1,58 @@ +@import '../../mixins', '../../includes', '../../variables'; + +@if ($mm_include_shadows_page) { + .mm-menu_shadow-page { + &:after { + @if ($mm_IE11Fallbacks) { + box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + } + + content: ''; + display: block; + width: 20px; + height: 120%; + position: absolute; + left: 100%; + top: -10%; + z-index: 100; + clip-path: polygon(-20px 0, 0 0, 0 100%, -20px 100%); + + box-shadow: var(--mm-shadow); + } + + @if ($mm_include_positioning_right) { + &.mm-menu_position-right:after { + left: auto; + right: 100%; + clip-path: polygon(20px 0, 40px 0, 40px 100%, 20px 100%); + } + } + + @if ($mm_include_positioning_front) { + &.mm-menu_position-front:after { + content: none; + display: none; + } + } + } +} + +@if ($mm_include_shadows_menu) { + .mm-menu_shadow-menu { + @if ($mm_IE11Fallbacks) { + box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + } + + box-shadow: var(--mm-shadow); + } +} + +@if ($mm_include_shadows_panels) { + .mm-menu_shadow-panels .mm-panels > .mm-panel { + @if ($mm_IE11Fallbacks) { + box-shadow: 0 0 10px rgba(0, 0, 0, 0.3); + } + + box-shadow: var(--mm-shadow); + } +} diff --git a/src/extensions/themes/_includes.scss b/src/extensions/themes/_includes.scss new file mode 100644 index 0000000..6997f04 --- /dev/null +++ b/src/extensions/themes/_includes.scss @@ -0,0 +1,4 @@ +$mm_include_themes: true !default; +$mm_include_themes_white: $mm_include_themes !default; +$mm_include_themes_dark: $mm_include_themes !default; +$mm_include_themes_black: $mm_include_themes !default; diff --git a/src/extensions/themes/mmenu.themes.scss b/src/extensions/themes/mmenu.themes.scss new file mode 100644 index 0000000..020c405 --- /dev/null +++ b/src/extensions/themes/mmenu.themes.scss @@ -0,0 +1,44 @@ +@import + '../../mixins', + '../../includes', + '../../variables'; + + +@if ( $mm_include_themes_white ) { + .mm-menu_theme-white { + --mm-color-border : rgba( 0,0,0, 0.1 ); + --mm-color-button : rgba( 0,0,0, 0.3 ); + --mm-color-text : rgba( 0,0,0, 0.7 ); + --mm-color-text-dimmed : rgba( 0,0,0, 0.3 ); + --mm-color-background : #fff; + --mm-color-background-highlight : rgba( 0,0,0, 0.06 ); + --mm-color-background-emphasis : rgba( 0,0,0, 0.03 ); + --mm-shadow : 0 0 10px rgba( 0,0,0, 0.2 ); + } +} + +@if ( $mm_include_themes_dark ) { + .mm-menu_theme-dark { + --mm-color-border : rgba( 0,0,0, 0.3 ); + --mm-color-button : rgba( 255,255,255, 0.4 ); + --mm-color-text : rgba( 255,255,255, 0.85 ); + --mm-color-text-dimmed : rgba( 255,255,255, 0.4 ); + --mm-color-background : #333; + --mm-color-background-highlight : rgba( 255,255,255, 0.08 ); + --mm-color-background-emphasis : rgba( 0,0,0, 0.1 ); + --mm-shadow : 0 0 20px rgba( 0,0,0, 0.5 ); + } +} + +@if ( $mm_include_themes_black ) { + .mm-menu_theme-black { + --mm-color-border : rgba( 255,255,255, 0.25 ); + --mm-color-button : rgba( 255,255,255, 0.4 ); + --mm-color-text : rgba( 255,255,255, 0.75 ); + --mm-color-text-dimmed : rgba( 255,255,255, 0.4 ); + --mm-color-background : #000; + --mm-color-background-highlight : rgba( 255,255,255, 0.2 ); + --mm-color-background-emphasis : rgba( 255,255,255, 0.15 ); + --mm-shadow : none + } +} diff --git a/src/mmenu.debugger.js b/src/mmenu.debugger.js new file mode 100644 index 0000000..14df1a0 --- /dev/null +++ b/src/mmenu.debugger.js @@ -0,0 +1,417 @@ +/** + * Debugger for mmenu.js + * Include this file after including the mmenu.js plugin to debug your menu. + */ +(function() { + const _console = Mmenu.console || + console || { + log: function() {}, + warn: function() {}, + error: function() {}, + group: function() {}, + groupEnd: function() {} + }; + + const warnings = []; + const deprecated = (depr, repl, vers) => { + var msg = 'Mmenu: ' + depr + ' is deprecated'; + + if (vers) { + msg += ' as of version ' + vers; + } + if (repl) { + msg += ', use ' + repl + ' instead'; + } + msg += '.'; + + warnings.push(msg); + }; + + if (typeof Mmenu == 'undefined') { + _console.error( + 'Global variable "Mmenu" (needed for the debugger) not found!' + ); + return; + } + + /** Log deprecated warnings. */ + Mmenu.prototype._deprecatedWarnings = function() { + /** + * ---------------------------- + * Version 8.4 > 8.5 + * ---------------------------- + */ + + /* Add-ons */ + + // Navbars "next" content is removed. + if (this.opts.navbars) { + this.opts.navbars.forEach(navbar => { + if (navbar.content.includes('next')) { + deprecated( + 'The "next" content for the "navbars" add-on', + null, + '8.5.0' + ); + } + }); + } + + /* Extensions */ + + // Removed the tileview extension. + ['tileview'].forEach(ext => { + Object.keys(this.opts.extensions).forEach(key => { + if (this.opts.extensions[key].includes(ext)) { + deprecated( + 'The "' + ext + '" extension', + 'custom CSS', + '8.5.0' + ); + } + }); + }); + + /** + * ---------------------------- + * Version 8.3 > 8.4 + * ---------------------------- + */ + + /* Config */ + + // Styling listitems with "spacer" is removed. + if ( + this.conf.classNames.spacer || + this.node.menu.querySelector('.Spacer') + ) { + deprecated( + 'Styling a listitem with "Spacer"', + 'custom CSS', + '8.4.0' + ); + } + + /** + * ---------------------------- + * Version 8.2 > 8.3 + * ---------------------------- + */ + + /* OPTIONS */ + + // The navbar.title option can no longer be a function. + if (typeof this.opts.navbar.title == 'function') { + deprecated( + 'A function for the "navbar.title" option', + 'a custom JS loop', + '8.3.0' + ); + + // Prevent an error. + this.opts.navbar.title = Mmenu.options.navbar.title; + } + + /* ADD-ONS */ + + // New Drag add-on with lesser options. + if (this.opts.drag) { + // Swiping to close panels no longer supported. + if (this.opts.drag.panels) { + deprecated( + 'Swiping to close panels using the "drag" add-on', + null, + '8.3.0' + ); + } + + // "drag.menu" Suboptions now are the "drag" options. + if (this.opts.drag.menu) { + deprecated( + 'The "drag.menu" options for the "drag" add-on', + 'the "drag" option', + '8.3.0' + ); + } + } + + // The dividers.type option is removed. + if (this.opts.dividers) { + if (this.opts.dividers.type == 'light') { + deprecated( + 'The "type" option for the "dividers" add-on', + 'custom CSS', + '8.3.0' + ); + } + } + + /* EXTENSIONS */ + + // Removed panel-scoped extensions. + [ + 'mm-panel-border-none', + 'mm-panel-border-full', + 'mm-panel_listview-justify', + 'mm-panel-slide-0', + 'mm-panel-slide-100' + ].forEach(ext => { + if (this.node.menu.querySelector(ext)) { + deprecated( + 'Using the classname ' + ext + ' on a specific panel.', + 'custom CSS', + '8.3.0' + ); + } + }); + + // Removed (parts of) extensions. + [ + 'border-offset', + 'fx-menu-fade', + 'fx-menu-zoom', + 'fx-panels-slide-up', + 'fx-panels-slide-right', + 'fx-panels-zoom', + 'fx-listitems-drop', + 'fx-listitems-fade', + 'fx-listitems-slide' + ].forEach(ext => { + Object.keys(this.opts.extensions).forEach(key => { + if (this.opts.extensions[key].includes(ext)) { + deprecated( + 'The "' + ext + '" extension', + 'custom CSS', + '8.3.0' + ); + } + }); + }); + + /** + * ---------------------------- + * Version 8.1 > 8.2 + * ---------------------------- + */ + + /* API */ + + // Deprecated API methods. + this.bind('initPanels:deprecated', method => { + deprecated('The "initPanels" API method', '"initPanel"', '8.2.0'); + }); + + /** + * ---------------------------- + * Version 8.0 > 8.1 + * ---------------------------- + */ + + /* CONFIGURATION */ + + // conf.clone is moved to conf.offCanvas.clone. + if (typeof this.conf.clone != 'undefined') { + deprecated( + 'The "clone" configuration option', + '"offCanvas.clone"', + '8.1.0' + ); + + // Try to fix it. + if (typeof this.conf.offCanvas.clone == 'undefined') { + this.conf.offCanvas.clone = this.conf.clone; + } + } + + /** + * ---------------------------- + * Version 7.3 > 8.0 + * ---------------------------- + */ + + /* API */ + + // These methods no longer accept a jQuery object as an argument, + // they now only accept a HTMLElement. + [ + 'setPage', + 'openPanel', + 'closePanel', + 'closeAllPanels', + 'setSelected' + ].forEach(method => { + this.bind(method + ':before', panel => { + if ( + typeof panel != 'undefined' && + typeof jQuery != 'undefined' && + panel instanceof jQuery + ) { + deprecated( + 'Passing a jQuery object as an argument to the "' + + method + + '" API method', + 'a HTMLElement', + '8.0.0' + ); + } + }); + }); + + // These methods no longer accept a jQuery object as an argument, + // they now only accept an array of HTMLElements. + ['initPanels'].forEach(method => { + this.bind(method + ':before', panel => { + if ( + typeof panel != 'undefined' && + typeof jQuery != 'undefined' && + panel instanceof jQuery + ) { + deprecated( + 'Passing a jQuery object as an argument to the "' + + method + + '" API method', + 'a HTMLElement array', + '8.0.0' + ); + } + }); + }); + + /* OPTIONS */ + + // opts.navbars.navbar.height is removed in favor of specifying a different CSS variable (--mm-navbar-size ) for each navbar. + if (this.opts.navbars) { + this.opts.navbars.forEach(navbar => { + if (typeof navbar.height !== 'undefined') { + deprecated( + 'The "height" option in the "navbars" options.', + 'the CSS variable "--mm-navbar-size"', + '8.0.0' + ); + } + }); + } + + // opts.dividers.fixed is removed, all dividers are now sticky by default. + if (this.opts.dividers) { + if ( + typeof this.opts.dividers == 'object' && + typeof this.opts.dividers.fixed !== 'undefined' + ) { + deprecated( + 'The "fixed" option in the "dividers" options.', + null, + '8.0.0' + ); + } + } + + // opts.iconbar.add is renamed to opts.iconbar.use. + if (this.opts.iconbar) { + if ( + typeof this.opts.iconbar == 'object' && + typeof this.opts.iconbar.add !== 'undefined' + ) { + deprecated( + 'The "add" option in the "iconbar" options.', + '"use"', + '8.0.0' + ); + + // Try to fix it. + this.opts.iconbar.use = this.opts.iconbar.add; + } + } + + /* CONFIGURATION */ + + // conf.fixedElements.elemInsertMethod is changed to conf.fixedElements.fixed.insertMethod. + if (typeof this.conf.fixedElements.elemInsertMethod != 'undefined') { + deprecated( + 'The "elemInsertMethod" option in the "fixedElements" configuration', + '"fixed.insertMethod"', + '8.0.0' + ); + + // Try to fix it. + if ( + typeof this.conf.fixedElements.fixed.insertMethod == 'undefined' + ) { + this.conf.fixedElements.fixed.insertMethod = this.conf.fixedElements.elemInsertMethod; + } + } + + // conf.fixedElements.elemInsertSelector is changed to conf.fixedElements.fixed.insertSelector. + if (typeof this.conf.fixedElements.elemInsertMethod != 'undefined') { + deprecated( + 'The "elemInsertSelector" option in the "fixedElements" configuration', + '"fixed.insertSelector"', + '8.0.0' + ); + + // Try to fix it. + if ( + typeof this.conf.fixedElements.fixed.insertSelector == + 'undefined' + ) { + this.conf.fixedElements.fixed.insertSelector = this.conf.fixedElements.elemInsertSelector; + } + } + + /* WRAPPERS */ + + // Removed and renamed framework wrappers + if (this.opts.wrappers) { + this.opts.wrappers.forEach(wrapper => { + switch (wrapper) { + // Bootstrap 3 framework wrapper is removed + case 'bootstrap3': + deprecated('The "bootstrap3" wrapper', null, '8.0.0'); + + // Try to fix it. + let indexbs3 = this.opts.wrappers.indexOf(wrapper); + if (indexbs3 > -1) { + this.opts.wrappers.splice(indexbs3, 1); + } + break; + + // Bootstrap 4 framework wrapper is renamed to "bootstrap" + case 'bootstrap4': + deprecated( + 'The "bootstrap4" wrapper', + '"bootstrap"', + '8.0.0' + ); + + // Try to fix it. + this.opts.wrappers.push('bootstrap'); + + let indexbs4 = this.opts.wrappers.indexOf(wrapper); + if (indexbs4 > -1) { + this.opts.wrappers.splice(indexbs4, 1); + } + break; + + // jQuery Mobile framework wrapper is removed + case 'jqueryMobile': + deprecated('The "jqueryMobile" wrapper', null, '8.0.0'); + + // Try to fix it. + let indexjqm = this.opts.wrappers.indexOf(wrapper); + if (indexjqm > -1) { + this.opts.wrappers.splice(indexjqm, 1); + } + break; + } + }); + } + + if (warnings.length) { + _console.group('Mmenu deprecated warnings.'); + warnings.forEach(msg => { + _console.warn(msg); + }); + _console.groupEnd(); + } + }; +})(); diff --git a/src/mmenu.js b/src/mmenu.js new file mode 100644 index 0000000..39e8e7f --- /dev/null +++ b/src/mmenu.js @@ -0,0 +1,117 @@ +/*! + * mmenu.js + * mmenujs.com + * + * Copyright (c) Fred Heusschen + * frebsite.nl + * + * License: CC-BY-NC-4.0 + * http://creativecommons.org/licenses/by-nc/4.0/ + */ + +// Core +import Mmenu from '../dist/core/oncanvas/mmenu.oncanvas'; + +// Core add-ons +import offcanvas from '../dist/core/offcanvas/mmenu.offcanvas'; +import screenReader from '../dist/core/screenreader/mmenu.screenreader'; +import scrollBugFix from '../dist/core/scrollbugfix/mmenu.scrollbugfix'; + +// Add-ons +import autoHeight from '../dist/addons/autoheight/mmenu.autoheight'; +import backButton from '../dist/addons/backbutton/mmenu.backbutton'; +import columns from '../dist/addons/columns/mmenu.columns'; +import counters from '../dist/addons/counters/mmenu.counters'; +import dividers from '../dist/addons/dividers/mmenu.dividers'; +import drag from '../dist/addons/drag/mmenu.drag'; +import dropdown from '../dist/addons/dropdown/mmenu.dropdown'; +import fixedElements from '../dist/addons/fixedelements/mmenu.fixedelements'; +import iconbar from '../dist/addons/iconbar/mmenu.iconbar'; +import iconPanels from '../dist/addons/iconpanels/mmenu.iconpanels'; +import keyboardNavigation from '../dist/addons/keyboardnavigation/mmenu.keyboardnavigation'; +import lazySubmenus from '../dist/addons/lazysubmenus/mmenu.lazysubmenus'; +import navbars from '../dist/addons/navbars/mmenu.navbars'; +import pageScroll from '../dist/addons/pagescroll/mmenu.pagescroll'; +import searchfield from '../dist/addons/searchfield/mmenu.searchfield'; +import sectionIndexer from '../dist/addons/sectionindexer/mmenu.sectionindexer'; +import setSelected from '../dist/addons/setselected/mmenu.setselected'; +import sidebar from '../dist/addons/sidebar/mmenu.sidebar'; +import toggles from '../dist/addons/toggles/mmenu.toggles'; + +// Wrappers +import angular from '../dist/wrappers/angular/mmenu.angular'; +import bootstrap from '../dist/wrappers/bootstrap/mmenu.bootstrap'; +import olark from '../dist/wrappers/olark/mmenu.olark'; +import turbolinks from '../dist/wrappers/turbolinks/mmenu.turbolinks'; +import wordpress from '../dist/wrappers/wordpress/mmenu.wordpress'; + +Mmenu.addons = { + // Core add-ons + offcanvas, + screenReader, + scrollBugFix, + + // Add-ons + autoHeight, + backButton, + columns, + counters, + dividers, + drag, + dropdown, + fixedElements, + iconbar, + iconPanels, + keyboardNavigation, + lazySubmenus, + navbars, + pageScroll, + searchfield, + sectionIndexer, + setSelected, + sidebar, + toggles +}; + +// Wrappers +Mmenu.wrappers = { + angular, + bootstrap, + olark, + turbolinks, + wordpress +}; + +// Export module +export default Mmenu; + +// Global namespace +if (window) { + window.Mmenu = Mmenu; +} + +// jQuery plugin +(function($) { + if ($) { + $.fn.mmenu = function(options, configs) { + var $result = $(); + + this.each(function(e, element) { + // Don't proceed if the element already is a mmenu. + if (element.mmApi) { + return; + } + + var menu = new Mmenu(element, options, configs), + $menu = $(menu.node.menu); + + // Store the API for backward compat. + $menu.data('mmenu', menu.API); + + $result = $result.add($menu); + }); + + return $result; + }; + } +})(window.jQuery || window.Zepto || null); diff --git a/src/mmenu.scss b/src/mmenu.scss new file mode 100644 index 0000000..8741c54 --- /dev/null +++ b/src/mmenu.scss @@ -0,0 +1,63 @@ +/*! + * mmenu.js + * mmenujs.com + * + * Copyright (c) Fred Heusschen + * frebsite.nl + * + * License: CC-BY-NC-4.0 + * http://creativecommons.org/licenses/by-nc/4.0/ + */ + +// There's a bug in the CSS polyfill that'll override the :root vars with the .mm-menu_them-* vars +// Therefor we'll import the themes file first. +@import 'extensions/themes/mmenu.themes'; + +// Core +@import 'core/oncanvas/mmenu.oncanvas'; + +// Core add-ons +@import 'core/offcanvas/mmenu.offcanvas'; +@import 'core/screenreader/mmenu.screenreader'; +//@import 'core/scrollbugfix/mmenu.scrollbugfix'; + +// Add-ons +@import 'addons/autoheight/mmenu.autoheight'; +//@import 'addons/backbutton/mmenu.backbutton'; +@import 'addons/columns/mmenu.columns'; +@import 'addons/counters/mmenu.counters'; +@import 'addons/dividers/mmenu.dividers'; +@import 'addons/drag/mmenu.drag'; +@import 'addons/dropdown/mmenu.dropdown'; +//@import 'addons/fixedelements/mmenu.fixedelements'; +@import 'addons/iconbar/mmenu.iconbar'; +@import 'addons/iconpanels/mmenu.iconpanels'; +@import 'addons/keyboardnavigation/mmenu.keyboardnavigation'; +//@import 'addons/lazysubmenus/mmenu.lazysubmenus'; +@import 'addons/navbars/mmenu.navbars'; +//@import 'addons/pagescroll/mmenu.pagescroll'; +@import 'addons/searchfield/mmenu.searchfield'; +@import 'addons/sectionindexer/mmenu.sectionindexer'; +@import 'addons/setselected/mmenu.setselected'; +@import 'addons/sidebar/mmenu.sidebar'; +@import 'addons/toggles/mmenu.toggles'; + +// Extensions +@import 'extensions/borderstyle/mmenu.borderstyle'; +@import 'extensions/effects/mmenu.effects'; +@import 'extensions/fullscreen/mmenu.fullscreen'; +@import 'extensions/listview/mmenu.listview'; +@import 'extensions/multiline/mmenu.multiline'; +@import 'extensions/pagedim/mmenu.pagedim'; +@import 'extensions/popup/mmenu.popup'; +@import 'extensions/positioning/mmenu.positioning'; +@import 'extensions/shadows/mmenu.shadows'; +@import 'extensions/themes/mmenu.themes'; + +// Wrappers +//@import 'wrappers/angular/mmenu.angular'; +@import 'wrappers/bootstrap/mmenu.bootstrap'; +//@import 'wrappers/magento/mmenu.magento'; +//@import 'wrappers/olark/mmenu.olark'; +//@import 'wrappers/turbolinks/mmenu.turbolinks'; +//@import 'wrappers/wordpress/mmenu.wordpress'; diff --git a/src/wrappers/angular/mmenu.angular.ts b/src/wrappers/angular/mmenu.angular.ts new file mode 100644 index 0000000..43471df --- /dev/null +++ b/src/wrappers/angular/mmenu.angular.ts @@ -0,0 +1,11 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; + +export default function( + this : Mmenu +) { + this.opts.onClick = { + close : true, + preventDefault : false, + setSelected : true + }; +}; \ No newline at end of file diff --git a/src/wrappers/bootstrap/mmenu.bootstrap.scss b/src/wrappers/bootstrap/mmenu.bootstrap.scss new file mode 100644 index 0000000..dcf0aa8 --- /dev/null +++ b/src/wrappers/bootstrap/mmenu.bootstrap.scss @@ -0,0 +1,3 @@ +body.modal-open .mm-slideout { + z-index: unset; +} \ No newline at end of file diff --git a/src/wrappers/bootstrap/mmenu.bootstrap.ts b/src/wrappers/bootstrap/mmenu.bootstrap.ts new file mode 100644 index 0000000..73d4ab3 --- /dev/null +++ b/src/wrappers/bootstrap/mmenu.bootstrap.ts @@ -0,0 +1,135 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; +import * as DOM from '../../_modules/dom'; + +export default function(this: Mmenu) { + // Create the menu + if (this.node.menu.matches('.navbar-collapse')) { + // No need for cloning the menu... + if (this.conf.offCanvas) { + this.conf.offCanvas.clone = false; + } + + // ... We'll create a new menu + var nav = DOM.create('nav'), + panel = DOM.create('div'); + + nav.append(panel); + + DOM.children(this.node.menu).forEach(child => { + switch (true) { + case child.matches('.navbar-nav'): + panel.append(cloneNav(child)); + break; + + case child.matches('.dropdown-menu'): + panel.append(cloneDropdown(child)); + break; + + case child.matches('.form-inline'): + this.conf.searchfield.form = { + action: child.getAttribute('action') || null, + method: child.getAttribute('method') || null + }; + this.conf.searchfield.input = { + name: + child.querySelector('input').getAttribute('name') || + null + }; + this.conf.searchfield.clear = false; + this.conf.searchfield.submit = true; + break; + + default: + panel.append(child.cloneNode(true)); + break; + } + }); + + // Set the menu + this.bind('initMenu:before', () => { + document.body.prepend(nav); + this.node.menu = nav; + }); + + // Hijack the toggler. + let parent = this.node.menu.parentElement; + if (parent) { + let toggler: HTMLElement = parent.querySelector('.navbar-toggler'); + + if (toggler) { + toggler.removeAttribute('data-target'); + // delete toggler.dataset.target; // IE10 has no dataset :( + toggler.removeAttribute('aria-controls'); + + // Remove all bound events. + toggler.outerHTML = toggler.outerHTML; + toggler = parent.querySelector('.navbar-toggler'); + + // Open the menu on-click. + toggler.addEventListener('click', evnt => { + evnt.preventDefault(); + evnt.stopImmediatePropagation(); + this[this.vars.opened ? 'close' : 'open'](); + }); + } + } + } + + function cloneLink(anchor: HTMLElement) { + var link = DOM.create(anchor.matches('a') ? 'a' : 'span'); + + // Copy attributes + var attr = ['href', 'title', 'target']; + for (var a = 0; a < attr.length; a++) { + if (typeof anchor.getAttribute(attr[a]) != 'undefined') { + link.setAttribute(attr[a], anchor.getAttribute(attr[a])); + } + } + + // Copy contents + link.innerHTML = anchor.innerHTML; + + // Remove Screen reader text. + DOM.find(link, '.sr-only').forEach(sro => { + sro.remove(); + }); + + return link; + } + function cloneDropdown(dropdown: HTMLElement) { + var list = DOM.create('ul'); + DOM.children(dropdown).forEach(anchor => { + var item = DOM.create('li'); + + if (anchor.matches('.dropdown-divider')) { + item.classList.add('Divider'); + } else if (anchor.matches('.dropdown-item')) { + item.append(cloneLink(anchor)); + } + list.append(item); + }); + return list; + } + function cloneNav(nav: HTMLElement) { + var list = DOM.create('ul'); + + DOM.find(nav, '.nav-item').forEach(anchor => { + var item = DOM.create('li'); + + if (anchor.matches('.active')) { + item.classList.add('Selected'); + } + if (!anchor.matches('.nav-link')) { + let dropdown = DOM.children(anchor, '.dropdown-menu')[0]; + if (dropdown) { + item.append(cloneDropdown(dropdown)); + } + anchor = DOM.children(anchor, '.nav-link')[0]; + } + item.prepend(cloneLink(anchor)); + + list.append(item); + }); + return list; + } +} diff --git a/src/wrappers/magento/mmenu.magento.ts b/src/wrappers/magento/mmenu.magento.ts new file mode 100644 index 0000000..3cd324f --- /dev/null +++ b/src/wrappers/magento/mmenu.magento.ts @@ -0,0 +1,7 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; + +export default function( + this : Mmenu +) { + this.conf.classNames.selected = 'active'; +}; diff --git a/src/wrappers/olark/mmenu.olark.ts b/src/wrappers/olark/mmenu.olark.ts new file mode 100644 index 0000000..7b70c02 --- /dev/null +++ b/src/wrappers/olark/mmenu.olark.ts @@ -0,0 +1,7 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; + +export default function( + this : Mmenu +) { + this.conf.offCanvas.page.noSelector.push( '#olark' ); +}; diff --git a/src/wrappers/turbolinks/mmenu.turbolinks.ts b/src/wrappers/turbolinks/mmenu.turbolinks.ts new file mode 100644 index 0000000..5be2d8c --- /dev/null +++ b/src/wrappers/turbolinks/mmenu.turbolinks.ts @@ -0,0 +1,20 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; + +export default function(this: Mmenu) { + let classnames; + + document.addEventListener('turbolinks:before-visit', evnt => { + classnames = document + .querySelector('.mm-wrapper') + .className.split(' ') + .filter(name => /mm-/.test(name)); + }); + + document.addEventListener('turbolinks:load', evnt => { + if (typeof classnames === 'undefined') { + return; + } + + document.querySelector('.mm-wrapper').className = classnames; + }); +} diff --git a/src/wrappers/wordpress/mmenu.wordpress.ts b/src/wrappers/wordpress/mmenu.wordpress.ts new file mode 100644 index 0000000..d65eaf0 --- /dev/null +++ b/src/wrappers/wordpress/mmenu.wordpress.ts @@ -0,0 +1,11 @@ +import Mmenu from '../../core/oncanvas/mmenu.oncanvas'; + +export default function(this: Mmenu) { + this.conf.classNames.selected = 'current-menu-item'; + + var wpadminbar = document.getElementById('wpadminbar'); + if (wpadminbar) { + wpadminbar.style.position = 'fixed'; + wpadminbar.classList.add('mm-slideout'); + } +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..29a3dae --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,8 @@ +{ + "include": [ + "src/**/*" + ], + "compilerOptions": { + "target": "es5" + } +}