Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/matomo-org/matomo.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
Diffstat (limited to 'node_modules/materialize-css/js/sidenav.js')
-rw-r--r--node_modules/materialize-css/js/sidenav.js580
1 files changed, 580 insertions, 0 deletions
diff --git a/node_modules/materialize-css/js/sidenav.js b/node_modules/materialize-css/js/sidenav.js
new file mode 100644
index 0000000000..4a88dd3901
--- /dev/null
+++ b/node_modules/materialize-css/js/sidenav.js
@@ -0,0 +1,580 @@
+(function($, anim) {
+ 'use strict';
+
+ let _defaults = {
+ edge: 'left',
+ draggable: true,
+ inDuration: 250,
+ outDuration: 200,
+ onOpenStart: null,
+ onOpenEnd: null,
+ onCloseStart: null,
+ onCloseEnd: null,
+ preventScrolling: true
+ };
+
+ /**
+ * @class
+ */
+ class Sidenav extends Component {
+ /**
+ * Construct Sidenav instance and set up overlay
+ * @constructor
+ * @param {Element} el
+ * @param {Object} options
+ */
+ constructor(el, options) {
+ super(Sidenav, el, options);
+
+ this.el.M_Sidenav = this;
+ this.id = this.$el.attr('id');
+
+ /**
+ * Options for the Sidenav
+ * @member Sidenav#options
+ * @prop {String} [edge='left'] - Side of screen on which Sidenav appears
+ * @prop {Boolean} [draggable=true] - Allow swipe gestures to open/close Sidenav
+ * @prop {Number} [inDuration=250] - Length in ms of enter transition
+ * @prop {Number} [outDuration=200] - Length in ms of exit transition
+ * @prop {Function} onOpenStart - Function called when sidenav starts entering
+ * @prop {Function} onOpenEnd - Function called when sidenav finishes entering
+ * @prop {Function} onCloseStart - Function called when sidenav starts exiting
+ * @prop {Function} onCloseEnd - Function called when sidenav finishes exiting
+ */
+ this.options = $.extend({}, Sidenav.defaults, options);
+
+ /**
+ * Describes open/close state of Sidenav
+ * @type {Boolean}
+ */
+ this.isOpen = false;
+
+ /**
+ * Describes if Sidenav is fixed
+ * @type {Boolean}
+ */
+ this.isFixed = this.el.classList.contains('sidenav-fixed');
+
+ /**
+ * Describes if Sidenav is being draggeed
+ * @type {Boolean}
+ */
+ this.isDragged = false;
+
+ // Window size variables for window resize checks
+ this.lastWindowWidth = window.innerWidth;
+ this.lastWindowHeight = window.innerHeight;
+
+ this._createOverlay();
+ this._createDragTarget();
+ this._setupEventHandlers();
+ this._setupClasses();
+ this._setupFixed();
+
+ Sidenav._sidenavs.push(this);
+ }
+
+ static get defaults() {
+ return _defaults;
+ }
+
+ static init(els, options) {
+ return super.init(this, els, options);
+ }
+
+ /**
+ * Get Instance
+ */
+ static getInstance(el) {
+ let domElem = !!el.jquery ? el[0] : el;
+ return domElem.M_Sidenav;
+ }
+
+ /**
+ * Teardown component
+ */
+ destroy() {
+ this._removeEventHandlers();
+ this._enableBodyScrolling();
+ this._overlay.parentNode.removeChild(this._overlay);
+ this.dragTarget.parentNode.removeChild(this.dragTarget);
+ this.el.M_Sidenav = undefined;
+ this.el.style.transform = '';
+
+ let index = Sidenav._sidenavs.indexOf(this);
+ if (index >= 0) {
+ Sidenav._sidenavs.splice(index, 1);
+ }
+ }
+
+ _createOverlay() {
+ let overlay = document.createElement('div');
+ this._closeBound = this.close.bind(this);
+ overlay.classList.add('sidenav-overlay');
+
+ overlay.addEventListener('click', this._closeBound);
+
+ document.body.appendChild(overlay);
+ this._overlay = overlay;
+ }
+
+ _setupEventHandlers() {
+ if (Sidenav._sidenavs.length === 0) {
+ document.body.addEventListener('click', this._handleTriggerClick);
+ }
+
+ this._handleDragTargetDragBound = this._handleDragTargetDrag.bind(this);
+ this._handleDragTargetReleaseBound = this._handleDragTargetRelease.bind(this);
+ this._handleCloseDragBound = this._handleCloseDrag.bind(this);
+ this._handleCloseReleaseBound = this._handleCloseRelease.bind(this);
+ this._handleCloseTriggerClickBound = this._handleCloseTriggerClick.bind(this);
+
+ this.dragTarget.addEventListener('touchmove', this._handleDragTargetDragBound);
+ this.dragTarget.addEventListener('touchend', this._handleDragTargetReleaseBound);
+ this._overlay.addEventListener('touchmove', this._handleCloseDragBound);
+ this._overlay.addEventListener('touchend', this._handleCloseReleaseBound);
+ this.el.addEventListener('touchmove', this._handleCloseDragBound);
+ this.el.addEventListener('touchend', this._handleCloseReleaseBound);
+ this.el.addEventListener('click', this._handleCloseTriggerClickBound);
+
+ // Add resize for side nav fixed
+ if (this.isFixed) {
+ this._handleWindowResizeBound = this._handleWindowResize.bind(this);
+ window.addEventListener('resize', this._handleWindowResizeBound);
+ }
+ }
+
+ _removeEventHandlers() {
+ if (Sidenav._sidenavs.length === 1) {
+ document.body.removeEventListener('click', this._handleTriggerClick);
+ }
+
+ this.dragTarget.removeEventListener('touchmove', this._handleDragTargetDragBound);
+ this.dragTarget.removeEventListener('touchend', this._handleDragTargetReleaseBound);
+ this._overlay.removeEventListener('touchmove', this._handleCloseDragBound);
+ this._overlay.removeEventListener('touchend', this._handleCloseReleaseBound);
+ this.el.removeEventListener('touchmove', this._handleCloseDragBound);
+ this.el.removeEventListener('touchend', this._handleCloseReleaseBound);
+ this.el.removeEventListener('click', this._handleCloseTriggerClickBound);
+
+ // Remove resize for side nav fixed
+ if (this.isFixed) {
+ window.removeEventListener('resize', this._handleWindowResizeBound);
+ }
+ }
+
+ /**
+ * Handle Trigger Click
+ * @param {Event} e
+ */
+ _handleTriggerClick(e) {
+ let $trigger = $(e.target).closest('.sidenav-trigger');
+ if (e.target && $trigger.length) {
+ let sidenavId = M.getIdFromTrigger($trigger[0]);
+
+ let sidenavInstance = document.getElementById(sidenavId).M_Sidenav;
+ if (sidenavInstance) {
+ sidenavInstance.open($trigger);
+ }
+ e.preventDefault();
+ }
+ }
+
+ /**
+ * Set variables needed at the beggining of drag
+ * and stop any current transition.
+ * @param {Event} e
+ */
+ _startDrag(e) {
+ let clientX = e.targetTouches[0].clientX;
+ this.isDragged = true;
+ this._startingXpos = clientX;
+ this._xPos = this._startingXpos;
+ this._time = Date.now();
+ this._width = this.el.getBoundingClientRect().width;
+ this._overlay.style.display = 'block';
+ this._initialScrollTop = this.isOpen ? this.el.scrollTop : M.getDocumentScrollTop();
+ this._verticallyScrolling = false;
+ anim.remove(this.el);
+ anim.remove(this._overlay);
+ }
+
+ /**
+ * Set variables needed at each drag move update tick
+ * @param {Event} e
+ */
+ _dragMoveUpdate(e) {
+ let clientX = e.targetTouches[0].clientX;
+ let currentScrollTop = this.isOpen ? this.el.scrollTop : M.getDocumentScrollTop();
+ this.deltaX = Math.abs(this._xPos - clientX);
+ this._xPos = clientX;
+ this.velocityX = this.deltaX / (Date.now() - this._time);
+ this._time = Date.now();
+ if (this._initialScrollTop !== currentScrollTop) {
+ this._verticallyScrolling = true;
+ }
+ }
+
+ /**
+ * Handles Dragging of Sidenav
+ * @param {Event} e
+ */
+ _handleDragTargetDrag(e) {
+ // Check if draggable
+ if (!this.options.draggable || this._isCurrentlyFixed() || this._verticallyScrolling) {
+ return;
+ }
+
+ // If not being dragged, set initial drag start variables
+ if (!this.isDragged) {
+ this._startDrag(e);
+ }
+
+ // Run touchmove updates
+ this._dragMoveUpdate(e);
+
+ // Calculate raw deltaX
+ let totalDeltaX = this._xPos - this._startingXpos;
+
+ // dragDirection is the attempted user drag direction
+ let dragDirection = totalDeltaX > 0 ? 'right' : 'left';
+
+ // Don't allow totalDeltaX to exceed Sidenav width or be dragged in the opposite direction
+ totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
+ if (this.options.edge === dragDirection) {
+ totalDeltaX = 0;
+ }
+
+ /**
+ * transformX is the drag displacement
+ * transformPrefix is the initial transform placement
+ * Invert values if Sidenav is right edge
+ */
+ let transformX = totalDeltaX;
+ let transformPrefix = 'translateX(-100%)';
+ if (this.options.edge === 'right') {
+ transformPrefix = 'translateX(100%)';
+ transformX = -transformX;
+ }
+
+ // Calculate open/close percentage of sidenav, with open = 1 and close = 0
+ this.percentOpen = Math.min(1, totalDeltaX / this._width);
+
+ // Set transform and opacity styles
+ this.el.style.transform = `${transformPrefix} translateX(${transformX}px)`;
+ this._overlay.style.opacity = this.percentOpen;
+ }
+
+ /**
+ * Handle Drag Target Release
+ */
+ _handleDragTargetRelease() {
+ if (this.isDragged) {
+ if (this.percentOpen > 0.2) {
+ this.open();
+ } else {
+ this._animateOut();
+ }
+
+ this.isDragged = false;
+ this._verticallyScrolling = false;
+ }
+ }
+
+ /**
+ * Handle Close Drag
+ * @param {Event} e
+ */
+ _handleCloseDrag(e) {
+ if (this.isOpen) {
+ // Check if draggable
+ if (!this.options.draggable || this._isCurrentlyFixed() || this._verticallyScrolling) {
+ return;
+ }
+
+ // If not being dragged, set initial drag start variables
+ if (!this.isDragged) {
+ this._startDrag(e);
+ }
+
+ // Run touchmove updates
+ this._dragMoveUpdate(e);
+
+ // Calculate raw deltaX
+ let totalDeltaX = this._xPos - this._startingXpos;
+
+ // dragDirection is the attempted user drag direction
+ let dragDirection = totalDeltaX > 0 ? 'right' : 'left';
+
+ // Don't allow totalDeltaX to exceed Sidenav width or be dragged in the opposite direction
+ totalDeltaX = Math.min(this._width, Math.abs(totalDeltaX));
+ if (this.options.edge !== dragDirection) {
+ totalDeltaX = 0;
+ }
+
+ let transformX = -totalDeltaX;
+ if (this.options.edge === 'right') {
+ transformX = -transformX;
+ }
+
+ // Calculate open/close percentage of sidenav, with open = 1 and close = 0
+ this.percentOpen = Math.min(1, 1 - totalDeltaX / this._width);
+
+ // Set transform and opacity styles
+ this.el.style.transform = `translateX(${transformX}px)`;
+ this._overlay.style.opacity = this.percentOpen;
+ }
+ }
+
+ /**
+ * Handle Close Release
+ */
+ _handleCloseRelease() {
+ if (this.isOpen && this.isDragged) {
+ if (this.percentOpen > 0.8) {
+ this._animateIn();
+ } else {
+ this.close();
+ }
+
+ this.isDragged = false;
+ this._verticallyScrolling = false;
+ }
+ }
+
+ /**
+ * Handles closing of Sidenav when element with class .sidenav-close
+ */
+ _handleCloseTriggerClick(e) {
+ let $closeTrigger = $(e.target).closest('.sidenav-close');
+ if ($closeTrigger.length && !this._isCurrentlyFixed()) {
+ this.close();
+ }
+ }
+
+ /**
+ * Handle Window Resize
+ */
+ _handleWindowResize() {
+ // Only handle horizontal resizes
+ if (this.lastWindowWidth !== window.innerWidth) {
+ if (window.innerWidth > 992) {
+ this.open();
+ } else {
+ this.close();
+ }
+ }
+
+ this.lastWindowWidth = window.innerWidth;
+ this.lastWindowHeight = window.innerHeight;
+ }
+
+ _setupClasses() {
+ if (this.options.edge === 'right') {
+ this.el.classList.add('right-aligned');
+ this.dragTarget.classList.add('right-aligned');
+ }
+ }
+
+ _removeClasses() {
+ this.el.classList.remove('right-aligned');
+ this.dragTarget.classList.remove('right-aligned');
+ }
+
+ _setupFixed() {
+ if (this._isCurrentlyFixed()) {
+ this.open();
+ }
+ }
+
+ _isCurrentlyFixed() {
+ return this.isFixed && window.innerWidth > 992;
+ }
+
+ _createDragTarget() {
+ let dragTarget = document.createElement('div');
+ dragTarget.classList.add('drag-target');
+ document.body.appendChild(dragTarget);
+ this.dragTarget = dragTarget;
+ }
+
+ _preventBodyScrolling() {
+ let body = document.body;
+ body.style.overflow = 'hidden';
+ }
+
+ _enableBodyScrolling() {
+ let body = document.body;
+ body.style.overflow = '';
+ }
+
+ open() {
+ if (this.isOpen === true) {
+ return;
+ }
+
+ this.isOpen = true;
+
+ // Run onOpenStart callback
+ if (typeof this.options.onOpenStart === 'function') {
+ this.options.onOpenStart.call(this, this.el);
+ }
+
+ // Handle fixed Sidenav
+ if (this._isCurrentlyFixed()) {
+ anim.remove(this.el);
+ anim({
+ targets: this.el,
+ translateX: 0,
+ duration: 0,
+ easing: 'easeOutQuad'
+ });
+ this._enableBodyScrolling();
+ this._overlay.style.display = 'none';
+
+ // Handle non-fixed Sidenav
+ } else {
+ if (this.options.preventScrolling) {
+ this._preventBodyScrolling();
+ }
+
+ if (!this.isDragged || this.percentOpen != 1) {
+ this._animateIn();
+ }
+ }
+ }
+
+ close() {
+ if (this.isOpen === false) {
+ return;
+ }
+
+ this.isOpen = false;
+
+ // Run onCloseStart callback
+ if (typeof this.options.onCloseStart === 'function') {
+ this.options.onCloseStart.call(this, this.el);
+ }
+
+ // Handle fixed Sidenav
+ if (this._isCurrentlyFixed()) {
+ let transformX = this.options.edge === 'left' ? '-105%' : '105%';
+ this.el.style.transform = `translateX(${transformX})`;
+
+ // Handle non-fixed Sidenav
+ } else {
+ this._enableBodyScrolling();
+
+ if (!this.isDragged || this.percentOpen != 0) {
+ this._animateOut();
+ } else {
+ this._overlay.style.display = 'none';
+ }
+ }
+ }
+
+ _animateIn() {
+ this._animateSidenavIn();
+ this._animateOverlayIn();
+ }
+
+ _animateSidenavIn() {
+ let slideOutPercent = this.options.edge === 'left' ? -1 : 1;
+ if (this.isDragged) {
+ slideOutPercent =
+ this.options.edge === 'left'
+ ? slideOutPercent + this.percentOpen
+ : slideOutPercent - this.percentOpen;
+ }
+
+ anim.remove(this.el);
+ anim({
+ targets: this.el,
+ translateX: [`${slideOutPercent * 100}%`, 0],
+ duration: this.options.inDuration,
+ easing: 'easeOutQuad',
+ complete: () => {
+ // Run onOpenEnd callback
+ if (typeof this.options.onOpenEnd === 'function') {
+ this.options.onOpenEnd.call(this, this.el);
+ }
+ }
+ });
+ }
+
+ _animateOverlayIn() {
+ let start = 0;
+ if (this.isDragged) {
+ start = this.percentOpen;
+ } else {
+ $(this._overlay).css({
+ display: 'block'
+ });
+ }
+
+ anim.remove(this._overlay);
+ anim({
+ targets: this._overlay,
+ opacity: [start, 1],
+ duration: this.options.inDuration,
+ easing: 'easeOutQuad'
+ });
+ }
+
+ _animateOut() {
+ this._animateSidenavOut();
+ this._animateOverlayOut();
+ }
+
+ _animateSidenavOut() {
+ let endPercent = this.options.edge === 'left' ? -1 : 1;
+ let slideOutPercent = 0;
+ if (this.isDragged) {
+ slideOutPercent =
+ this.options.edge === 'left'
+ ? endPercent + this.percentOpen
+ : endPercent - this.percentOpen;
+ }
+
+ anim.remove(this.el);
+ anim({
+ targets: this.el,
+ translateX: [`${slideOutPercent * 100}%`, `${endPercent * 105}%`],
+ duration: this.options.outDuration,
+ easing: 'easeOutQuad',
+ complete: () => {
+ // Run onOpenEnd callback
+ if (typeof this.options.onCloseEnd === 'function') {
+ this.options.onCloseEnd.call(this, this.el);
+ }
+ }
+ });
+ }
+
+ _animateOverlayOut() {
+ anim.remove(this._overlay);
+ anim({
+ targets: this._overlay,
+ opacity: 0,
+ duration: this.options.outDuration,
+ easing: 'easeOutQuad',
+ complete: () => {
+ $(this._overlay).css('display', 'none');
+ }
+ });
+ }
+ }
+
+ /**
+ * @static
+ * @memberof Sidenav
+ * @type {Array.<Sidenav>}
+ */
+ Sidenav._sidenavs = [];
+
+ M.Sidenav = Sidenav;
+
+ if (M.jQueryLoaded) {
+ M.initializeJqueryWrapper(Sidenav, 'sidenav', 'M_Sidenav');
+ }
+})(cash, M.anime);