Initial commit
This commit is contained in:
commit
b82db0e393
47
CONTRIBUTING.md
Normal file
47
CONTRIBUTING.md
Normal file
@ -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.
|
||||
|
||||
|
||||
<a name="bugs"></a>
|
||||
## 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.
|
||||
|
||||
|
||||
<a name="features"></a>
|
||||
## 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.
|
||||
2
LICENSE.txt
Normal file
2
LICENSE.txt
Normal file
@ -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.
|
||||
31
README.md
Normal file
31
README.md
Normal file
@ -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.<br />
|
||||
Working on a WordPress site? Check out [the mmenu WordPress plugin](https://mmenujs.com/wordpress-plugin).
|
||||
|
||||
<img src="https://mmenujs.com/img/preview-mmenu.png" alt="mmenu.js" width="100%" />
|
||||
|
||||
### Licence
|
||||
The mmenu javascript plugin is licensed under the [CC-BY-NC-4.0 license](http://creativecommons.org/licenses/by-nc/4.0/).<br />
|
||||
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/).<br />
|
||||
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).<br />
|
||||
[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.</p>
|
||||
|
||||
### 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.<br />
|
||||
Run `gulp watch` in the command-line to put a watch on the files and run all scripts immediately after saving your changes.
|
||||
27
composer.json
Normal file
27
composer.json
Normal file
@ -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"
|
||||
]
|
||||
}
|
||||
162
demo/advanced.html
Normal file
162
demo/advanced.html
Normal file
@ -0,0 +1,162 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="author" content="www.frebsite.nl" />
|
||||
<meta name="viewport" content="width=device-width minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" />
|
||||
|
||||
<title>mmenu.js demo</title>
|
||||
|
||||
<link rel="stylesheet" href="http://maxcdn.bootstrapcdn.com/font-awesome/4.7.0/css/font-awesome.min.css" />
|
||||
<link rel="stylesheet" href="css/demo.css" />
|
||||
<link rel="stylesheet" href="../dist/mmenu.css" />
|
||||
|
||||
<style>
|
||||
:root {
|
||||
--mm-sidebar-expanded-size: 300px;
|
||||
}
|
||||
.mm-menu {
|
||||
--mm-listitem-size: 50px;
|
||||
--mm-navbar-size: 50px;
|
||||
}
|
||||
|
||||
@media (min-width: 992px) {
|
||||
.header a {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
|
||||
.mm-navbar_tabs span {
|
||||
display: inline-block;
|
||||
margin-left: 8px;
|
||||
}
|
||||
@media (max-width: 450px) {
|
||||
.mm-navbar_tabs span {
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div class="header">
|
||||
<a href="#menu"><span></span></a>
|
||||
Demo
|
||||
</div>
|
||||
<div class="content">
|
||||
<p><strong>This is an advanced demo.</strong><br />
|
||||
Click the menu icon to open the menu.</p>
|
||||
</div>
|
||||
<nav id="menu">
|
||||
<div id="panel-menu">
|
||||
<ul>
|
||||
<li><a href="#/">Home</a></li>
|
||||
<li><span>About us</span>
|
||||
<ul>
|
||||
<li><a href="#/">History</a></li>
|
||||
<li><span>The team</span>
|
||||
<ul>
|
||||
<li><a href="#/">Management</a></li>
|
||||
<li><a href="#/">Sales</a></li>
|
||||
<li><a href="#/">Development</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#/">Our address</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#/">Contact</a></li>
|
||||
|
||||
<li class="Divider">Other demos</li>
|
||||
<li><a href="default.html">Default demo</a></li>
|
||||
<li><a href="onepage.html">One page demo</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="panel-account">
|
||||
<ul>
|
||||
<li><a href="#/">My profile</a></li>
|
||||
<li><a href="#/">Privacy settings</a></li>
|
||||
<li><a href="#/">Activity</a></li>
|
||||
<li><a href="#/">Sign out</a></li>
|
||||
</ul>
|
||||
</div>
|
||||
|
||||
<div id="panel-cart">
|
||||
<p style="text-align: center; padding-top: 30px;">Your shoppingcart is empty.<br />
|
||||
<a href="#/">Continue shopping.</a></p>
|
||||
</div>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- mmenu scripts -->
|
||||
<script src="../dist/mmenu.polyfills.js"></script>
|
||||
<script src="../dist/mmenu.js"></script>
|
||||
<script>
|
||||
new Mmenu(
|
||||
document.querySelector('#menu'),
|
||||
{
|
||||
extensions : [ 'theme-dark', 'shadow-page' ],
|
||||
setSelected : true,
|
||||
counters : true,
|
||||
searchfield : {
|
||||
placeholder : 'Search menu items'
|
||||
},
|
||||
iconbar : {
|
||||
use : '(min-width: 450px)',
|
||||
top : [
|
||||
'<a href="#/"><span class="fa fa-home"></span></a>'
|
||||
],
|
||||
bottom : [
|
||||
'<a href="#/"><span class="fa fa-twitter"></span></a>',
|
||||
'<a href="#/"><span class="fa fa-facebook"></span></a>',
|
||||
'<a href="#/"><span class="fa fa-youtube"></span></a>'
|
||||
]
|
||||
},
|
||||
sidebar : {
|
||||
collapsed : {
|
||||
use : '(min-width: 450px)',
|
||||
hideNavbar : false
|
||||
},
|
||||
expanded : {
|
||||
use : '(min-width: 992px)'
|
||||
}
|
||||
},
|
||||
navbars : [
|
||||
{
|
||||
content : [ 'searchfield' ]
|
||||
}, {
|
||||
type : 'tabs',
|
||||
content : [
|
||||
'<a href="#panel-menu"><i class="fa fa-bars"></i> <span>Menu</span></a>',
|
||||
'<a href="#panel-account"><i class="fa fa-user"></i> <span>Account</span></a>',
|
||||
'<a href="#panel-cart"><i class="fa fa-shopping-cart"></i> <span>Cart</span></a>'
|
||||
]
|
||||
}, {
|
||||
content : [ 'prev', 'breadcrumbs', 'close' ]
|
||||
}, {
|
||||
position : 'bottom',
|
||||
content : [ '<a href="http://mmenu.frebsite.nl/wordpress-plugin" target="_blank">WordPress plugin</a>' ]
|
||||
}
|
||||
]
|
||||
}, {
|
||||
searchfield : {
|
||||
clear : true
|
||||
},
|
||||
navbars : {
|
||||
breadcrumbs : {
|
||||
removeFirst : true
|
||||
}
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
document.addEventListener( 'click', function( evnt ) {
|
||||
var anchor = evnt.target.closest( 'a[href^="#/"]' );
|
||||
if ( anchor ) {
|
||||
alert('Thank you for clicking, but that\'s a demo link.');
|
||||
evnt.preventDefault();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
92
demo/css/demo.css
Normal file
92
demo/css/demo.css
Normal file
@ -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;
|
||||
}
|
||||
75
demo/css/site.css
Normal file
75
demo/css/site.css
Normal file
@ -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%);
|
||||
}
|
||||
64
demo/default.html
Normal file
64
demo/default.html
Normal file
@ -0,0 +1,64 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="author" content="www.frebsite.nl" />
|
||||
<meta name="viewport" content="width=device-width minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" />
|
||||
|
||||
<title>mmenu.js demo</title>
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="css/demo.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../dist/mmenu.css" />
|
||||
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div class="header">
|
||||
<a href="#menu"><span></span></a>
|
||||
Demo
|
||||
</div>
|
||||
<div class="content">
|
||||
<p><strong>This is a demo.</strong><br />
|
||||
Click the menu icon to open the menu.</p>
|
||||
</div>
|
||||
<nav id="menu">
|
||||
<ul>
|
||||
<li><a href="#">Home</a></li>
|
||||
<li><span>About us</span>
|
||||
<ul>
|
||||
<li><a href="#about/history">History</a></li>
|
||||
<li><span>The team</span>
|
||||
<ul>
|
||||
<li><a href="#about/team/management">Management</a></li>
|
||||
<li><a href="#about/team/sales">Sales</a></li>
|
||||
<li><a href="#about/team/development">Development</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#about/address">Our address</a></li>
|
||||
</ul>
|
||||
</li>
|
||||
<li><a href="#contact">Contact</a></li>
|
||||
|
||||
<li class="Divider">Other demos</li>
|
||||
<li><a href="advanced.html">Advanced demo</a></li>
|
||||
<li><a href="onepage.html">One page demo</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- mmenu scripts -->
|
||||
<script src="../dist/mmenu.polyfills.js"></script>
|
||||
<script src="../dist/mmenu.js"></script>
|
||||
<script>
|
||||
new Mmenu( document.querySelector( '#menu' ));
|
||||
|
||||
document.addEventListener( 'click', function( evnt ) {
|
||||
var anchor = evnt.target.closest( 'a[href^="#/"]' );
|
||||
if ( anchor ) {
|
||||
alert('Thank you for clicking, but that\'s a demo link.');
|
||||
evnt.preventDefault();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
BIN
demo/img/iphonex-example-blue.png
Normal file
BIN
demo/img/iphonex-example-blue.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 21 KiB |
BIN
demo/img/iphonex-example-camera.png
Normal file
BIN
demo/img/iphonex-example-camera.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.2 KiB |
128
demo/onepage.html
Normal file
128
demo/onepage.html
Normal file
@ -0,0 +1,128 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="author" content="www.frebsite.nl" />
|
||||
<meta name="viewport" content="width=device-width minimum-scale=1.0 maximum-scale=1.0 user-scalable=no" />
|
||||
|
||||
<title>mmenu.js demo</title>
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="css/demo.css" />
|
||||
<link type="text/css" rel="stylesheet" href="../dist/mmenu.css" />
|
||||
|
||||
<!-- for the one page layout -->
|
||||
<style type="text/css">
|
||||
section
|
||||
{
|
||||
border-top: 1px solid #ccc;
|
||||
padding: 150px 0 200px;
|
||||
}
|
||||
section:first-child
|
||||
{
|
||||
border-top: none;
|
||||
padding-top: 0;
|
||||
}
|
||||
</style>
|
||||
|
||||
<!-- for the fixed header -->
|
||||
<style type="text/css">
|
||||
.header,
|
||||
.footer
|
||||
{
|
||||
position: fixed;
|
||||
left: 0;
|
||||
right: 0;
|
||||
}
|
||||
.header
|
||||
{
|
||||
top: 0;
|
||||
}
|
||||
.footer
|
||||
{
|
||||
bottom: 0;
|
||||
}
|
||||
@media (min-width: 800px) {
|
||||
.header a
|
||||
{
|
||||
display: none;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<div id="page">
|
||||
<div class="header Fixed">
|
||||
<a href="#menu"><span></span></a>
|
||||
Demo
|
||||
</div>
|
||||
<div class="content" id="content">
|
||||
<section id="intro">
|
||||
<p><strong>This is a demo</strong><br />
|
||||
Click the menu icon to open the menu.</p>
|
||||
<p>Some of the links in the menu link to a section on this page.</p>
|
||||
</section>
|
||||
<section id="widescreen">
|
||||
<p><strong>Widescreen extension</strong><br />
|
||||
On wider screens, the menu will always be opened.</p>
|
||||
<p><a href="#menu">Open the menu.</a></p>
|
||||
</section>
|
||||
<section id="drag">
|
||||
<p><strong>Drag add-on</strong><br />
|
||||
You can also drag the page to the right to open the menu.</p>
|
||||
<p><a href="#menu">Open the menu.</a></p>
|
||||
</section>
|
||||
<section id="fixed">
|
||||
<p><strong>Fixed elements</strong><br />
|
||||
Notice how the fixed header and footer slide out along with the page.</p>
|
||||
<p><a href="#menu">Open the menu.</a></p>
|
||||
</section>
|
||||
</div>
|
||||
<div class="footer Fixed">
|
||||
Fixed footer :-)
|
||||
</div>
|
||||
<nav id="menu">
|
||||
<ul>
|
||||
<li><a href="#content">Introduction</a></li>
|
||||
<li><a href="#widescreen">Widescreen extension</a></li>
|
||||
<li><a href="#drag">Drag add-on</a></li>
|
||||
<li><a href="#fixed">Fixed elements</a></li>
|
||||
|
||||
<li class="Divider">Other demos</li>
|
||||
<li><a href="default.html">Default demo</a></li>
|
||||
<li><a href="advanced.html">Advanced demo</a></li>
|
||||
</ul>
|
||||
</nav>
|
||||
</div>
|
||||
|
||||
<!-- Hammer.js for dragging -->
|
||||
<script type="text/javascript" src="http://cdn.jsdelivr.net/hammerjs/2.0.8/hammer.min.js"></script>
|
||||
|
||||
<!-- mmenu scripts -->
|
||||
<script src="../dist/mmenu.polyfills.js"></script>
|
||||
<script src="../dist/mmenu.js"></script>
|
||||
|
||||
<script>
|
||||
new Mmenu(
|
||||
document.querySelector( '#menu' ),
|
||||
{
|
||||
drag : true,
|
||||
pageScroll : {
|
||||
scroll : true,
|
||||
update : true
|
||||
},
|
||||
sidebar : {
|
||||
expanded : 800
|
||||
}
|
||||
}
|
||||
);
|
||||
|
||||
document.addEventListener( 'click', function( evnt ) {
|
||||
var anchor = evnt.target.closest( 'a[href^="#/"]' );
|
||||
if ( anchor ) {
|
||||
alert('Thank you for clicking, but that\'s a demo link.');
|
||||
evnt.preventDefault();
|
||||
}
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
132
dist/_modules/dom.js
vendored
Normal file
132
dist/_modules/dom.js
vendored
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
12
dist/_modules/dragevents/_defaults.js
vendored
Normal file
12
dist/_modules/dragevents/_defaults.js
vendored
Normal file
@ -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
|
||||
};
|
||||
15
dist/_modules/dragevents/_helpers.js
vendored
Normal file
15
dist/_modules/dragevents/_helpers.js
vendored
Normal file
@ -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;
|
||||
};
|
||||
11
dist/_modules/dragevents/_settings.js
vendored
Normal file
11
dist/_modules/dragevents/_settings.js
vendored
Normal file
@ -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
|
||||
};
|
||||
4
dist/_modules/dragevents/_support.js
vendored
Normal file
4
dist/_modules/dragevents/_support.js
vendored
Normal file
@ -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;
|
||||
208
dist/_modules/dragevents/index.js
vendored
Normal file
208
dist/_modules/dragevents/index.js
vendored
Normal file
@ -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;
|
||||
50
dist/_modules/eventlisteners.js
vendored
Normal file
50
dist/_modules/eventlisteners.js
vendored
Normal file
@ -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 || {});
|
||||
});
|
||||
}
|
||||
125
dist/_modules/helpers.js
vendored
Normal file
125
dist/_modules/helpers.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
34
dist/_modules/i18n.js
vendored
Normal file
34
dist/_modules/i18n.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
43
dist/_modules/matchmedia.js
vendored
Normal file
43
dist/_modules/matchmedia.js
vendored
Normal file
@ -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]();
|
||||
}
|
||||
}
|
||||
4
dist/_modules/support.js
vendored
Normal file
4
dist/_modules/support.js
vendored
Normal file
@ -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;
|
||||
1
dist/_version.js
vendored
Normal file
1
dist/_version.js
vendored
Normal file
@ -0,0 +1 @@
|
||||
export default '8.5.3';
|
||||
27
dist/addons/autoheight/_options.js
vendored
Normal file
27
dist/addons/autoheight/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/addons/autoheight/mmenu.autoheight.css
vendored
Normal file
1
dist/addons/autoheight/mmenu.autoheight.css
vendored
Normal file
@ -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}
|
||||
84
dist/addons/autoheight/mmenu.autoheight.js
vendored
Normal file
84
dist/addons/autoheight/mmenu.autoheight.js
vendored
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
23
dist/addons/backbutton/_options.js
vendored
Normal file
23
dist/addons/backbutton/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
58
dist/addons/backbutton/mmenu.backbutton.js
vendored
Normal file
58
dist/addons/backbutton/mmenu.backbutton.js
vendored
Normal file
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
38
dist/addons/columns/_options.js
vendored
Normal file
38
dist/addons/columns/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/addons/columns/mmenu.columns.css
vendored
Normal file
1
dist/addons/columns/mmenu.columns.css
vendored
Normal file
File diff suppressed because one or more lines are too long
103
dist/addons/columns/mmenu.columns.js
vendored
Normal file
103
dist/addons/columns/mmenu.columns.js
vendored
Normal file
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
28
dist/addons/counters/_options.js
vendored
Normal file
28
dist/addons/counters/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
1
dist/addons/counters/mmenu.counters.css
vendored
Normal file
1
dist/addons/counters/mmenu.counters.css
vendored
Normal file
@ -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}
|
||||
65
dist/addons/counters/mmenu.counters.js
vendored
Normal file
65
dist/addons/counters/mmenu.counters.js
vendored
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
25
dist/addons/dividers/_options.js
vendored
Normal file
25
dist/addons/dividers/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
1
dist/addons/dividers/mmenu.dividers.css
vendored
Normal file
1
dist/addons/dividers/mmenu.dividers.css
vendored
Normal file
@ -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)}
|
||||
46
dist/addons/dividers/mmenu.dividers.js
vendored
Normal file
46
dist/addons/dividers/mmenu.dividers.js
vendored
Normal file
@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
202
dist/addons/drag/_drag.open.js
vendored
Normal file
202
dist/addons/drag/_drag.open.js
vendored
Normal file
@ -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;
|
||||
};
|
||||
22
dist/addons/drag/_options.js
vendored
Normal file
22
dist/addons/drag/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
1
dist/addons/drag/mmenu.drag.css
vendored
Normal file
1
dist/addons/drag/mmenu.drag.css
vendored
Normal file
@ -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}
|
||||
21
dist/addons/drag/mmenu.drag.js
vendored
Normal file
21
dist/addons/drag/mmenu.drag.js
vendored
Normal file
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
19
dist/addons/dropdown/_configs.js
vendored
Normal file
19
dist/addons/dropdown/_configs.js
vendored
Normal file
@ -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;
|
||||
31
dist/addons/dropdown/_options.js
vendored
Normal file
31
dist/addons/dropdown/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/addons/dropdown/mmenu.dropdown.css
vendored
Normal file
1
dist/addons/dropdown/mmenu.dropdown.css
vendored
Normal file
@ -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}
|
||||
159
dist/addons/dropdown/mmenu.dropdown.js
vendored
Normal file
159
dist/addons/dropdown/mmenu.dropdown.js
vendored
Normal file
@ -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 });
|
||||
}
|
||||
}
|
||||
5
dist/addons/fixedelements/_configs.js
vendored
Normal file
5
dist/addons/fixedelements/_configs.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
var configs = {
|
||||
insertMethod: 'append',
|
||||
insertSelector: 'body'
|
||||
};
|
||||
export default configs;
|
||||
26
dist/addons/fixedelements/mmenu.fixedelements.js
vendored
Normal file
26
dist/addons/fixedelements/mmenu.fixedelements.js
vendored
Normal file
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
33
dist/addons/iconbar/_options.js
vendored
Normal file
33
dist/addons/iconbar/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
1
dist/addons/iconbar/mmenu.iconbar.css
vendored
Normal file
1
dist/addons/iconbar/mmenu.iconbar.css
vendored
Normal file
@ -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)}
|
||||
103
dist/addons/iconbar/mmenu.iconbar.js
vendored
Normal file
103
dist/addons/iconbar/mmenu.iconbar.js
vendored
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
33
dist/addons/iconpanels/_options.js
vendored
Normal file
33
dist/addons/iconpanels/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/addons/iconpanels/mmenu.iconpanels.css
vendored
Normal file
1
dist/addons/iconpanels/mmenu.iconpanels.css
vendored
Normal file
@ -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}
|
||||
99
dist/addons/iconpanels/mmenu.iconpanels.js
vendored
Normal file
99
dist/addons/iconpanels/mmenu.iconpanels.js
vendored
Normal file
@ -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);
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
23
dist/addons/keyboardnavigation/_options.js
vendored
Normal file
23
dist/addons/keyboardnavigation/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/addons/keyboardnavigation/mmenu.keyboardnavigation.css
vendored
Normal file
1
dist/addons/keyboardnavigation/mmenu.keyboardnavigation.css
vendored
Normal file
@ -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}
|
||||
183
dist/addons/keyboardnavigation/mmenu.keyboardnavigation.js
vendored
Normal file
183
dist/addons/keyboardnavigation/mmenu.keyboardnavigation.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
});
|
||||
};
|
||||
22
dist/addons/lazysubmenus/_options.js
vendored
Normal file
22
dist/addons/lazysubmenus/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
103
dist/addons/lazysubmenus/mmenu.lazysubmenus.js
vendored
Normal file
103
dist/addons/lazysubmenus/mmenu.lazysubmenus.js
vendored
Normal file
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
7
dist/addons/navbars/_configs.js
vendored
Normal file
7
dist/addons/navbars/_configs.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
var configs = {
|
||||
breadcrumbs: {
|
||||
separator: '/',
|
||||
removeFirst: false
|
||||
}
|
||||
};
|
||||
export default configs;
|
||||
53
dist/addons/navbars/_navbar.breadcrumbs.js
vendored
Normal file
53
dist/addons/navbars/_navbar.breadcrumbs.js
vendored
Normal file
@ -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
|
||||
? '<span>' + text + '</span>'
|
||||
: '<a href="#' +
|
||||
current.id +
|
||||
'">' +
|
||||
text +
|
||||
'</a>');
|
||||
}
|
||||
}
|
||||
first = false;
|
||||
}
|
||||
current = current['mmParent'];
|
||||
}
|
||||
if (_this.conf.navbars.breadcrumbs.removeFirst) {
|
||||
crumbs.shift();
|
||||
}
|
||||
breadcrumbs.innerHTML = crumbs.join('<span class="mm-separator">' +
|
||||
_this.conf.navbars.breadcrumbs.separator +
|
||||
'</span>');
|
||||
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));
|
||||
});
|
||||
});
|
||||
}
|
||||
17
dist/addons/navbars/_navbar.close.js
vendored
Normal file
17
dist/addons/navbars/_navbar.close.js
vendored
Normal file
@ -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));
|
||||
});
|
||||
}
|
||||
31
dist/addons/navbars/_navbar.next.js
vendored
Normal file
31
dist/addons/navbars/_navbar.next.js
vendored
Normal file
@ -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));
|
||||
});
|
||||
}
|
||||
41
dist/addons/navbars/_navbar.prev.js
vendored
Normal file
41
dist/addons/navbars/_navbar.prev.js
vendored
Normal file
@ -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));
|
||||
});
|
||||
}
|
||||
11
dist/addons/navbars/_navbar.searchfield.js
vendored
Normal file
11
dist/addons/navbars/_navbar.searchfield.js
vendored
Normal file
@ -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];
|
||||
}
|
||||
40
dist/addons/navbars/_navbar.tabs.js
vendored
Normal file
40
dist/addons/navbars/_navbar.tabs.js
vendored
Normal file
@ -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);
|
||||
}
|
||||
60
dist/addons/navbars/_navbar.title.js
vendored
Normal file
60
dist/addons/navbars/_navbar.title.js
vendored
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
30
dist/addons/navbars/_options.js
vendored
Normal file
30
dist/addons/navbars/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/addons/navbars/mmenu.navbars.css
vendored
Normal file
1
dist/addons/navbars/mmenu.navbars.css
vendored
Normal file
@ -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)}
|
||||
120
dist/addons/navbars/mmenu.navbars.js
vendored
Normal file
120
dist/addons/navbars/mmenu.navbars.js
vendored
Normal file
@ -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]);
|
||||
}
|
||||
});
|
||||
}
|
||||
5
dist/addons/pagescroll/_configs.js
vendored
Normal file
5
dist/addons/pagescroll/_configs.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
var configs = {
|
||||
scrollOffset: 0,
|
||||
updateOffset: 50
|
||||
};
|
||||
export default configs;
|
||||
23
dist/addons/pagescroll/_options.js
vendored
Normal file
23
dist/addons/pagescroll/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
111
dist/addons/pagescroll/mmenu.pagescroll.js
vendored
Normal file
111
dist/addons/pagescroll/mmenu.pagescroll.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
7
dist/addons/searchfield/_configs.js
vendored
Normal file
7
dist/addons/searchfield/_configs.js
vendored
Normal file
@ -0,0 +1,7 @@
|
||||
var configs = {
|
||||
clear: false,
|
||||
form: false,
|
||||
input: false,
|
||||
submit: false
|
||||
};
|
||||
export default configs;
|
||||
55
dist/addons/searchfield/_options.js
vendored
Normal file
55
dist/addons/searchfield/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/addons/searchfield/mmenu.searchfield.css
vendored
Normal file
1
dist/addons/searchfield/mmenu.searchfield.css
vendored
Normal file
@ -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}
|
||||
507
dist/addons/searchfield/mmenu.searchfield.js
vendored
Normal file
507
dist/addons/searchfield/mmenu.searchfield.js
vendored
Normal file
@ -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');
|
||||
};
|
||||
5
dist/addons/searchfield/translations/de.js
vendored
Normal file
5
dist/addons/searchfield/translations/de.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export default {
|
||||
Search: 'Suche',
|
||||
'No results found.': 'Keine Ergebnisse gefunden.',
|
||||
cancel: 'beenden'
|
||||
};
|
||||
5
dist/addons/searchfield/translations/fa.js
vendored
Normal file
5
dist/addons/searchfield/translations/fa.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export default {
|
||||
Search: 'جستجو',
|
||||
'No results found.': 'نتیجهای یافت نشد.',
|
||||
cancel: 'انصراف'
|
||||
};
|
||||
5
dist/addons/searchfield/translations/nl.js
vendored
Normal file
5
dist/addons/searchfield/translations/nl.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export default {
|
||||
Search: 'Zoeken',
|
||||
'No results found.': 'Geen resultaten gevonden.',
|
||||
cancel: 'annuleren'
|
||||
};
|
||||
5
dist/addons/searchfield/translations/ru.js
vendored
Normal file
5
dist/addons/searchfield/translations/ru.js
vendored
Normal file
@ -0,0 +1,5 @@
|
||||
export default {
|
||||
Search: 'Найти',
|
||||
'No results found.': 'Ничего не найдено.',
|
||||
cancel: 'отменить'
|
||||
};
|
||||
11
dist/addons/searchfield/translations/translate.js
vendored
Normal file
11
dist/addons/searchfield/translations/translate.js
vendored
Normal file
@ -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');
|
||||
}
|
||||
23
dist/addons/sectionindexer/_options.js
vendored
Normal file
23
dist/addons/sectionindexer/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/addons/sectionindexer/mmenu.sectionindexer.css
vendored
Normal file
1
dist/addons/sectionindexer/mmenu.sectionindexer.css
vendored
Normal file
@ -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}
|
||||
70
dist/addons/sectionindexer/mmenu.sectionindexer.js
vendored
Normal file
70
dist/addons/sectionindexer/mmenu.sectionindexer.js
vendored
Normal file
@ -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 += '<a href="#">' + letter + '</a>';
|
||||
});
|
||||
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');
|
||||
});
|
||||
});
|
||||
}
|
||||
25
dist/addons/setselected/_options.js
vendored
Normal file
25
dist/addons/setselected/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/addons/setselected/mmenu.setselected.css
vendored
Normal file
1
dist/addons/setselected/mmenu.setselected.css
vendored
Normal file
@ -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)}
|
||||
66
dist/addons/setselected/mmenu.setselected.js
vendored
Normal file
66
dist/addons/setselected/mmenu.setselected.js
vendored
Normal file
@ -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');
|
||||
});
|
||||
}
|
||||
}
|
||||
62
dist/addons/sidebar/_options.js
vendored
Normal file
62
dist/addons/sidebar/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
1
dist/addons/sidebar/mmenu.sidebar.css
vendored
Normal file
1
dist/addons/sidebar/mmenu.sidebar.css
vendored
Normal file
@ -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)}
|
||||
117
dist/addons/sidebar/mmenu.sidebar.js
vendored
Normal file
117
dist/addons/sidebar/mmenu.sidebar.js
vendored
Normal file
@ -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'
|
||||
};
|
||||
}
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
1
dist/addons/toggles/mmenu.toggles.css
vendored
Normal file
1
dist/addons/toggles/mmenu.toggles.css
vendored
Normal file
@ -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}
|
||||
17
dist/addons/toggles/mmenu.toggles.js
vendored
Normal file
17
dist/addons/toggles/mmenu.toggles.js
vendored
Normal file
@ -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');
|
||||
});
|
||||
});
|
||||
}
|
||||
13
dist/core/offcanvas/_configs.js
vendored
Normal file
13
dist/core/offcanvas/_configs.js
vendored
Normal file
@ -0,0 +1,13 @@
|
||||
var configs = {
|
||||
clone: false,
|
||||
menu: {
|
||||
insertMethod: 'prepend',
|
||||
insertSelector: 'body'
|
||||
},
|
||||
page: {
|
||||
nodetype: 'div',
|
||||
selector: null,
|
||||
noSelector: []
|
||||
}
|
||||
};
|
||||
export default configs;
|
||||
18
dist/core/offcanvas/_options.js
vendored
Normal file
18
dist/core/offcanvas/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/core/offcanvas/mmenu.offcanvas.css
vendored
Normal file
1
dist/core/offcanvas/mmenu.offcanvas.css
vendored
Normal file
@ -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}
|
||||
331
dist/core/offcanvas/mmenu.offcanvas.js
vendored
Normal file
331
dist/core/offcanvas/mmenu.offcanvas.js
vendored
Normal file
@ -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 <body>
|
||||
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 = '<a></a>';
|
||||
// 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');
|
||||
};
|
||||
15
dist/core/oncanvas/_configs.js
vendored
Normal file
15
dist/core/oncanvas/_configs.js
vendored
Normal file
@ -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;
|
||||
18
dist/core/oncanvas/_options.js
vendored
Normal file
18
dist/core/oncanvas/_options.js
vendored
Normal file
@ -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;
|
||||
1
dist/core/oncanvas/mmenu.oncanvas.css
vendored
Normal file
1
dist/core/oncanvas/mmenu.oncanvas.css
vendored
Normal file
File diff suppressed because one or more lines are too long
774
dist/core/oncanvas/mmenu.oncanvas.js
vendored
Normal file
774
dist/core/oncanvas/mmenu.oncanvas.js
vendored
Normal file
@ -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;
|
||||
3
dist/core/oncanvas/translations/de.js
vendored
Normal file
3
dist/core/oncanvas/translations/de.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export default {
|
||||
'Menu': 'Menü'
|
||||
};
|
||||
3
dist/core/oncanvas/translations/fa.js
vendored
Normal file
3
dist/core/oncanvas/translations/fa.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export default {
|
||||
'Menu': 'منو'
|
||||
};
|
||||
3
dist/core/oncanvas/translations/nl.js
vendored
Normal file
3
dist/core/oncanvas/translations/nl.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export default {
|
||||
'Menu': 'Menu'
|
||||
};
|
||||
3
dist/core/oncanvas/translations/ru.js
vendored
Normal file
3
dist/core/oncanvas/translations/ru.js
vendored
Normal file
@ -0,0 +1,3 @@
|
||||
export default {
|
||||
'Menu': 'Меню'
|
||||
};
|
||||
11
dist/core/oncanvas/translations/translate.js
vendored
Normal file
11
dist/core/oncanvas/translations/translate.js
vendored
Normal file
@ -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');
|
||||
}
|
||||
9
dist/core/screenreader/_configs.js
vendored
Normal file
9
dist/core/screenreader/_configs.js
vendored
Normal file
@ -0,0 +1,9 @@
|
||||
var configs = {
|
||||
text: {
|
||||
closeMenu: 'Close menu',
|
||||
closeSubmenu: 'Close submenu',
|
||||
openSubmenu: 'Open submenu',
|
||||
toggleSubmenu: 'Toggle submenu'
|
||||
}
|
||||
};
|
||||
export default configs;
|
||||
24
dist/core/screenreader/_options.js
vendored
Normal file
24
dist/core/screenreader/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
1
dist/core/screenreader/mmenu.screenreader.css
vendored
Normal file
1
dist/core/screenreader/mmenu.screenreader.css
vendored
Normal file
@ -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}
|
||||
189
dist/core/screenreader/mmenu.screenreader.js
vendored
Normal file
189
dist/core/screenreader/mmenu.screenreader.js
vendored
Normal file
@ -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 '<span class="mm-sronly">' + text + '</span>';
|
||||
};
|
||||
})();
|
||||
6
dist/core/screenreader/translations/de.js
vendored
Normal file
6
dist/core/screenreader/translations/de.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
'Close menu': 'Menü schließen',
|
||||
'Close submenu': 'Untermenü schließen',
|
||||
'Open submenu': 'Untermenü öffnen',
|
||||
'Toggle submenu': 'Untermenü wechseln'
|
||||
};
|
||||
6
dist/core/screenreader/translations/fa.js
vendored
Normal file
6
dist/core/screenreader/translations/fa.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
'Close menu': 'بستن منو',
|
||||
'Close submenu': 'بستن زیرمنو',
|
||||
'Open submenu': 'بازکردن زیرمنو',
|
||||
'Toggle submenu': 'سوییچ زیرمنو'
|
||||
};
|
||||
6
dist/core/screenreader/translations/nl.js
vendored
Normal file
6
dist/core/screenreader/translations/nl.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
'Close menu': 'Menu sluiten',
|
||||
'Close submenu': 'Submenu sluiten',
|
||||
'Open submenu': 'Submenu openen',
|
||||
'Toggle submenu': 'Submenu wisselen'
|
||||
};
|
||||
6
dist/core/screenreader/translations/ru.js
vendored
Normal file
6
dist/core/screenreader/translations/ru.js
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
export default {
|
||||
'Close menu': 'Закрыть меню',
|
||||
'Close submenu': 'Закрыть подменю',
|
||||
'Open submenu': 'Открыть подменю',
|
||||
'Toggle submenu': 'Переключить подменю'
|
||||
};
|
||||
11
dist/core/screenreader/translations/translate.js
vendored
Normal file
11
dist/core/screenreader/translations/translate.js
vendored
Normal file
@ -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');
|
||||
}
|
||||
22
dist/core/scrollbugfix/_options.js
vendored
Normal file
22
dist/core/scrollbugfix/_options.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
;
|
||||
91
dist/core/scrollbugfix/mmenu.scrollbugfix.js
vendored
Normal file
91
dist/core/scrollbugfix/mmenu.scrollbugfix.js
vendored
Normal file
@ -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';
|
||||
}
|
||||
});
|
||||
}
|
||||
1
dist/extensions/borderstyle/mmenu.borderstyle.css
vendored
Normal file
1
dist/extensions/borderstyle/mmenu.borderstyle.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
.mm-menu_border-none .mm-listitem:after{content:none}.mm-menu_border-full .mm-listitem:after{left:0!important}
|
||||
1
dist/extensions/effects/mmenu.effects.css
vendored
Normal file
1
dist/extensions/effects/mmenu.effects.css
vendored
Normal file
@ -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)}
|
||||
1
dist/extensions/fullscreen/mmenu.fullscreen.css
vendored
Normal file
1
dist/extensions/fullscreen/mmenu.fullscreen.css
vendored
Normal file
@ -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}
|
||||
1
dist/extensions/listview/mmenu.listview.css
vendored
Normal file
1
dist/extensions/listview/mmenu.listview.css
vendored
Normal file
@ -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}
|
||||
1
dist/extensions/multiline/mmenu.multiline.css
vendored
Normal file
1
dist/extensions/multiline/mmenu.multiline.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
.mm-menu_multiline .mm-listitem__text{-o-text-overflow:clip;text-overflow:clip;white-space:normal}
|
||||
1
dist/extensions/pagedim/mmenu.pagedim.css
vendored
Normal file
1
dist/extensions/pagedim/mmenu.pagedim.css
vendored
Normal file
@ -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}
|
||||
1
dist/extensions/popup/mmenu.popup.css
vendored
Normal file
1
dist/extensions/popup/mmenu.popup.css
vendored
Normal file
@ -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}
|
||||
1
dist/extensions/positioning/mmenu.positioning.css
vendored
Normal file
1
dist/extensions/positioning/mmenu.positioning.css
vendored
Normal file
@ -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)}
|
||||
1
dist/extensions/shadows/mmenu.shadows.css
vendored
Normal file
1
dist/extensions/shadows/mmenu.shadows.css
vendored
Normal file
@ -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)}
|
||||
1
dist/extensions/themes/mmenu.themes.css
vendored
Normal file
1
dist/extensions/themes/mmenu.themes.css
vendored
Normal file
@ -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}
|
||||
10
dist/mmenu.css
vendored
Normal file
10
dist/mmenu.css
vendored
Normal file
File diff suppressed because one or more lines are too long
12
dist/mmenu.js
vendored
Normal file
12
dist/mmenu.js
vendored
Normal file
File diff suppressed because one or more lines are too long
150
dist/mmenu.polyfills.js
vendored
Normal file
150
dist/mmenu.polyfills.js
vendored
Normal file
@ -0,0 +1,150 @@
|
||||
// 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);
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
// 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;
|
||||
};
|
||||
}
|
||||
|
||||
// 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]);
|
||||
8
dist/wrappers/angular/mmenu.angular.js
vendored
Normal file
8
dist/wrappers/angular/mmenu.angular.js
vendored
Normal file
@ -0,0 +1,8 @@
|
||||
export default function () {
|
||||
this.opts.onClick = {
|
||||
close: true,
|
||||
preventDefault: false,
|
||||
setSelected: true
|
||||
};
|
||||
}
|
||||
;
|
||||
1
dist/wrappers/bootstrap/mmenu.bootstrap.css
vendored
Normal file
1
dist/wrappers/bootstrap/mmenu.bootstrap.css
vendored
Normal file
@ -0,0 +1 @@
|
||||
body.modal-open .mm-slideout{z-index:unset}
|
||||
113
dist/wrappers/bootstrap/mmenu.bootstrap.js
vendored
Normal file
113
dist/wrappers/bootstrap/mmenu.bootstrap.js
vendored
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
4
dist/wrappers/magento/mmenu.magento.js
vendored
Normal file
4
dist/wrappers/magento/mmenu.magento.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export default function () {
|
||||
this.conf.classNames.selected = 'active';
|
||||
}
|
||||
;
|
||||
4
dist/wrappers/olark/mmenu.olark.js
vendored
Normal file
4
dist/wrappers/olark/mmenu.olark.js
vendored
Normal file
@ -0,0 +1,4 @@
|
||||
export default function () {
|
||||
this.conf.offCanvas.page.noSelector.push('#olark');
|
||||
}
|
||||
;
|
||||
15
dist/wrappers/turbolinks/mmenu.turbolinks.js
vendored
Normal file
15
dist/wrappers/turbolinks/mmenu.turbolinks.js
vendored
Normal file
@ -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;
|
||||
});
|
||||
}
|
||||
8
dist/wrappers/wordpress/mmenu.wordpress.js
vendored
Normal file
8
dist/wrappers/wordpress/mmenu.wordpress.js
vendored
Normal file
@ -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');
|
||||
}
|
||||
}
|
||||
142
gulp/css.js
Normal file
142
gulp/css.js
Normal file
@ -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));
|
||||
};
|
||||
35
gulp/dirs.js
Normal file
35
gulp/dirs.js
Normal file
@ -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;
|
||||
};
|
||||
93
gulp/js.js
Normal file
93
gulp/js.js
Normal file
@ -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));
|
||||
};
|
||||
27
gulp/polyfills.js
Normal file
27
gulp/polyfills.js
Normal file
@ -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));
|
||||
};
|
||||
69
gulpfile.js
Executable file
69
gulpfile.js
Executable file
@ -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);
|
||||
};
|
||||
28
index.html
Normal file
28
index.html
Normal file
@ -0,0 +1,28 @@
|
||||
<!DOCTYPE html>
|
||||
<html>
|
||||
<head>
|
||||
<meta charset="utf-8" />
|
||||
<meta name="author" content="www.frebsite.nl" />
|
||||
<meta content="width=600px user-scalable=yes" name="viewport" />
|
||||
<meta name="robots" content="noindex, nofollow" />
|
||||
|
||||
<title>mmenu.js, app look-alike menus with sliding submenus.</title>
|
||||
|
||||
<link type="text/css" rel="stylesheet" href="http://fonts.googleapis.com/css?family=Pacifico" />
|
||||
<link type="text/css" rel="stylesheet" href="demo/css/site.css" />
|
||||
</head>
|
||||
<body>
|
||||
<div id="wrapper">
|
||||
<div class="phone">
|
||||
<iframe name="phone" src="demo/advanced.html" frameborder="0" width="320" height="480"></iframe>
|
||||
</div>
|
||||
<div id="page">
|
||||
<h1>mmenu</h1>
|
||||
<p>The best javascript plugin for app look-alike on- and off-canvas menus with sliding submenus for your website and web-app.</p>
|
||||
<p>Check out the example on the left or <a href="https://mmenujs.com/examples.html" target="_blank">play around with the options</a>.</p>
|
||||
<p>For the full documentation please visit: <a href="https://mmenujs.com" target="_blank">mmenujs.com</a></p>
|
||||
<p>There also is a <a href="http://mmenujs.com/wordpress-plugin">WordPress plugin available</a>.</p>
|
||||
</div>
|
||||
</div>
|
||||
</body>
|
||||
</html>
|
||||
6270
package-lock.json
generated
Normal file
6270
package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load Diff
41
package.json
Normal file
41
package.json
Normal file
@ -0,0 +1,41 @@
|
||||
{
|
||||
"name": "mmenu-js",
|
||||
"version": "8.5.3",
|
||||
"main": "dist/mmenu.js",
|
||||
"module": "src/mmenu.js",
|
||||
"author": "Fred Heusschen <info@frebsite.nl>",
|
||||
"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"
|
||||
}
|
||||
}
|
||||
93
src/_includes.scss
Normal file
93
src/_includes.scss
Normal file
@ -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;
|
||||
183
src/_mixins.scss
Normal file
183
src/_mixins.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
158
src/_modules/dom.ts
Normal file
158
src/_modules/dom.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
13
src/_modules/dragevents/_defaults.ts
Normal file
13
src/_modules/dragevents/_defaults.ts
Normal file
@ -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
|
||||
};
|
||||
15
src/_modules/dragevents/_helpers.ts
Normal file
15
src/_modules/dragevents/_helpers.ts
Normal file
@ -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;
|
||||
};
|
||||
12
src/_modules/dragevents/_settings.ts
Normal file
12
src/_modules/dragevents/_settings.ts
Normal file
@ -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
|
||||
};
|
||||
5
src/_modules/dragevents/_support.ts
Normal file
5
src/_modules/dragevents/_support.ts
Normal file
@ -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;
|
||||
24
src/_modules/dragevents/_typings.d.ts
vendored
Normal file
24
src/_modules/dragevents/_typings.d.ts
vendored
Normal file
@ -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;
|
||||
}
|
||||
298
src/_modules/dragevents/index.ts
Normal file
298
src/_modules/dragevents/index.ts
Normal file
@ -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
|
||||
];
|
||||
}
|
||||
}
|
||||
64
src/_modules/eventlisteners.ts
Normal file
64
src/_modules/eventlisteners.ts
Normal file
@ -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 || {});
|
||||
});
|
||||
}
|
||||
147
src/_modules/helpers.ts
Normal file
147
src/_modules/helpers.ts
Normal file
@ -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;
|
||||
}
|
||||
39
src/_modules/i18n.ts
Normal file
39
src/_modules/i18n.ts
Normal file
@ -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;
|
||||
}
|
||||
44
src/_modules/matchmedia.ts
Normal file
44
src/_modules/matchmedia.ts
Normal file
@ -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]();
|
||||
}
|
||||
}
|
||||
5
src/_modules/support.ts
Normal file
5
src/_modules/support.ts
Normal file
@ -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;
|
||||
18
src/_polyfills/api.closest.js
Normal file
18
src/_polyfills/api.closest.js
Normal file
@ -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;
|
||||
};
|
||||
}
|
||||
9
src/_polyfills/api.foreach.js
Normal file
9
src/_polyfills/api.foreach.js
Normal file
@ -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);
|
||||
}
|
||||
};
|
||||
}
|
||||
17
src/_polyfills/api.matches.js
Normal file
17
src/_polyfills/api.matches.js
Normal file
@ -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;
|
||||
};
|
||||
}
|
||||
28
src/_polyfills/dom.append.js
Normal file
28
src/_polyfills/dom.append.js
Normal file
@ -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]);
|
||||
28
src/_polyfills/dom.before.js
Normal file
28
src/_polyfills/dom.before.js
Normal file
@ -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]);
|
||||
28
src/_polyfills/dom.prepend.js
Normal file
28
src/_polyfills/dom.prepend.js
Normal file
@ -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]);
|
||||
16
src/_polyfills/dom.remove.js
Normal file
16
src/_polyfills/dom.remove.js
Normal file
@ -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]);
|
||||
69
src/_variables.scss
Normal file
69
src/_variables.scss
Normal file
@ -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;
|
||||
1
src/_version.ts
Normal file
1
src/_version.ts
Normal file
@ -0,0 +1 @@
|
||||
export default '8.5.3';
|
||||
1
src/addons/autoheight/_includes.scss
Normal file
1
src/addons/autoheight/_includes.scss
Normal file
@ -0,0 +1 @@
|
||||
$mm_include_autoheight: true !default;
|
||||
33
src/addons/autoheight/_options.ts
Normal file
33
src/addons/autoheight/_options.ts
Normal file
@ -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;
|
||||
};
|
||||
6
src/addons/autoheight/_typings.d.ts
vendored
Normal file
6
src/addons/autoheight/_typings.d.ts
vendored
Normal file
@ -0,0 +1,6 @@
|
||||
/** Options for the autoHeight add-on. */
|
||||
interface mmOptionsAutoheight {
|
||||
|
||||
/** What type of height to use. */
|
||||
height ?: 'default' | 'auto' | 'highest'
|
||||
}
|
||||
31
src/addons/autoheight/mmenu.autoheight.scss
Normal file
31
src/addons/autoheight/mmenu.autoheight.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
105
src/addons/autoheight/mmenu.autoheight.ts
Normal file
105
src/addons/autoheight/mmenu.autoheight.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
28
src/addons/backbutton/_options.ts
Normal file
28
src/addons/backbutton/_options.ts
Normal file
@ -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;
|
||||
};
|
||||
9
src/addons/backbutton/_typings.d.ts
vendored
Normal file
9
src/addons/backbutton/_typings.d.ts
vendored
Normal file
@ -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
|
||||
}
|
||||
73
src/addons/backbutton/mmenu.backbutton.ts
Normal file
73
src/addons/backbutton/mmenu.backbutton.ts
Normal file
@ -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();
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
1
src/addons/columns/_includes.scss
Normal file
1
src/addons/columns/_includes.scss
Normal file
@ -0,0 +1 @@
|
||||
$mm_include_columns: true !default;
|
||||
33
src/addons/columns/_mixins.scss
Normal file
33
src/addons/columns/_mixins.scss
Normal file
@ -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
|
||||
);
|
||||
}
|
||||
45
src/addons/columns/_options.ts
Normal file
45
src/addons/columns/_options.ts
Normal file
@ -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;
|
||||
};
|
||||
19
src/addons/columns/_typings.d.ts
vendored
Normal file
19
src/addons/columns/_typings.d.ts
vendored
Normal file
@ -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
|
||||
}
|
||||
58
src/addons/columns/mmenu.columns.scss
Normal file
58
src/addons/columns/mmenu.columns.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
137
src/addons/columns/mmenu.columns.ts
Normal file
137
src/addons/columns/mmenu.columns.ts
Normal file
@ -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);
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
8
src/addons/counters/_counters.rtl.scss
Normal file
8
src/addons/counters/_counters.rtl.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
1
src/addons/counters/_includes.scss
Normal file
1
src/addons/counters/_includes.scss
Normal file
@ -0,0 +1 @@
|
||||
$mm_include_counters: true !default;
|
||||
34
src/addons/counters/_options.ts
Normal file
34
src/addons/counters/_options.ts
Normal file
@ -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;
|
||||
}
|
||||
12
src/addons/counters/_typings.d.ts
vendored
Normal file
12
src/addons/counters/_typings.d.ts
vendored
Normal file
@ -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
|
||||
}
|
||||
1
src/addons/counters/_variables.scss
Normal file
1
src/addons/counters/_variables.scss
Normal file
@ -0,0 +1 @@
|
||||
$mm_counterWidth: $mm_btnSize !default;
|
||||
23
src/addons/counters/mmenu.counters.scss
Normal file
23
src/addons/counters/mmenu.counters.scss
Normal file
@ -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';
|
||||
79
src/addons/counters/mmenu.counters.ts
Normal file
79
src/addons/counters/mmenu.counters.ts
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
1
src/addons/dividers/_includes.scss
Normal file
1
src/addons/dividers/_includes.scss
Normal file
@ -0,0 +1 @@
|
||||
$mm_include_dividers: true !default;
|
||||
31
src/addons/dividers/_options.ts
Normal file
31
src/addons/dividers/_options.ts
Normal file
@ -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;
|
||||
}
|
||||
8
src/addons/dividers/_typings.d.ts
vendored
Normal file
8
src/addons/dividers/_typings.d.ts
vendored
Normal file
@ -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;
|
||||
}
|
||||
53
src/addons/dividers/mmenu.dividers.scss
Normal file
53
src/addons/dividers/mmenu.dividers.scss
Normal file
@ -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);
|
||||
}
|
||||
}
|
||||
56
src/addons/dividers/mmenu.dividers.ts
Normal file
56
src/addons/dividers/mmenu.dividers.ts
Normal file
@ -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);
|
||||
}
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
277
src/addons/drag/_drag.open.ts
Normal file
277
src/addons/drag/_drag.open.ts
Normal file
@ -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;
|
||||
};
|
||||
1
src/addons/drag/_includes.scss
Normal file
1
src/addons/drag/_includes.scss
Normal file
@ -0,0 +1 @@
|
||||
$mm_include_drag: true !default;
|
||||
25
src/addons/drag/_options.ts
Normal file
25
src/addons/drag/_options.ts
Normal file
@ -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;
|
||||
}
|
||||
8
src/addons/drag/_typings.d.ts
vendored
Normal file
8
src/addons/drag/_typings.d.ts
vendored
Normal file
@ -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;
|
||||
}
|
||||
17
src/addons/drag/mmenu.drag.scss
Normal file
17
src/addons/drag/mmenu.drag.scss
Normal file
@ -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;
|
||||
}
|
||||
}
|
||||
24
src/addons/drag/mmenu.drag.ts
Normal file
24
src/addons/drag/mmenu.drag.ts
Normal file
@ -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);
|
||||
});
|
||||
}
|
||||
}
|
||||
19
src/addons/dropdown/_configs.ts
Normal file
19
src/addons/dropdown/_configs.ts
Normal file
@ -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;
|
||||
Some files were not shown because too many files have changed in this diff Show More
Loading…
x
Reference in New Issue
Block a user