UNPKG

vue-waves-effect

Version:

Waves effect directive for Vue. Based on Waves.

929 lines (741 loc) 30 kB
(function webpackUniversalModuleDefinition(root, factory) { if(typeof exports === 'object' && typeof module === 'object') module.exports = factory(); else if(typeof define === 'function' && define.amd) define([], factory); else if(typeof exports === 'object') exports["vueWavesEffect"] = factory(); else root["vueWavesEffect"] = factory(); })((typeof self !== 'undefined' ? self : this), function() { return /******/ (function(modules) { // webpackBootstrap /******/ // The module cache /******/ var installedModules = {}; /******/ /******/ // The require function /******/ function __webpack_require__(moduleId) { /******/ /******/ // Check if module is in cache /******/ if(installedModules[moduleId]) { /******/ return installedModules[moduleId].exports; /******/ } /******/ // Create a new module (and put it into the cache) /******/ var module = installedModules[moduleId] = { /******/ i: moduleId, /******/ l: false, /******/ exports: {} /******/ }; /******/ /******/ // Execute the module function /******/ modules[moduleId].call(module.exports, module, module.exports, __webpack_require__); /******/ /******/ // Flag the module as loaded /******/ module.l = true; /******/ /******/ // Return the exports of the module /******/ return module.exports; /******/ } /******/ /******/ /******/ // expose the modules object (__webpack_modules__) /******/ __webpack_require__.m = modules; /******/ /******/ // expose the module cache /******/ __webpack_require__.c = installedModules; /******/ /******/ // define getter function for harmony exports /******/ __webpack_require__.d = function(exports, name, getter) { /******/ if(!__webpack_require__.o(exports, name)) { /******/ Object.defineProperty(exports, name, { enumerable: true, get: getter }); /******/ } /******/ }; /******/ /******/ // define __esModule on exports /******/ __webpack_require__.r = function(exports) { /******/ if(typeof Symbol !== 'undefined' && Symbol.toStringTag) { /******/ Object.defineProperty(exports, Symbol.toStringTag, { value: 'Module' }); /******/ } /******/ Object.defineProperty(exports, '__esModule', { value: true }); /******/ }; /******/ /******/ // create a fake namespace object /******/ // mode & 1: value is a module id, require it /******/ // mode & 2: merge all properties of value into the ns /******/ // mode & 4: return value when already ns object /******/ // mode & 8|1: behave like require /******/ __webpack_require__.t = function(value, mode) { /******/ if(mode & 1) value = __webpack_require__(value); /******/ if(mode & 8) return value; /******/ if((mode & 4) && typeof value === 'object' && value && value.__esModule) return value; /******/ var ns = Object.create(null); /******/ __webpack_require__.r(ns); /******/ Object.defineProperty(ns, 'default', { enumerable: true, value: value }); /******/ if(mode & 2 && typeof value != 'string') for(var key in value) __webpack_require__.d(ns, key, function(key) { return value[key]; }.bind(null, key)); /******/ return ns; /******/ }; /******/ /******/ // getDefaultExport function for compatibility with non-harmony modules /******/ __webpack_require__.n = function(module) { /******/ var getter = module && module.__esModule ? /******/ function getDefault() { return module['default']; } : /******/ function getModuleExports() { return module; }; /******/ __webpack_require__.d(getter, 'a', getter); /******/ return getter; /******/ }; /******/ /******/ // Object.prototype.hasOwnProperty.call /******/ __webpack_require__.o = function(object, property) { return Object.prototype.hasOwnProperty.call(object, property); }; /******/ /******/ // __webpack_public_path__ /******/ __webpack_require__.p = ""; /******/ /******/ /******/ // Load entry module and return exports /******/ return __webpack_require__(__webpack_require__.s = "fb15"); /******/ }) /************************************************************************/ /******/ ({ /***/ "8875": /***/ (function(module, exports, __webpack_require__) { var __WEBPACK_AMD_DEFINE_FACTORY__, __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;// addapted from the document.currentScript polyfill by Adam Miller // MIT license // source: https://github.com/amiller-gh/currentScript-polyfill // added support for Firefox https://bugzilla.mozilla.org/show_bug.cgi?id=1620505 (function (root, factory) { if (true) { !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_FACTORY__ = (factory), __WEBPACK_AMD_DEFINE_RESULT__ = (typeof __WEBPACK_AMD_DEFINE_FACTORY__ === 'function' ? (__WEBPACK_AMD_DEFINE_FACTORY__.apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__)) : __WEBPACK_AMD_DEFINE_FACTORY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } else {} }(typeof self !== 'undefined' ? self : this, function () { function getCurrentScript () { var descriptor = Object.getOwnPropertyDescriptor(document, 'currentScript') // for chrome if (!descriptor && 'currentScript' in document && document.currentScript) { return document.currentScript } // for other browsers with native support for currentScript if (descriptor && descriptor.get !== getCurrentScript && document.currentScript) { return document.currentScript } // IE 8-10 support script readyState // IE 11+ & Firefox support stack trace try { throw new Error(); } catch (err) { // Find the second match for the "at" string to get file src url from stack. var ieStackRegExp = /.*at [^(]*\((.*):(.+):(.+)\)$/ig, ffStackRegExp = /@([^@]*):(\d+):(\d+)\s*$/ig, stackDetails = ieStackRegExp.exec(err.stack) || ffStackRegExp.exec(err.stack), scriptLocation = (stackDetails && stackDetails[1]) || false, line = (stackDetails && stackDetails[2]) || false, currentLocation = document.location.href.replace(document.location.hash, ''), pageSource, inlineScriptSourceRegExp, inlineScriptSource, scripts = document.getElementsByTagName('script'); // Live NodeList collection if (scriptLocation === currentLocation) { pageSource = document.documentElement.outerHTML; inlineScriptSourceRegExp = new RegExp('(?:[^\\n]+?\\n){0,' + (line - 2) + '}[^<]*<script>([\\d\\D]*?)<\\/script>[\\d\\D]*', 'i'); inlineScriptSource = pageSource.replace(inlineScriptSourceRegExp, '$1').trim(); } for (var i = 0; i < scripts.length; i++) { // If ready state is interactive, return the script tag if (scripts[i].readyState === 'interactive') { return scripts[i]; } // If src matches, return the script tag if (scripts[i].src === scriptLocation) { return scripts[i]; } // If inline source matches, return the script tag if ( scriptLocation === currentLocation && scripts[i].innerHTML && scripts[i].innerHTML.trim() === inlineScriptSource ) { return scripts[i]; } } // If no match, return null return null; } }; return getCurrentScript })); /***/ }), /***/ "c8ba": /***/ (function(module, exports) { var g; // This works in non-strict mode g = (function() { return this; })(); try { // This works if eval is allowed (see CSP) g = g || new Function("return this")(); } catch (e) { // This works if the window reference is available if (typeof window === "object") g = window; } // g can still be undefined, but nothing to do about it... // We return undefined, instead of nothing here, so it's // easier to handle this case. if(!global) { ...} module.exports = g; /***/ }), /***/ "c9d5": /***/ (function(module, exports, __webpack_require__) { /* WEBPACK VAR INJECTION */(function(global) {var __WEBPACK_AMD_DEFINE_ARRAY__, __WEBPACK_AMD_DEFINE_RESULT__;/*! * Waves v0.7.6 * http://fian.my.id/Waves * * Copyright 2014-2018 Alfiana E. Sibuea and other contributors * Released under the MIT license * https://github.com/fians/Waves/blob/master/LICENSE */ ;(function(window, factory) { 'use strict'; // AMD. Register as an anonymous module. Wrap in function so we have access // to root via `this`. if (true) { !(__WEBPACK_AMD_DEFINE_ARRAY__ = [], __WEBPACK_AMD_DEFINE_RESULT__ = (function() { window.Waves = factory.call(window); return window.Waves; }).apply(exports, __WEBPACK_AMD_DEFINE_ARRAY__), __WEBPACK_AMD_DEFINE_RESULT__ !== undefined && (module.exports = __WEBPACK_AMD_DEFINE_RESULT__)); } // Node. Does not work with strict CommonJS, but only CommonJS-like // environments that support module.exports, like Node. else {} })(typeof global === 'object' ? global : this, function() { 'use strict'; var Waves = Waves || {}; var $$ = document.querySelectorAll.bind(document); var toString = Object.prototype.toString; var isTouchAvailable = 'ontouchstart' in window; // Find exact position of element function isWindow(obj) { return obj !== null && obj === obj.window; } function getWindow(elem) { return isWindow(elem) ? elem : elem.nodeType === 9 && elem.defaultView; } function isObject(value) { var type = typeof value; return type === 'function' || type === 'object' && !!value; } function isDOMNode(obj) { return isObject(obj) && obj.nodeType > 0; } function getWavesElements(nodes) { var stringRepr = toString.call(nodes); if (stringRepr === '[object String]') { return $$(nodes); } else if (isObject(nodes) && /^\[object (Array|HTMLCollection|NodeList|Object)\]$/.test(stringRepr) && nodes.hasOwnProperty('length')) { return nodes; } else if (isDOMNode(nodes)) { return [nodes]; } return []; } function offset(elem) { var docElem, win, box = { top: 0, left: 0 }, doc = elem && elem.ownerDocument; docElem = doc.documentElement; if (typeof elem.getBoundingClientRect !== typeof undefined) { box = elem.getBoundingClientRect(); } win = getWindow(doc); return { top: box.top + win.pageYOffset - docElem.clientTop, left: box.left + win.pageXOffset - docElem.clientLeft }; } function convertStyle(styleObj) { var style = ''; for (var prop in styleObj) { if (styleObj.hasOwnProperty(prop)) { style += (prop + ':' + styleObj[prop] + ';'); } } return style; } var Effect = { // Effect duration duration: 750, // Effect delay (check for scroll before showing effect) delay: 200, show: function(e, element, velocity) { // Disable right click if (e.button === 2) { return false; } element = element || this; // Create ripple var ripple = document.createElement('div'); ripple.className = 'waves-ripple waves-rippling'; element.appendChild(ripple); // Get click coordinate and element width var pos = offset(element); var relativeY = 0; var relativeX = 0; // Support for touch devices if('touches' in e && e.touches.length) { relativeY = (e.touches[0].pageY - pos.top); relativeX = (e.touches[0].pageX - pos.left); } //Normal case else { relativeY = (e.pageY - pos.top); relativeX = (e.pageX - pos.left); } // Support for synthetic events relativeX = relativeX >= 0 ? relativeX : 0; relativeY = relativeY >= 0 ? relativeY : 0; var scale = 'scale(' + ((element.clientWidth / 100) * 3) + ')'; var translate = 'translate(0,0)'; if (velocity) { translate = 'translate(' + (velocity.x) + 'px, ' + (velocity.y) + 'px)'; } // Attach data to element ripple.setAttribute('data-hold', Date.now()); ripple.setAttribute('data-x', relativeX); ripple.setAttribute('data-y', relativeY); ripple.setAttribute('data-scale', scale); ripple.setAttribute('data-translate', translate); // Set ripple position var rippleStyle = { top: relativeY + 'px', left: relativeX + 'px' }; ripple.classList.add('waves-notransition'); ripple.setAttribute('style', convertStyle(rippleStyle)); ripple.classList.remove('waves-notransition'); // Scale the ripple rippleStyle['-webkit-transform'] = scale + ' ' + translate; rippleStyle['-moz-transform'] = scale + ' ' + translate; rippleStyle['-ms-transform'] = scale + ' ' + translate; rippleStyle['-o-transform'] = scale + ' ' + translate; rippleStyle.transform = scale + ' ' + translate; rippleStyle.opacity = '1'; var duration = e.type === 'mousemove' ? 2500 : Effect.duration; rippleStyle['-webkit-transition-duration'] = duration + 'ms'; rippleStyle['-moz-transition-duration'] = duration + 'ms'; rippleStyle['-o-transition-duration'] = duration + 'ms'; rippleStyle['transition-duration'] = duration + 'ms'; ripple.setAttribute('style', convertStyle(rippleStyle)); }, hide: function(e, element) { element = element || this; var ripples = element.getElementsByClassName('waves-rippling'); for (var i = 0, len = ripples.length; i < len; i++) { removeRipple(e, element, ripples[i]); } if (isTouchAvailable) { element.removeEventListener('touchend', Effect.hide); element.removeEventListener('touchcancel', Effect.hide); } element.removeEventListener('mouseup', Effect.hide); element.removeEventListener('mouseleave', Effect.hide); } }; /** * Collection of wrapper for HTML element that only have single tag * like <input> and <img> */ var TagWrapper = { // Wrap <input> tag so it can perform the effect input: function(element) { var parent = element.parentNode; // If input already have parent just pass through if (parent.tagName.toLowerCase() === 'i' && parent.classList.contains('waves-effect')) { return; } // Put element class and style to the specified parent var wrapper = document.createElement('i'); wrapper.className = element.className + ' waves-input-wrapper'; element.className = 'waves-button-input'; // Put element as child parent.replaceChild(wrapper, element); wrapper.appendChild(element); // Apply element color and background color to wrapper var elementStyle = window.getComputedStyle(element, null); var color = elementStyle.color; var backgroundColor = elementStyle.backgroundColor; wrapper.setAttribute('style', 'color:' + color + ';background:' + backgroundColor); element.setAttribute('style', 'background-color:rgba(0,0,0,0);'); }, // Wrap <img> tag so it can perform the effect img: function(element) { var parent = element.parentNode; // If input already have parent just pass through if (parent.tagName.toLowerCase() === 'i' && parent.classList.contains('waves-effect')) { return; } // Put element as child var wrapper = document.createElement('i'); parent.replaceChild(wrapper, element); wrapper.appendChild(element); } }; /** * Hide the effect and remove the ripple. Must be * a separate function to pass the JSLint... */ function removeRipple(e, el, ripple) { // Check if the ripple still exist if (!ripple) { return; } ripple.classList.remove('waves-rippling'); var relativeX = ripple.getAttribute('data-x'); var relativeY = ripple.getAttribute('data-y'); var scale = ripple.getAttribute('data-scale'); var translate = ripple.getAttribute('data-translate'); // Get delay beetween mousedown and mouse leave var diff = Date.now() - Number(ripple.getAttribute('data-hold')); var delay = 350 - diff; if (delay < 0) { delay = 0; } if (e.type === 'mousemove') { delay = 150; } // Fade out ripple after delay var duration = e.type === 'mousemove' ? 2500 : Effect.duration; setTimeout(function() { var style = { top: relativeY + 'px', left: relativeX + 'px', opacity: '0', // Duration '-webkit-transition-duration': duration + 'ms', '-moz-transition-duration': duration + 'ms', '-o-transition-duration': duration + 'ms', 'transition-duration': duration + 'ms', '-webkit-transform': scale + ' ' + translate, '-moz-transform': scale + ' ' + translate, '-ms-transform': scale + ' ' + translate, '-o-transform': scale + ' ' + translate, 'transform': scale + ' ' + translate }; ripple.setAttribute('style', convertStyle(style)); setTimeout(function() { try { el.removeChild(ripple); } catch (e) { return false; } }, duration); }, delay); } /** * Disable mousedown event for 500ms during and after touch */ var TouchHandler = { /* uses an integer rather than bool so there's no issues with * needing to clear timeouts if another touch event occurred * within the 500ms. Cannot mouseup between touchstart and * touchend, nor in the 500ms after touchend. */ touches: 0, allowEvent: function(e) { var allow = true; if (/^(mousedown|mousemove)$/.test(e.type) && TouchHandler.touches) { allow = false; } return allow; }, registerEvent: function(e) { var eType = e.type; if (eType === 'touchstart') { TouchHandler.touches += 1; // push } else if (/^(touchend|touchcancel)$/.test(eType)) { setTimeout(function() { if (TouchHandler.touches) { TouchHandler.touches -= 1; // pop after 500ms } }, 500); } } }; /** * Delegated click handler for .waves-effect element. * returns null when .waves-effect element not in "click tree" */ function getWavesEffectElement(e) { if (TouchHandler.allowEvent(e) === false) { return null; } var element = null; var target = e.target || e.srcElement; while (target.parentElement) { if ( (!(target instanceof SVGElement)) && target.classList.contains('waves-effect')) { element = target; break; } target = target.parentElement; } return element; } /** * Bubble the click and show effect if .waves-effect elem was found */ function showEffect(e) { // Disable effect if element has "disabled" property on it // In some cases, the event is not triggered by the current element // if (e.target.getAttribute('disabled') !== null) { // return; // } var element = getWavesEffectElement(e); if (element !== null) { // Make it sure the element has either disabled property, disabled attribute or 'disabled' class if (element.disabled || element.getAttribute('disabled') || element.classList.contains('disabled')) { return; } TouchHandler.registerEvent(e); if (e.type === 'touchstart' && Effect.delay) { var hidden = false; var timer = setTimeout(function () { timer = null; Effect.show(e, element); }, Effect.delay); var hideEffect = function(hideEvent) { // if touch hasn't moved, and effect not yet started: start effect now if (timer) { clearTimeout(timer); timer = null; Effect.show(e, element); } if (!hidden) { hidden = true; Effect.hide(hideEvent, element); } removeListeners(); }; var touchMove = function(moveEvent) { if (timer) { clearTimeout(timer); timer = null; } hideEffect(moveEvent); removeListeners(); }; element.addEventListener('touchmove', touchMove, false); element.addEventListener('touchend', hideEffect, false); element.addEventListener('touchcancel', hideEffect, false); var removeListeners = function() { element.removeEventListener('touchmove', touchMove); element.removeEventListener('touchend', hideEffect); element.removeEventListener('touchcancel', hideEffect); }; } else { Effect.show(e, element); if (isTouchAvailable) { element.addEventListener('touchend', Effect.hide, false); element.addEventListener('touchcancel', Effect.hide, false); } element.addEventListener('mouseup', Effect.hide, false); element.addEventListener('mouseleave', Effect.hide, false); } } } Waves.init = function(options) { var body = document.body; options = options || {}; if ('duration' in options) { Effect.duration = options.duration; } if ('delay' in options) { Effect.delay = options.delay; } if (isTouchAvailable) { body.addEventListener('touchstart', showEffect, false); body.addEventListener('touchcancel', TouchHandler.registerEvent, false); body.addEventListener('touchend', TouchHandler.registerEvent, false); } body.addEventListener('mousedown', showEffect, false); }; /** * Attach Waves to dynamically loaded inputs, or add .waves-effect and other * waves classes to a set of elements. Set drag to true if the ripple mouseover * or skimming effect should be applied to the elements. */ Waves.attach = function(elements, classes) { elements = getWavesElements(elements); if (toString.call(classes) === '[object Array]') { classes = classes.join(' '); } classes = classes ? ' ' + classes : ''; var element, tagName; for (var i = 0, len = elements.length; i < len; i++) { element = elements[i]; tagName = element.tagName.toLowerCase(); if (['input', 'img'].indexOf(tagName) !== -1) { TagWrapper[tagName](element); element = element.parentElement; } if (element.className.indexOf('waves-effect') === -1) { element.className += ' waves-effect' + classes; } } }; /** * Cause a ripple to appear in an element via code. */ Waves.ripple = function(elements, options) { elements = getWavesElements(elements); var elementsLen = elements.length; options = options || {}; options.wait = options.wait || 0; options.position = options.position || null; // default = centre of element if (elementsLen) { var element, pos, off, centre = {}, i = 0; var mousedown = { type: 'mousedown', button: 1 }; var hideRipple = function(mouseup, element) { return function() { Effect.hide(mouseup, element); }; }; for (; i < elementsLen; i++) { element = elements[i]; pos = options.position || { x: element.clientWidth / 2, y: element.clientHeight / 2 }; off = offset(element); centre.x = off.left + pos.x; centre.y = off.top + pos.y; mousedown.pageX = centre.x; mousedown.pageY = centre.y; Effect.show(mousedown, element); if (options.wait >= 0 && options.wait !== null) { var mouseup = { type: 'mouseup', button: 1 }; setTimeout(hideRipple(mouseup, element), options.wait); } } } }; /** * Remove all ripples from an element. */ Waves.calm = function(elements) { elements = getWavesElements(elements); var mouseup = { type: 'mouseup', button: 1 }; for (var i = 0, len = elements.length; i < len; i++) { Effect.hide(mouseup, elements[i]); } }; /** * Deprecated API fallback */ Waves.displayEffect = function(options) { console.error('Waves.displayEffect() has been deprecated and will be removed in future version. Please use Waves.init() to initialize Waves effect'); Waves.init(options); }; return Waves; }); /* WEBPACK VAR INJECTION */}.call(this, __webpack_require__("c8ba"))) /***/ }), /***/ "ded2": /***/ (function(module, exports, __webpack_require__) { // extracted by mini-css-extract-plugin /***/ }), /***/ "fb15": /***/ (function(module, __webpack_exports__, __webpack_require__) { "use strict"; __webpack_require__.r(__webpack_exports__); // CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/setPublicPath.js // This file is imported into lib/wc client bundles. if (typeof window !== 'undefined') { var currentScript = window.document.currentScript if (true) { var getCurrentScript = __webpack_require__("8875") currentScript = getCurrentScript() // for backward compatibility, because previously we directly included the polyfill if (!('currentScript' in document)) { Object.defineProperty(document, 'currentScript', { get: getCurrentScript }) } } var src = currentScript && currentScript.src.match(/(.+\/)[^/]+\.js(\?.*)?$/) if (src) { __webpack_require__.p = src[1] // eslint-disable-line } } // Indicate to webpack that this file can be concatenated /* harmony default export */ var setPublicPath = (null); // EXTERNAL MODULE: ./src/css/index.sass var css = __webpack_require__("ded2"); // CONCATENATED MODULE: ./src/directives/waves-directive.js /** * @author: Isnur MSM <isnurmsm@gmail.com> * @tutorial: https://isnur.github.io/vue-waves-effect/ */ var Waves = __webpack_require__("c9d5"); /* harmony default export */ var waves_directive = ({ name: 'waves', config: {}, install(Vue, options) { Vue.mixin({ created: function () { Waves.init(options); } }); Vue.directive('waves', { inserted(el, binding, vnode, oldVnode) { const classes = Object.keys(binding.modifiers).map(function (val) { return `waves-${val}`; }); Waves.attach(el, classes); }, bind(el, binding, vnode, oldVnode) { if (binding.arg === 'hover') { el.addEventListener('mouseenter', function () { if (el.tagName === 'IMG' || el.tagName === 'INPUT') { Waves.ripple(el.parentElement, { wait: 0 }); } else { Waves.ripple(el, { wait: 0 }); } }); } }, unbind(el, binding, vnode, oldVnode) { try { document.querySelectorAll('.waves-ripple').forEach(e => e.remove()); } catch (e) { console.log(e); } }, componentUpdated(el, binding, vnode, oldVnode) { try { document.querySelectorAll('.waves-ripple').forEach(e => e.remove()); } catch (e) { console.log(e); } } }); } }); // CONCATENATED MODULE: ./src/index.js /* harmony default export */ var src_0 = (waves_directive); // CONCATENATED MODULE: ./node_modules/@vue/cli-service/lib/commands/build/entry-lib.js /* harmony default export */ var entry_lib = __webpack_exports__["default"] = (src_0); /***/ }) /******/ })["default"]; }); //# sourceMappingURL=vueWavesEffect.umd.js.map