├── .editorconfig ├── .gitignore ├── .npmignore ├── FUNDING.yml ├── LICENSE.md ├── README.md ├── bower.json ├── build ├── mojs-player.js └── mojs-player.min.js ├── css ├── assets │ ├── colors.postcss.css │ └── globals.postcss.css ├── blocks │ ├── button-switch.postcss.css │ ├── button-switch.postcss.css.json │ ├── button.postcss.css │ ├── button.postcss.css.json │ ├── handle.postcss.css │ ├── handle.postcss.css.json │ ├── hide-button.postcss.css │ ├── hide-button.postcss.css.json │ ├── icon-button.postcss.css │ ├── icon-button.postcss.css.json │ ├── icon-fork.postcss.css │ ├── icon-fork.postcss.css.json │ ├── icon.postcss.css │ ├── icon.postcss.css.json │ ├── label-button.postcss.css │ ├── label-button.postcss.css.json │ ├── mojs-player.postcss.css │ ├── mojs-player.postcss.css.json │ ├── opacity-switch.postcss.css │ ├── opacity-switch.postcss.css.json │ ├── play-button.postcss.css │ ├── play-button.postcss.css.json │ ├── player-slider.postcss.css │ ├── player-slider.postcss.css.json │ ├── player.postcss.css │ ├── repeat-button.postcss.css │ ├── repeat-button.postcss.css.json │ ├── slider.postcss.css │ ├── slider.postcss.css.json │ ├── speed-control.postcss.css │ ├── speed-control.postcss.css.json │ ├── stop-button.postcss.css │ ├── stop-button.postcss.css.json │ ├── track.postcss.css │ └── track.postcss.css.json ├── main.postcss.css └── main.postcss.css.json ├── gulpfile.js ├── index.html ├── js ├── components │ ├── bounds-button.babel.js │ ├── button-switch.babel.js │ ├── button.babel.js │ ├── handle.babel.js │ ├── hide-button.babel.js │ ├── icon-button.babel.js │ ├── icon-fork.babel.js │ ├── icon.babel.js │ ├── icons.babel.js │ ├── label-button.babel.js │ ├── module.babel.js │ ├── opacity-switch.babel.js │ ├── play-button.babel.js │ ├── player-slider.babel.js │ ├── repeat-button.babel.js │ ├── ripple.babel.js │ ├── slider.babel.js │ ├── speed-control.babel.js │ ├── stop-button.babel.js │ └── track.babel.js └── mojs-player.babel.js ├── lib ├── components │ ├── bounds-button.js │ ├── button-switch.js │ ├── button.js │ ├── handle.js │ ├── hide-button.js │ ├── icon-button.js │ ├── icon-fork.js │ ├── icon.js │ ├── icons.js │ ├── label-button.js │ ├── module.js │ ├── opacity-switch.js │ ├── play-button.js │ ├── player-slider.js │ ├── repeat-button.js │ ├── ripple.js │ ├── slider.js │ ├── speed-control.js │ ├── stop-button.js │ └── track.js └── mojs-player.js ├── logo.png ├── mockups ├── mojs-player.sketch └── mojs-player@x4.png ├── package-lock.json ├── package.json └── webpack.config.js /.editorconfig: -------------------------------------------------------------------------------- 1 | # top-most editorconfig file 2 | root = true 3 | 4 | # editor configuration 5 | [*] 6 | charset = utf-8 7 | end_of_line = lf 8 | indent_style = space 9 | indent_size = 2 10 | trim_trailing_whitespace = true 11 | insert_final_newline = true 12 | 13 | # preserve markdown line break 14 | [*.md] 15 | trim_trailing_whitespace = false 16 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | node_modules/ 2 | -------------------------------------------------------------------------------- /.npmignore: -------------------------------------------------------------------------------- 1 | mockups/ 2 | css/ 3 | lib/ 4 | js/ 5 | .editorconfig 6 | index.html 7 | bower.json 8 | gulpfile.js 9 | webpack.config.js 10 | -------------------------------------------------------------------------------- /FUNDING.yml: -------------------------------------------------------------------------------- 1 | # These are supported funding model platforms 2 | 3 | github: xavierfoucrier 4 | -------------------------------------------------------------------------------- /LICENSE.md: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2023 Oleg Solomka, Xavier Foucrier, Jonas Sandstedt 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # @mojs/player – [![npm](https://img.shields.io/npm/v/@mojs/player.svg)](https://www.npmjs.com/package/@mojs/player) 2 | 3 | GUI player to control your animations. 4 | 5 | ![@mojs/player](logo.png "@mojs/player") 6 | 7 | Player controls for [mojs](https://github.com/mojs/mojs). Intended to help you to craft `mojs` animation sequences. To be clear, this player is not needed to play `mojs` animations. It is just a debug tool that gives you the ability to: 8 | - control your sequences with `GUI` while working on them 9 | - it saves the current progress of your animation thus you don't loose the `focus` 10 | - it gives you `bounds` to constrain `focus point` of your animation 11 | - it gives you the control over the speed of animation 12 | - it gives you the ability to seek animations freely 13 | - it saves player's state and settings thus they not get lost when page reloaded 14 | 15 | ## Installation 16 | 17 | The `MojsPlayer` depends on `mojs >= 0.225.2` so make sure you link it first. 18 | 19 | ```console 20 | # cdn 21 | 22 | 23 | # npm 24 | npm i @mojs/player 25 | ``` 26 | 27 | Import `MojsPlayer` constructor to your code, depending on your environment: 28 | 29 | ```javascript 30 | const MojsPlayer = require('mojs-player').default; 31 | 32 | // or 33 | import MojsPlayer from '@mojs/player'; 34 | ``` 35 | 36 | > If you installed it with script link — you should have `MojsPlayer` global 37 | 38 | ## Usage 39 | 40 | Construct `MojsPlayer` and pass your main `Tween/Timeline` to the `add` option: 41 | 42 | ```javascript 43 | // create the timeline 44 | const mainTimeline = new mojs.Timeline({}); 45 | 46 | // add the timeline to the player 47 | const mojsPlayer = new MojsPlayer({ 48 | add: mainTimeline 49 | }); 50 | ``` 51 | 52 | > The `add` option is the **only required option** to launch: player's controls should appear at the bottom of the page when ready 53 | 54 | You can also set other player initial state: 55 | 56 | ```javascript 57 | const mojsPlayer = new MojsPlayer({ 58 | 59 | // required 60 | add: mainTimeline, 61 | 62 | // optionally 63 | className: '', // class name to add to main HTMLElement 64 | isSaveState: true, // determines if should preserve state on page reload 65 | isPlaying: false, // playback state 66 | progress: 0, // initial progress 67 | isRepeat: false, // determines if it should repeat after completion 68 | isBounds: false, // determines if it should have bounds 69 | leftBound: 0, // left bound position [0...1] 70 | rightBound: 1, // right bound position [0...1] 71 | isSpeed: false, // determines if speed control should be open 72 | speed: 1, // `speed` value 73 | isHidden: false, // determines if the player should be hidden 74 | precision: 0.1, // step size for player handle - for instance, after page reload - player should restore timeline progress - the whole timeline will be updated incrementally with the `precision` step size until the progress will be met. 75 | name: 'mojs-player', // name for the player - mainly used for localstorage identifier, use to distinguish between multiple local players 76 | onToggleHide(isHidden) { // should be called after user taps on the hide-button (isHidden is a boolean, indicating the visibility state of the player) 77 | if (isHidden) { 78 | // do something when player is invisible 79 | } else { 80 | // do something when player is visible 81 | } 82 | } 83 | }); 84 | ``` 85 | 86 | ## Shortcuts 87 | 88 | - `alt + p` - toggle `play`/`pause` playback state 89 | - `alt + - ` - decrease progress by `1/100` 90 | - `alt + +` - increase progress by `1/100` 91 | - `shift + alt + -` - decrease progress by `1/10` 92 | - `shift + alt + +` - increase progress by `1/10` 93 | - `alt + s` - `stop` playback 94 | - `alt + r` - toggle `repeat` state 95 | - `alt + b` - toggle `bounds` state 96 | - `alt + h` - toggle `show`/`hide` player state 97 | - `alt + q` - reset `speed` to `1x` 98 | - `alt + 2` - decrease `speed` by `1/50` 99 | - `alt + 3` - increase `speed` by `1/50` 100 | - `shift + alt + 2` - decrease `speed` by `1/10` 101 | - `shift + alt + 3` - increase `speed` by `1/10` 102 | 103 | 104 | ## Development 105 | 106 | Install [webpack](https://webpack.github.io/) globally: 107 | 108 | ```console 109 | [sudo] npm install webpack -g 110 | ``` 111 | 112 | Install dependencies with [npm](https://www.npmjs.com/): 113 | 114 | ```console 115 | [sudo] npm install 116 | ``` 117 | 118 | Run [webpack](https://webpack.github.io/): 119 | 120 | ```console 121 | webpack 122 | ``` 123 | 124 | Please make sure you are on the `dev` branch before making changes. 125 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "mojs-player", 3 | "version": "1.3.0", 4 | "description": "Player controls for [mojs](mojs.github.io). Intended to help you to craft `mojs` animation sequences.", 5 | "main": "build/mojs-player.min.js", 6 | "authors": ["Oleg Solomka"], 7 | "license": "MIT", 8 | "keywords": ["motion", "effects", "animation", "motion", "graphics", "player"], 9 | "homepage": "https://github.com/mojs/mojs-player", 10 | "moduleType": ["amd", "node", "es6", "globals"], 11 | "ignore": ["**/.*", "node_modules", "bower_components", "test", "tests"] 12 | } -------------------------------------------------------------------------------- /css/assets/colors.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | $c-purple: #3A0839; 3 | $c-orange: #FF512F; 4 | $c-white : #FFFFFF; 5 | -------------------------------------------------------------------------------- /css/assets/globals.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import './colors.postcss.css'; 3 | 4 | /*$PX: 1/16rem;*/ 5 | $PX: 1px; 6 | $GS: calc( 10 * $PX ); 7 | $BRADIUS: calc( 3 * $PX ); 8 | -------------------------------------------------------------------------------- /css/blocks/button-switch.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .button-switch { 5 | position: relative; 6 | display: inline-block; 7 | 8 | & > .icon { 9 | position: absolute; 10 | } 11 | 12 | &:after { 13 | content: ""; 14 | position: absolute; 15 | left: 0; 16 | top: 0; 17 | right: 0; 18 | bottom: 0; 19 | z-index: 1; 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /css/blocks/button-switch.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"button-switch":"_button-switch_1putg_4","icon":"_icon_1putg_8"} -------------------------------------------------------------------------------- /css/blocks/button.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .button { 5 | position: relative; 6 | width: calc( 35 * $PX ); 7 | height: calc( 40 * $PX ); 8 | cursor: pointer; 9 | fill: #FFF; 10 | display: inline-block; 11 | &__ripple { 12 | position: absolute; 13 | left: 0; 14 | right: 0; 15 | top: 0; 16 | bottom: 0; 17 | z-index: 5; 18 | overflow: hidden; 19 | &:after { 20 | content: ""; 21 | position: absolute; 22 | left: 0; 23 | right: 0; 24 | top: 0; 25 | bottom: 0; 26 | z-index: 1; 27 | cursor: pointer; 28 | } 29 | } 30 | &:hover { 31 | opacity: .85; 32 | } 33 | 34 | &:active { 35 | opacity: 1; 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /css/blocks/button.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"button":"_button_wb9ek_4","button__ripple":"_button__ripple_wb9ek_1"} -------------------------------------------------------------------------------- /css/blocks/handle.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | $handleHeight: 13; 5 | .handle { 6 | width: calc( $handleHeight * $PX ); 7 | height: calc( $handleHeight * $PX ); 8 | 9 | cursor: pointer; 10 | transform: translateX(0); 11 | backface-visibility: hidden; 12 | 13 | &__inner, 14 | &__shadow { 15 | position: absolute; 16 | left: 0; 17 | top: 0; 18 | z-index: 1; 19 | 20 | width: 100%; 21 | height: 100%; 22 | border-radius: 50%; 23 | cursor: pointer; 24 | /*transform: translateZ(0);*/ 25 | /*backface-visibility: hidden;*/ 26 | } 27 | 28 | &__inner { 29 | background: #FFF; 30 | } 31 | 32 | &__shadow { 33 | box-shadow: calc( $PX ) calc( $PX ) calc( 2*$PX ) black; 34 | opacity: .35; 35 | z-index: 0; 36 | } 37 | 38 | &:hover &__inner, 39 | &:hover &__shadow { 40 | transform: scale(1.1); 41 | } 42 | 43 | &:active &__inner { 44 | transform: scale(1.2); 45 | /*box-shadow: calc( $PX ) calc( $PX ) calc( 1*$PX ) rgba(0,0,0,.35);*/ 46 | } 47 | &:active &__shadow { 48 | opacity: .85; 49 | transform: scale(1); 50 | } 51 | 52 | $width: 9; 53 | $height: 20; 54 | &.is-bound { 55 | width: calc( $width * $PX ); 56 | height: calc( $height * $PX ); 57 | margin-left: calc( - $width * $PX ); 58 | margin-top: calc( - $height/2 * $PX ); 59 | } 60 | &.is-bound &__inner { 61 | background: $c-orange; 62 | $lineHeight: 40; 63 | &:after { 64 | content: ''; 65 | position: absolute; 66 | right: 0; 67 | top: 50%; 68 | margin-top: calc( - $lineHeight/2 * $PX ); 69 | width: calc( $PX ); 70 | height: calc( $lineHeight * $PX ); 71 | background: $c-orange; 72 | } 73 | } 74 | &.is-bound &__inner, 75 | &.is-bound &__shadow { 76 | border-top-left-radius: $BRADIUS; 77 | border-bottom-left-radius: $BRADIUS; 78 | border-top-right-radius: 0; 79 | border-bottom-right-radius: 0; 80 | } 81 | 82 | &.is-inversed { 83 | margin-left: 0; 84 | } 85 | &.is-inversed &__shadow { 86 | box-shadow: calc( - $PX ) calc( $PX ) calc( 2*$PX ) black; 87 | } 88 | &.is-inversed &__inner { 89 | border-top-left-radius: 0; 90 | border-bottom-left-radius: 0; 91 | border-top-right-radius: $BRADIUS; 92 | border-bottom-right-radius: $BRADIUS; 93 | &:after { 94 | right: auto; 95 | left: 0; 96 | } 97 | } 98 | } 99 | -------------------------------------------------------------------------------- /css/blocks/handle.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"handle":"_handle_8vrrs_5","handle__inner":"_handle__inner_8vrrs_1","handle__shadow":"_handle__shadow_8vrrs_1","is-bound":"_is-bound_8vrrs_54","is-inversed":"_is-inversed_8vrrs_82"} -------------------------------------------------------------------------------- /css/blocks/hide-button.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .hide-button { 5 | 6 | width: calc( 22 * $PX ); 7 | height: calc( 16 * $PX ); 8 | 9 | background: $c-purple; 10 | 11 | border-top-left-radius: $BRADIUS; 12 | border-top-right-radius: $BRADIUS; 13 | 14 | &__icon { 15 | position: absolute; 16 | left: 50%; 17 | top: 50%; 18 | width: calc( 8 * $PX ); 19 | height: calc( 8 * $PX ); 20 | margin-top: calc( 1 * $PX ); 21 | transform: translate( -50%, -50% ); 22 | } 23 | 24 | &.is-hidden &__icon { 25 | transform: translate( -50%, -65% ) rotate( 180deg ); 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /css/blocks/hide-button.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"hide-button":"_hide-button_aiv1o_4","hide-button__icon":"_hide-button__icon_aiv1o_1","is-hidden":"_is-hidden_aiv1o_24"} -------------------------------------------------------------------------------- /css/blocks/icon-button.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .icon-button { 5 | /* styles */ 6 | & .icon { 7 | position: absolute; 8 | left: 50%; 9 | top: 50%; 10 | transform: translate( -50%, -50% ); 11 | } 12 | } 13 | -------------------------------------------------------------------------------- /css/blocks/icon-button.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"icon-button":"_icon-button_qglug_4","icon":"_icon_qglug_4"} -------------------------------------------------------------------------------- /css/blocks/icon-fork.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .icon-fork { 5 | & > .icon { 6 | /*position: absolute;*/ 7 | opacity: 0; 8 | position: absolute; 9 | top: 50%; 10 | left: 50%; 11 | transform: translate( -50%, -50% ); 12 | } 13 | & > .icon:nth-of-type(3) { 14 | position: absolute; 15 | opacity: 1; 16 | } 17 | 18 | &.is-on > .icon:nth-of-type(2) { 19 | opacity: 1; 20 | } 21 | &.is-on > .icon:nth-of-type(3) { 22 | opacity: 0; 23 | } 24 | } 25 | -------------------------------------------------------------------------------- /css/blocks/icon-fork.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"icon-fork":"_icon-fork_1n6j9_4","icon":"_icon_1n6j9_4","is-on":"_is-on_1n6j9_18"} -------------------------------------------------------------------------------- /css/blocks/icon.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | $size: 12; 5 | .icon { 6 | position: relative; 7 | width: calc( 12 * $PX ); 8 | height: calc( 12 * $PX ); 9 | cursor: pointer; 10 | 11 | & > svg { 12 | position: absolute; 13 | left: 0; 14 | top: 0; 15 | width: 100%; 16 | height: 100%; 17 | fill: inherit; 18 | & > use { 19 | fill: inherit; 20 | } 21 | } 22 | 23 | &:after { 24 | content: ''; 25 | position: absolute; 26 | left: 0; 27 | top: 0; 28 | right: 0; 29 | bottom: 0; 30 | z-index: 1; 31 | } 32 | 33 | &.is-x2 { 34 | width: calc( 16*$PX ); 35 | height: calc( 16*$PX ); 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /css/blocks/icon.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"icon":"_icon_if24v_5","is-x2":"_is-x2_if24v_33"} -------------------------------------------------------------------------------- /css/blocks/label-button.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .label-button { 5 | font-family: Arial, sans-serif; 6 | font-size: calc( 9 * $PX ); 7 | letter-spacing: calc( .5* $PX ); 8 | color: white; 9 | &__label { 10 | position: absolute; 11 | left: 50%; 12 | top: 50%; 13 | transform: translate( -50%, -50% ); 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /css/blocks/label-button.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"label-button":"_label-button_1cxps_4","label-button__label":"_label-button__label_1cxps_1"} -------------------------------------------------------------------------------- /css/blocks/mojs-player.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .mojs-player { 5 | position: fixed; 6 | left: 0; 7 | bottom: 0; 8 | width: 100%; 9 | height: calc( 40 * $PX ); 10 | background: rgba( 58, 8, 57, .85 ); 11 | z-index: 100; 12 | 13 | * { 14 | box-sizing: border-box; 15 | } 16 | 17 | $btnWidth: 35; 18 | $btnCount: 5; 19 | $leftWidth: calc( $btnCount * $btnWidth * $PX ); 20 | &__left { 21 | position: absolute; 22 | left: 0; 23 | width: $leftWidth; 24 | } 25 | 26 | &__mid { 27 | position: absolute; 28 | left: $leftWidth; 29 | right: calc( $btnWidth/2 * $PX ); 30 | overflow: hidden; 31 | padding: 0 calc( 20 * $PX ); 32 | } 33 | 34 | &__right { 35 | position: absolute; 36 | right: 0; 37 | } 38 | 39 | &__hide-button { 40 | position: absolute; 41 | right: calc( 6 * $PX ); 42 | bottom: 100%; 43 | } 44 | 45 | &__mojs-logo { 46 | [data-component="icon"] { 47 | fill: $c-orange; 48 | } 49 | } 50 | 51 | &.is-hidden { 52 | transform: translateY(100%); 53 | } 54 | &.is-transition { 55 | transition: all .15s ease-out; 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /css/blocks/mojs-player.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"mojs-player":"_mojs-player_12g93_4","mojs-player__left":"_mojs-player__left_12g93_1","mojs-player__mid":"_mojs-player__mid_12g93_1","mojs-player__right":"_mojs-player__right_12g93_1","mojs-player__hide-button":"_mojs-player__hide-button_12g93_1","mojs-player__mojs-logo":"_mojs-player__mojs-logo_12g93_1","is-hidden":"_is-hidden_12g93_51","is-transition":"_is-transition_12g93_54"} -------------------------------------------------------------------------------- /css/blocks/opacity-switch.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .opacity-switch { 5 | opacity: .5; 6 | .icon { 7 | position: absolute; 8 | left: 50%; 9 | top: 50%; 10 | transform: translate(-50%, -50%); 11 | } 12 | &:hover { 13 | opacity: .4; 14 | } 15 | &.is-on { 16 | opacity: 1; 17 | &:hover { 18 | opacity: .85; 19 | } 20 | } 21 | 22 | 23 | 24 | 25 | } 26 | -------------------------------------------------------------------------------- /css/blocks/opacity-switch.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"opacity-switch":"_opacity-switch_17z5s_4","icon":"_icon_17z5s_6","is-on":"_is-on_17z5s_15"} -------------------------------------------------------------------------------- /css/blocks/play-button.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .play-button { 5 | /* styles */ 6 | } 7 | -------------------------------------------------------------------------------- /css/blocks/play-button.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"play-button":"_play-button_16uj5_4"} -------------------------------------------------------------------------------- /css/blocks/player-slider.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | /*@import './handle.postcss.css';*/ 4 | 5 | $height: 40; 6 | .player-slider { 7 | /*overflow: hidden;*/ 8 | height: calc( $height * $PX ); 9 | & > div { 10 | position: absolute; 11 | left: 0; 12 | top: 0; 13 | z-index: 2; 14 | } 15 | & .slider { 16 | z-index: 1; 17 | height: 100%; 18 | } 19 | 20 | } 21 | -------------------------------------------------------------------------------- /css/blocks/player-slider.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"player-slider":"_player-slider_1h9vh_6","slider":"_slider_1h9vh_15"} -------------------------------------------------------------------------------- /css/blocks/player.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | .mojs-player { 3 | background-color: color(#3A0839 alpha(85%)); 4 | height: calc( 40 * $PX ); 5 | width: calc( 100 * $PX ); 6 | display: inline-block; 7 | 8 | position: fixed; 9 | bottom: calc( 1.5 * $GS ); 10 | left: 50%; 11 | transform: translateX( -50% ); 12 | border-radius: $BRADIUS; 13 | 14 | box-shadow: calc($PX) calc($PX) calc( 1*$PX ) rgba(0,0,0,.25) 15 | } 16 | -------------------------------------------------------------------------------- /css/blocks/repeat-button.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .repeat-button { 5 | /* styles */ 6 | } 7 | -------------------------------------------------------------------------------- /css/blocks/repeat-button.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"repeat-button":"_repeat-button_xhfpi_4"} -------------------------------------------------------------------------------- /css/blocks/slider.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | /*@import './handle.postcss.css';*/ 4 | 5 | $height: 30; 6 | .slider { 7 | position: relative; 8 | width: 100%; 9 | height: calc( $height * $PX ); 10 | 11 | &__inner { 12 | width: 100%; 13 | height: 100%; 14 | position: relative; 15 | } 16 | 17 | & .handle, 18 | & .progress-handle { 19 | z-index: 3; 20 | position: absolute; 21 | top: 50%; 22 | } 23 | $handleHeight: 13; 24 | & .progress-handle { 25 | left: 0; 26 | margin-left: calc( - $handleHeight/2 * $PX ); 27 | margin-top: calc( - $handleHeight/2 * $PX ); 28 | } 29 | 30 | & .track { 31 | z-index: 2; 32 | } 33 | 34 | &.is-y { 35 | width: calc( $height * $PX ); 36 | height: 100%; 37 | 38 | .handle { 39 | left: 50%; 40 | top: auto; 41 | bottom: 0; 42 | margin-top: 0; 43 | margin-bottom: calc( -$handleHeight/2 * $PX ); 44 | } 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /css/blocks/slider.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"slider":"_slider_1e5my_6","slider__inner":"_slider__inner_1e5my_1","handle":"_handle_1e5my_17","progress-handle":"_progress-handle_1e5my_18","track":"_track_1e5my_30","is-y":"_is-y_1e5my_34"} -------------------------------------------------------------------------------- /css/blocks/speed-control.postcss.css: -------------------------------------------------------------------------------- 1 | @import '../assets/globals.postcss.css'; 2 | 3 | .speed-control { 4 | position: relative; 5 | display: inline-block; 6 | height: calc( 40 * $PX ); 7 | 8 | $pad: 20; 9 | &__slider { 10 | position: absolute; 11 | bottom: 100%; 12 | left: calc( 3 * $PX ); 13 | width: calc( 30 * $PX ); 14 | height: calc( (80 + 2*$pad) * $PX ); 15 | padding-top: calc( $pad * $PX ); 16 | padding-bottom: calc( $pad * $PX ); 17 | 18 | border-top-right-radius: $BRADIUS; 19 | border-top-left-radius: $BRADIUS; 20 | 21 | background: $c-purple; 22 | 23 | $translateSize: calc( -99999999 * $PX ); 24 | transform: translate($translateSize, $translateSize); 25 | backface-visibility: hidden; 26 | 27 | &:before, 28 | &:after { 29 | content: ''; 30 | position: absolute; 31 | top: 50%; 32 | width: calc( 3*$PX ); 33 | height: calc( $PX ); 34 | background: #FFF; 35 | } 36 | $shift: calc( 5*$PX ); 37 | &:before { 38 | left: $shift; 39 | } 40 | &:after { 41 | right: $shift; 42 | } 43 | } 44 | &__button { 45 | border: 1px solid cyan; 46 | } 47 | 48 | &.is-on &__slider { 49 | transform: translate(0, 0); 50 | } 51 | } 52 | -------------------------------------------------------------------------------- /css/blocks/speed-control.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"speed-control":"_speed-control_1jd3z_3","speed-control__slider":"_speed-control__slider_1jd3z_1","speed-control__button":"_speed-control__button_1jd3z_1","is-on":"_is-on_1jd3z_48"} -------------------------------------------------------------------------------- /css/blocks/stop-button.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | .stop-button { 5 | /* styles */ 6 | } 7 | -------------------------------------------------------------------------------- /css/blocks/stop-button.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"stop-button":"_stop-button_lpa7l_4"} -------------------------------------------------------------------------------- /css/blocks/track.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import '../assets/globals.postcss.css'; 3 | 4 | $height: 40; 5 | .track { 6 | position: relative; 7 | height: 100%; 8 | 9 | &__track { 10 | position: absolute; 11 | top: 50%; 12 | left: 0; 13 | 14 | width: 100%; 15 | height: calc( $PX ); 16 | 17 | background: #FFF; 18 | box-shadow: calc( $PX ) calc( $PX ) calc( $PX ) rgba(0,0,0,.5); 19 | 20 | &:after { 21 | content: ''; 22 | position: absolute; 23 | left: 0; 24 | top: calc( - $height/2 * $PX ); 25 | width: 100%; 26 | height: calc( $height * $PX ); 27 | cursor: pointer; 28 | /*background-color: yellow;*/ 29 | } 30 | } 31 | 32 | &__track-progress { 33 | position: absolute; 34 | left: 0; 35 | top: 50%; 36 | margin-top: calc( -1 * $PX ); 37 | height: calc( 3*$PX ); 38 | width: 0.0625em; 39 | /*background: $c-orange;*/ 40 | background: $c-white; 41 | z-index: 1; 42 | transform-origin: left center; 43 | &:after { 44 | /*content: '';*/ 45 | position: absolute; 46 | left: 0; 47 | top: calc( - $height/2 * $PX ); 48 | width: 100%; 49 | height: calc( $height * $PX ); 50 | cursor: pointer; 51 | backface-visibility: hidden; 52 | } 53 | } 54 | 55 | &__ripple { 56 | position: absolute; 57 | left: 0; 58 | top: 0; 59 | right: 0; 60 | bottom: 0; 61 | overflow: hidden; 62 | /*background: black;*/ 63 | /*z-index: 1;*/ 64 | } 65 | 66 | &.is-inversed { 67 | left: auto; 68 | right: 0; 69 | } 70 | 71 | &.is-inversed &__track-progress { 72 | transform-origin: right center; 73 | } 74 | 75 | &.is-bound &__track-progress { 76 | background: $c-orange; 77 | } 78 | 79 | &.is-y &__track { 80 | top: 0; 81 | left: 50%; 82 | 83 | height: 100%; 84 | width: calc( $PX ); 85 | 86 | /*box-shadow: calc( $PX ) calc( $PX ) calc( $PX ) rgba(0,0,0,.5); */ 87 | } 88 | 89 | 90 | } 91 | -------------------------------------------------------------------------------- /css/blocks/track.postcss.css.json: -------------------------------------------------------------------------------- 1 | {"track":"_track_1dpwb_5","track__track":"_track__track_1dpwb_1","track__track-progress":"_track__track-progress_1dpwb_1","track__ripple":"_track__ripple_1dpwb_1","is-inversed":"_is-inversed_1dpwb_66","is-bound":"_is-bound_1dpwb_75","is-y":"_is-y_1dpwb_79"} -------------------------------------------------------------------------------- /css/main.postcss.css: -------------------------------------------------------------------------------- 1 | 2 | @import 'assets/globals.postcss.css'; 3 | 4 | 5 | -------------------------------------------------------------------------------- /css/main.postcss.css.json: -------------------------------------------------------------------------------- 1 | {} -------------------------------------------------------------------------------- /gulpfile.js: -------------------------------------------------------------------------------- 1 | var gulp = require('gulp'); 2 | var fs = require('fs'); 3 | var livereload = require('gulp-livereload'); 4 | var changed = require('gulp-changed'); 5 | 6 | var plumber = require('gulp-plumber'); 7 | var concat = require('gulp-concat'); 8 | var rename = require('gulp-rename'); 9 | var uglify = require('gulp-uglify'); 10 | var sequence = require('run-sequence'); 11 | 12 | var insert = require('gulp-insert'); 13 | var jeditor = require("gulp-json-editor"); 14 | var shell = require("gulp-shell"); 15 | var babel = require("gulp-babel"); 16 | 17 | var devFolder = '', distFolder = '', currentVersion = 0; 18 | var distMoFile = devFolder + 'build/mojs-player.js'; 19 | var libMainFile = devFolder + 'lib/mojs-player.js'; 20 | 21 | var paths = { 22 | src: { 23 | babel: devFolder + 'js/**/*.babel.js', 24 | index: devFolder + 'index.jade', 25 | css: devFolder + 'css/**/*.styl', 26 | tests: distFolder + 'spec/**/*.coffee' 27 | }, 28 | dist:{ 29 | js: distFolder + 'js/', 30 | index: distFolder, 31 | css: distFolder + 'css/', 32 | tests: distFolder + 'spec/' 33 | } 34 | } 35 | 36 | var credits = '' 37 | 38 | gulp.task('babel-lib', function(e){ 39 | return gulp.src(paths.src.babel) 40 | .pipe(plumber()) 41 | .pipe(babel({ presets: ['es2015-loose'], plugins: [ 'transform-runtime' ] })) 42 | .pipe(rename(function (path) { 43 | return path.basename = path.basename.replace('.babel', ''); 44 | }) 45 | ).pipe(gulp.dest('lib/')) 46 | }); 47 | 48 | gulp.task('minify', function() { 49 | return gulp.src(distMoFile) 50 | .pipe(plumber()) 51 | .pipe(livereload()) 52 | .pipe(insert.transform(function(contents) { 53 | return credits + contents; 54 | })) 55 | .pipe(gulp.dest('./build')) 56 | .pipe(uglify()) 57 | .pipe(insert.transform(function(contents) { 58 | return credits + contents; 59 | })) 60 | .pipe(rename('mojs-player.min.js')) 61 | .pipe(gulp.dest('./build')) 62 | }); 63 | 64 | gulp.task('attribute-lib', function() { 65 | return gulp.src(libMainFile) 66 | .pipe(plumber()) 67 | .pipe(insert.transform(function(contents) { 68 | return credits + contents; 69 | })) 70 | .pipe(gulp.dest('./lib')) 71 | }); 72 | 73 | gulp.task('update-version', function() { 74 | sequence('get-current-version', 'update-bower-version', 'update-main-file-version'); 75 | }); 76 | 77 | gulp.task('get-current-version', function(e){ 78 | return gulp.src('package.json') 79 | .pipe(plumber()) 80 | .pipe(jeditor(function (json) { 81 | currentVersion = json.version; 82 | credits = '/*! \n\t:: MojsPlayer :: Player controls for [mojs](mojs.github.io). Intended to help you to craft `mojs` animation sequences.\n\tOleg Solomka @LegoMushroom 2021 MIT\n\t' + currentVersion + ' \n*/\n\n' 83 | return json; 84 | })) 85 | }); 86 | 87 | gulp.task('update-bower-version', function(e){ 88 | return gulp.src('bower.json') 89 | .pipe(plumber()) 90 | .pipe(jeditor(function (json) { 91 | json.version = currentVersion; 92 | return json; 93 | })) 94 | .pipe(gulp.dest('')) 95 | }); 96 | 97 | gulp.task('update-main-file-version', function(e){ 98 | return gulp.src('js/mojs-player.babel.js') 99 | .pipe(plumber()) 100 | .pipe(insert.transform(function(contents) { 101 | var newString = 'revision = \''+currentVersion+'\''; 102 | return contents 103 | .replace(/revision\s+?\=\s+?(\'|\")\d+\.\d+\.+\d+(\'|\")/i, newString); 104 | })) 105 | .pipe(gulp.dest('js/')) 106 | }); 107 | 108 | gulp.task('default', function(){ 109 | livereload.listen(); 110 | gulp.run('get-current-version'); 111 | gulp.watch(paths.src.babel, [ 'babel-lib' ]); 112 | gulp.watch(distMoFile, [ 'minify' ]); 113 | gulp.watch(libMainFile, [ 'attribute-lib' ]); 114 | gulp.watch('package.json', ['update-version']); 115 | }); 116 | -------------------------------------------------------------------------------- /index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | mo · js player 6 | 7 | 8 | 9 | 24 | 25 |
26 | 27 |
28 |
29 |
30 |
31 |
32 | 33 | 34 | 35 | 36 | 60 | 61 | 62 | 63 | -------------------------------------------------------------------------------- /js/components/bounds-button.babel.js: -------------------------------------------------------------------------------- 1 | import RepeatButton from './repeat-button'; 2 | 3 | // require('css/blocks/repeat-button.postcss.css'); 4 | // let CLASSES = require('css/blocks/repeat-button.postcss.css.json'); 5 | 6 | class BoundsButton extends RepeatButton { 7 | /* 8 | Method to declare defaults. 9 | @private 10 | @overrides @ RepeatButton 11 | */ 12 | _declareDefaults () { 13 | super._declareDefaults(); 14 | this._defaults.icon = 'bounds'; 15 | this._defaults.title = 'progress bounds (alt + b)'; 16 | } 17 | } 18 | 19 | export default BoundsButton; 20 | -------------------------------------------------------------------------------- /js/components/button-switch.babel.js: -------------------------------------------------------------------------------- 1 | import Button from './button'; 2 | 3 | require('../../css/blocks/button-switch.postcss.css'); 4 | let CLASSES = require('../../css/blocks/button-switch.postcss.css.json'); 5 | 6 | class ButtonSwitch extends Button { 7 | /* 8 | Method to declare _defaults. 9 | @private 10 | @overrides @ Button 11 | */ 12 | _declareDefaults () { 13 | super._declareDefaults(); 14 | this._defaults.isOn = false; 15 | this._defaults.onStateChange = null; 16 | } 17 | /* 18 | Method to set the state to `true`. 19 | @public 20 | @param {Boolean} If should invoke callback. 21 | */ 22 | on ( isCallback = true ) { 23 | // set to true because the next step is toggle 24 | this._props.isOn = true; 25 | this._reactOnStateChange( isCallback ); 26 | } 27 | /* 28 | Method to set the state to `false`. 29 | @public 30 | @param {Boolean} If should invoke callback. 31 | */ 32 | off ( isCallback = true ) { 33 | // set to true because the next step is toggle 34 | this._props.isOn = false; 35 | this._reactOnStateChange( isCallback ); 36 | } 37 | 38 | // --- 39 | 40 | /* 41 | Initial render method. 42 | @private 43 | @overrides @ Button 44 | @returns this 45 | */ 46 | _render () { 47 | super._render(); 48 | this.el.classList.add( CLASSES[ 'button-switch' ] ); 49 | this._setState(); 50 | this._reactOnStateChange(); 51 | } 52 | /* 53 | Method to invoke onPointerUp callback if excist. 54 | @private 55 | @overrides @ Button 56 | @param {Object} Original event object. 57 | */ 58 | _pointerUp ( e ) { 59 | if ( !this.wasTouched ) { 60 | this.wasTouched = false; 61 | e.stopPropagation(); 62 | return; 63 | } 64 | this._changeState(); 65 | super._pointerUp( e ); 66 | } 67 | /* 68 | Method to switch icons. 69 | @private 70 | */ 71 | _changeState () { 72 | this._props.isOn = !this._props.isOn; 73 | this._reactOnStateChange(); 74 | } 75 | /* 76 | Method to react on state change. 77 | @private 78 | @param {Boolean} If should invoke callback. 79 | */ 80 | _reactOnStateChange ( isCallback = true ) { 81 | if ( isCallback ) { 82 | this._callIfFunction( this._props.onStateChange, this._props.isOn ); 83 | } 84 | this._setState(); 85 | } 86 | /* 87 | Method that have been called on switch state change. 88 | @private 89 | */ 90 | _setState () { 91 | // console.log('change'); 92 | } 93 | 94 | } 95 | 96 | export default ButtonSwitch; 97 | -------------------------------------------------------------------------------- /js/components/button.babel.js: -------------------------------------------------------------------------------- 1 | import Module from './module'; 2 | import HammerJS from 'hammerjs'; 3 | import Ripple from './ripple'; 4 | 5 | require('../../css/blocks/button.postcss.css'); 6 | let CLASSES = require('../../css/blocks/button.postcss.css.json'); 7 | 8 | class Button extends Module { 9 | /* 10 | Method to declare defaults for the module. 11 | @private 12 | @overrides @ Module 13 | */ 14 | _declareDefaults () { 15 | super._declareDefaults() 16 | this._defaults.link = null; 17 | this._defaults.title = ''; 18 | this._defaults.target = null; 19 | this._defaults.onPointerDown = null; 20 | this._defaults.onPointerUp = null; 21 | this._defaults.onDoubleTap = null; 22 | } 23 | /* 24 | Initial render method. 25 | @private 26 | @overrides @ Module 27 | */ 28 | _render () { 29 | let p = this._props, 30 | className = 'button', 31 | tagName = ( p.link != null ) ? 'a' : 'div'; 32 | 33 | this._addMainElement( tagName ); 34 | this.el.classList.add( CLASSES[ className ] ); 35 | this.el.setAttribute( 'title', p.title ); 36 | p.link && this.el.setAttribute( 'href', p.link ); 37 | p.link && p.target && this.el.setAttribute( 'target', p.target ); 38 | this._addListeners(); 39 | 40 | this._createRipple(); 41 | } 42 | /* 43 | Method to create ripple. 44 | @private 45 | */ 46 | _createRipple () { 47 | this.ripple = new Ripple({ 48 | className: CLASSES[ `button__ripple` ], 49 | parent: this.el 50 | }); 51 | } 52 | /* 53 | Method to add event listeners to the icon. 54 | @private 55 | */ 56 | _addListeners () { 57 | this._addPointerDownEvent( this.el, this._pointerDown.bind( this ) ); 58 | this._addPointerUpEvent( this.el, this._pointerUp.bind( this ) ); 59 | this._addPointerUpEvent( document, this._pointerCancel.bind( this ) ); 60 | HammerJS(this.el).on('doubletap', this._doubleTap.bind( this ) ); 61 | } 62 | /* 63 | Method to invoke onPointerDown callback if exist. 64 | @private 65 | @param {Object} Original event object. 66 | */ 67 | _pointerDown ( e ) { 68 | this.wasTouched = true; 69 | this._callIfFunction( this._props.onPointerDown ); 70 | this.ripple._hold( e ); 71 | } 72 | /* 73 | Method to invoke onPointerUp callback if exist. 74 | @private 75 | @param {Object} Original event object. 76 | */ 77 | _pointerUp ( e ) { 78 | if ( !this.wasTouched ) { e.stopPropagation(); return; } 79 | 80 | this.wasTouched = false; 81 | this._callIfFunction( this._props.onPointerUp ); 82 | this.ripple._release(); 83 | e.preventDefault(); 84 | return false; 85 | } 86 | /* 87 | Method to invoke onPointerCancel callback if exist. 88 | @private 89 | @param {Object} Original event object. 90 | */ 91 | _pointerCancel ( e ) { 92 | if ( !this.wasTouched ) { return; }; 93 | this.wasTouched = false; 94 | this.ripple._cancel(); 95 | } 96 | /* 97 | Method to invoke onDoubleTap callback if exist. 98 | @private 99 | @param {Object} Original event object. 100 | */ 101 | _doubleTap ( e ) { 102 | this._callIfFunction( this._props.onDoubleTap ); 103 | } 104 | } 105 | 106 | export default Button; 107 | -------------------------------------------------------------------------------- /js/components/handle.babel.js: -------------------------------------------------------------------------------- 1 | import Module from './module'; 2 | import HammerJS from 'hammerjs'; 3 | 4 | require('../../css/blocks/handle.postcss.css'); 5 | let CLASSES = require('../../css/blocks/handle.postcss.css.json'); 6 | 7 | class Handle extends Module { 8 | /* 9 | Method to declare _defaults. 10 | @private 11 | @overrides @ Module 12 | */ 13 | _declareDefaults () { 14 | super._declareDefaults(); 15 | this._defaults.minBound = 0; 16 | this._defaults.maxBound = 1; 17 | this._defaults.isBound = false; 18 | this._defaults.isInversed = false; 19 | this._defaults.direction = 'x'; 20 | this._defaults.onSeekStart = null; 21 | this._defaults.onSeekEnd = null; 22 | this._defaults.onProgress = null; 23 | this._defaults.snapPoint = 0; 24 | this._defaults.snapStrength = 0; 25 | } 26 | /* 27 | Method to set handle progress. 28 | @public 29 | @param {Number} Progress [0...1]. 30 | @param {Boolean} If should invoke onProgress callback. 31 | @returns this. 32 | */ 33 | setProgress ( progress, isCallback = true ) { 34 | let shift = this._progressToShift( progress ); 35 | this._setShift( shift, isCallback ); 36 | // calc delta and save it 37 | this._delta = shift - this._shift; 38 | this._saveDelta(); 39 | return this; 40 | } 41 | /* 42 | Method to set bounds of progress. 43 | @public 44 | @param {Number} Min bound to set [0...1]. 45 | @param {Number} Max bound to set [0...1]. 46 | @returns this. 47 | */ 48 | setBounds ( min, max ) { 49 | this.setMinBound( min ); 50 | this.setMaxBound( max ); 51 | return this; 52 | } 53 | /* 54 | Method to set min bound of progress. 55 | @public 56 | @param {Number} Min bound to set [0...1]. 57 | @returns this. 58 | */ 59 | setMinBound ( min ) { 60 | this._props.minBound = Math.max( min, 0 ); 61 | if ( this._progress < min ) { this.setProgress( min ); } 62 | return this; 63 | } 64 | /* 65 | Method to set max bound of progress. 66 | @public 67 | @param {Number} Max bound to set [0...1]. 68 | @returns this. 69 | */ 70 | setMaxBound ( max ) { 71 | this._props.maxBound = Math.min( max, 1 ); 72 | if ( this._progress > max ) { this.setProgress( max ); } 73 | return this; 74 | } 75 | /* 76 | Method to declare properties. 77 | @private 78 | @overrides @ Module. 79 | */ 80 | _vars () { 81 | // `progress` of the handle [0..1] 82 | this._progress = 0; 83 | // `shift` of the handle ( position in `px` ) 84 | this._shift = 0; 85 | // `delta` deviation from the current `shift` 86 | this._delta = 0; 87 | } 88 | /* 89 | Method to set handle shift. 90 | @private 91 | @param {Number} Shift in `px`. 92 | @param {Boolean} If should invoke onProgress callback. 93 | @returns {Number}. 94 | */ 95 | _setShift(shift, isCallback = true) { 96 | let p = this._props, 97 | minBound = p.minBound*this._maxWidth, 98 | maxBound = p.maxBound*this._maxWidth; 99 | 100 | shift = this.clamp(shift, minBound, maxBound ); 101 | this._applyShift( shift ); 102 | if (isCallback) { this._onProgress( shift ); } 103 | else { this._progress = this._shiftToProgress( shift ); } 104 | return shift; 105 | } 106 | 107 | /** 108 | * clamp - functiboundson to clamp a `value` between `min` and `max` 109 | * 110 | * @param {Number} value Value to clamp. 111 | * @param {Number} min Min bound 112 | * @param {Number} max Max bound 113 | * @return {Number} Clamped value. 114 | */ 115 | clamp(value, min, max) { 116 | return Math.min(Math.max(value, min), max); 117 | } 118 | 119 | /* 120 | Method to apply shift to the DOMElement. 121 | @private 122 | @param {Number} Shift in pixels. 123 | */ 124 | _applyShift ( shift ) { 125 | let p = this._props; 126 | // translateZ(0) 127 | this.el.style.transform = ( p.direction === 'x' ) 128 | ? `translateX( ${ shift }px )` 129 | : `translateY( ${ -shift }px )`; 130 | } 131 | /* 132 | Method to get max width of the parent. 133 | @private 134 | */ 135 | _getMaxWidth () { 136 | let p = this._props, 137 | parent = p.parent; 138 | 139 | this._maxWidth = ( p.direction === 'x' ) 140 | ? parent.clientWidth : parent.clientHeight; 141 | } 142 | /* 143 | Method to render the component. 144 | @private 145 | @overrides @ Module 146 | */ 147 | _render () { 148 | super._render(); 149 | this._addElements(); 150 | this._getMaxWidth(); 151 | this._hammerTime(); 152 | } 153 | /* 154 | Method to classes on `this.el`. 155 | @private 156 | @overrides @ Module 157 | */ 158 | _addMainClasses () { 159 | super._addMainClasses(); 160 | 161 | let p = this._props, 162 | classList = this.el.classList; 163 | 164 | classList.add( CLASSES.handle ); 165 | if ( p.isBound ) { classList.add( CLASSES['is-bound'] ); } 166 | if ( p.isInversed ) { classList.add( CLASSES['is-inversed'] ); } 167 | } 168 | /* 169 | Method to add DOM elements on render. 170 | @private 171 | */ 172 | _addElements () { 173 | var inner = this._createElement('div'), 174 | shadow = this._createElement('div'); 175 | 176 | inner.classList.add( `${ CLASSES.handle__inner }` ); 177 | shadow.classList.add( `${ CLASSES.handle__shadow }` ); 178 | this.el.appendChild( shadow ); 179 | this.el.appendChild( inner ); 180 | } 181 | /* 182 | Method to initialize HammerJS an set up all even listeners. 183 | @private 184 | */ 185 | _hammerTime () { 186 | let p = this._props, 187 | direction = ( p.direction === 'x' ) ? 'HORIZONTAL' : 'VERTICAL', 188 | hm = new HammerJS.Manager(this.el, { 189 | recognizers: [ 190 | [HammerJS.Pan, { direction: HammerJS[ `DIRECTION_${direction}` ] }] 191 | ] 192 | }); 193 | 194 | hm.on( 'pan', this._pan.bind( this ) ); 195 | hm.on( 'panend', this._panEnd.bind( this ) ); 196 | this._addPointerDownEvent( this.el, this._pointerDown.bind(this) ); 197 | this._addPointerUpEvent( this.el, this._pointerUp.bind( this ) ); 198 | // add listener on document to cover edge cases 199 | // like when you press -> leave the element -> release 200 | this._addPointerUpEvent( document, this._pointerUpDoc.bind( this ) ); 201 | 202 | window.addEventListener( 'resize', this._onWindowResize.bind( this ) ); 203 | } 204 | /* 205 | Callback for pan end on main el. 206 | @private 207 | @param {Object} Original event object. 208 | */ 209 | _pan ( e ) { 210 | let p = this._props; 211 | this._delta = ( p.direction === 'x' ) ? e.deltaX : -e.deltaY; 212 | // get progress from the shift to undestand how far is the snapPoint 213 | let shift = this._shift + this._delta, 214 | proc = this._shiftToProgress( shift ); 215 | // if progress is around snapPoint set it to the snap point 216 | proc = ( Math.abs( proc - p.snapPoint ) < p.snapStrength ) 217 | ? p.snapPoint : proc; 218 | // recalculate the progress to shift and set it 219 | this._setShift( this._progressToShift( proc ) ); 220 | } 221 | /* 222 | Callback for pan end on main el. 223 | @private 224 | @param {Object} Original event object. 225 | */ 226 | _panEnd ( e ) { 227 | this._saveDelta(); 228 | this._callIfFunction( this._props.onSeekEnd, e ); 229 | } 230 | /* 231 | Callback for pointer down on main el. 232 | @private 233 | @param {Object} Original event object. 234 | */ 235 | _pointerDown ( e ) { 236 | let p = this._props; 237 | this._isPointerDown = true; 238 | this._callIfFunction( p.onSeekStart, e ); 239 | } 240 | /* 241 | Callback for pointer up on main el. 242 | @private 243 | @param {Object} Original event object. 244 | */ 245 | _pointerUp ( e ) { 246 | this._callIfFunction( this._props.onSeekEnd, e ); 247 | e.preventDefault(); 248 | return false; 249 | } 250 | /* 251 | Callback for pointer up on document. 252 | @private 253 | @param {Object} Original event object. 254 | */ 255 | _pointerUpDoc ( e ) { 256 | if ( !this._isPointerDown ) { return } 257 | this._callIfFunction( this._props.onSeekEnd, e ); 258 | this._isPointerDown = false; 259 | } 260 | /* 261 | Method to add _delta to _shift. 262 | @private 263 | */ 264 | _saveDelta () { this._shift += this._delta; } 265 | /* 266 | Method to call onProgress callback. 267 | @private 268 | @param {Number} Shift in `px`. 269 | */ 270 | _onProgress ( shift ) { 271 | let p = this._props, 272 | progress = this._shiftToProgress( shift ); 273 | 274 | if ( this._progress !== progress ) { 275 | this._progress = progress; 276 | if ( this._isFunction( p.onProgress ) ) { 277 | p.onProgress.call( this, progress ); 278 | } 279 | } 280 | } 281 | /* 282 | Method to recalc shift to progress. 283 | @private 284 | @param {Number} Shift in `px`. 285 | @returns {Number} Progress [0...1]. 286 | */ 287 | _shiftToProgress ( shift ) { 288 | return shift / this._maxWidth; 289 | } 290 | /* 291 | Method to progress shift to shift. 292 | @private 293 | @param {Number} Progress [0...1]. 294 | @returns {Number} Shift in `px`. 295 | 296 | */ 297 | _progressToShift ( progress ) { 298 | return progress*this._maxWidth; 299 | } 300 | /* 301 | Callback for window resize event. 302 | @private 303 | @param {Object} Original event object. 304 | */ 305 | _onWindowResize ( e ) { 306 | this._getMaxWidth(); 307 | this.setProgress( this._progress ); 308 | } 309 | } 310 | 311 | export default Handle; 312 | -------------------------------------------------------------------------------- /js/components/hide-button.babel.js: -------------------------------------------------------------------------------- 1 | 2 | import ButtonSwitch from './button-switch'; 3 | import Icon from './icon'; 4 | 5 | require('../../css/blocks/hide-button.postcss.css'); 6 | let CLASSES = require('../../css/blocks/hide-button.postcss.css.json'), 7 | className = 'hide-button'; 8 | 9 | class HideButton extends ButtonSwitch { 10 | _declareDefaults () { 11 | super._declareDefaults(); 12 | this._defaults.title = 'hide (alt + h)' 13 | } 14 | /* 15 | Initial render method. 16 | @private 17 | @overrides @ Button 18 | @returns this 19 | */ 20 | _render () { 21 | super._render(); 22 | this.el.classList.add( CLASSES[ className ] ); 23 | this._addIcon(); 24 | } 25 | /* 26 | Method to add icon. 27 | @private 28 | */ 29 | _addIcon () { 30 | this.icon = new Icon({ 31 | parent: this.el, 32 | className: CLASSES[ `${ className }__icon` ], 33 | shape: 'hide', 34 | prefix: this._props.prefix 35 | }); 36 | } 37 | /* 38 | Method that have been called on switch state change. 39 | @private 40 | @override @ ButtonSwitch 41 | */ 42 | _setState () { 43 | let method = ( this._props.isOn ) ? 'add' : 'remove' ; 44 | this.el.classList[ method ]( CLASSES[ `is-hidden` ] ); 45 | } 46 | } 47 | 48 | export default HideButton; 49 | -------------------------------------------------------------------------------- /js/components/icon-button.babel.js: -------------------------------------------------------------------------------- 1 | import Icon from './icon'; 2 | import Button from './button'; 3 | 4 | require('../../css/blocks/icon-button.postcss.css'); 5 | let CLASSES = require('../../css/blocks/icon-button.postcss.css.json'); 6 | 7 | class IconButton extends Button { 8 | /* 9 | Method to declare _defaults. 10 | @private 11 | @overrides @ Button 12 | */ 13 | _declareDefaults () { 14 | super._declareDefaults(); 15 | this._defaults.icon = ''; 16 | this._defaults.iconClass = ''; 17 | } 18 | /* 19 | Initial render method. 20 | @private 21 | @overrides @ Button 22 | @returns this 23 | */ 24 | _render () { 25 | super._render(); 26 | let p = this._props, 27 | className = 'icon-button'; 28 | this.el.classList.add( CLASSES[ className ] ); 29 | 30 | let icon = new Icon({ 31 | shape: p.icon, 32 | parent: this.el, 33 | className: [ CLASSES[ `icon` ], p.iconClass ], 34 | prefix: p.prefix 35 | }); 36 | } 37 | } 38 | 39 | export default IconButton; 40 | -------------------------------------------------------------------------------- /js/components/icon-fork.babel.js: -------------------------------------------------------------------------------- 1 | import ButtonSwitch from './button-switch'; 2 | import Icon from './icon'; 3 | // import HammerJS from 'hammerjs' 4 | 5 | require('../../css/blocks/icon-fork.postcss.css'); 6 | let CLASSES = require('../../css/blocks/icon-fork.postcss.css.json'); 7 | 8 | class IconFork extends ButtonSwitch { 9 | /* 10 | Initial render method. 11 | @private 12 | @overrides @ Icon 13 | @returns this 14 | */ 15 | _render () { 16 | super._render(); 17 | this.el.classList.add( CLASSES[ 'icon-fork' ] ); 18 | let p = this._props, 19 | prefix = p.prefix, 20 | parent = this.el, 21 | className = CLASSES.icon; 22 | 23 | this.icon1 = new Icon({ shape: p.icon1, prefix, parent, className }); 24 | this.icon2 = new Icon({ shape: p.icon2, prefix, parent, className }); 25 | } 26 | /* 27 | Method that should be called on state change. 28 | @private 29 | @override @ IconSwitch 30 | */ 31 | _setState () { 32 | let p = this._props, 33 | classList = this.el.classList, 34 | method = ( p.isOn ) ? 'add' : 'remove'; 35 | 36 | classList[ method ]( CLASSES[ 'is-on' ] ) 37 | } 38 | } 39 | 40 | export default IconFork; 41 | -------------------------------------------------------------------------------- /js/components/icon.babel.js: -------------------------------------------------------------------------------- 1 | import Module from './module'; 2 | import HammerJS from 'hammerjs' 3 | 4 | require('../../css/blocks/icon.postcss.css'); 5 | let CLASSES = require('../../css/blocks/icon.postcss.css.json'); 6 | 7 | class Icon extends Module { 8 | /* 9 | Method to declare _defaults. 10 | @private 11 | @overrides @ Module 12 | */ 13 | _declareDefaults () { 14 | super._declareDefaults(); 15 | this._defaults.shape = ''; 16 | this._defaults.size = 'x1'; 17 | this.NS = 'http://www.w3.org/2000/svg'; 18 | } 19 | /* 20 | Initial render method. 21 | @private 22 | @overrides @ Module 23 | @returns this 24 | */ 25 | _render () { 26 | this._addMainElement(); 27 | this.el.classList.add( CLASSES.icon ); 28 | this.el.classList.add( CLASSES[ `is-${ this._props.size }` ] ); 29 | this.el.setAttribute('data-component', 'icon'); 30 | this._renderIcon(); 31 | } 32 | /* 33 | Method to render svg icon into the el. 34 | @private 35 | */ 36 | _renderIcon () { 37 | let p = this._props, 38 | svg = document.createElementNS( this.NS, 'svg' ), 39 | content = ``; 40 | svg.setAttribute( 'viewBox', '0 0 32 32' ); 41 | this._addSVGHtml( svg, content ); 42 | this.el.appendChild( svg ); 43 | } 44 | /* 45 | Add HTML to SVG element. 46 | @private 47 | @param {Object} SVG node. 48 | @param {String} SVG content to add. 49 | */ 50 | _addSVGHtml ( svg, content ) { 51 | let receptacle = this._createElement( 'div' ), 52 | svgfragment = ` ${ content } `; 53 | receptacle.innerHTML = svgfragment; 54 | let nodes = Array.prototype.slice.call(receptacle.childNodes[0].childNodes); 55 | for (let i = 0; i < nodes.length; i++) { 56 | svg.appendChild( nodes[i] ); 57 | } 58 | } 59 | } 60 | 61 | export default Icon; 62 | -------------------------------------------------------------------------------- /js/components/icons.babel.js: -------------------------------------------------------------------------------- 1 | import Module from './module'; 2 | 3 | class Icons extends Module { 4 | /* 5 | Initial render method. 6 | @private 7 | @overrides @ Module 8 | */ 9 | _render () { 10 | this.el = this._createElement( 'div' ); 11 | this.el.innerHTML = this.getIcons(); 12 | this.el.setAttribute( 'id', `${ this._props.prefix }icons` ); 13 | this._prependChild( document.body, this.el ); 14 | } 15 | /* 16 | Method to get icons shapes. 17 | @private 18 | */ 19 | getIcons () { 20 | let prefix = this._props.prefix; 21 | return ` 22 | 23 | 24 | 25 | 26 | 27 | 28 | 29 | 30 | 31 | 32 | `; 33 | } 34 | 35 | } 36 | 37 | export default Icons; 38 | -------------------------------------------------------------------------------- /js/components/label-button.babel.js: -------------------------------------------------------------------------------- 1 | import ButtonSwitch from './button-switch'; 2 | 3 | require('../../css/blocks/label-button.postcss.css'); 4 | let CLASSES = require('../../css/blocks/label-button.postcss.css.json'); 5 | 6 | class LabelButton extends ButtonSwitch { 7 | /* 8 | Method to declare defaults. 9 | @private 10 | @overrides @ OpacitySwitch 11 | */ 12 | _declareDefaults () { 13 | super._declareDefaults(); 14 | this._defaults.title = 'speed (reset: alt + 1)'; 15 | } 16 | /* 17 | Method to populate the label with progress text. 18 | @public 19 | @param {String} Text to set. 20 | */ 21 | setLabelText ( text ) { 22 | this.label.innerHTML = text; 23 | } 24 | 25 | /* 26 | ^ PUBLIC ^ 27 | v PPRIVATE v 28 | */ 29 | 30 | /* 31 | Initial render method. 32 | @private 33 | @overrides @ Button 34 | @returns this 35 | */ 36 | _render () { 37 | super._render(); 38 | this._addClass( this.el, CLASSES[ 'label-button' ] ); 39 | this._addLabel(); 40 | // this.setLabelText( this._props.progress ); 41 | } 42 | /* 43 | Method to add label to the `el`. 44 | @private 45 | */ 46 | _addLabel () { 47 | this.label = this._createElement('div'); 48 | this.label.classList.add( CLASSES[ `label-button__label` ] ); 49 | this.el.appendChild( this.label ); 50 | } 51 | } 52 | 53 | export default LabelButton; 54 | -------------------------------------------------------------------------------- /js/components/module.babel.js: -------------------------------------------------------------------------------- 1 | /* 2 | Base class for all modules. 3 | Extends _defaults to _props 4 | */ 5 | class Module { 6 | /* 7 | constructor method calls scaffolding methods. 8 | */ 9 | constructor ( o = {} ) { 10 | this._o = o; 11 | this._index = this._o.index || 0; 12 | this._declareDefaults(); 13 | this._extendDefaults(); 14 | this._vars() 15 | this._render(); 16 | } 17 | /* 18 | Method to declare defaults. 19 | @private 20 | */ 21 | _declareDefaults () { 22 | this._defaults = { 23 | className: '', 24 | parent: document.body, 25 | isPrepend: false, 26 | isRipple: false, 27 | prefix: '' 28 | }; 29 | } 30 | /* 31 | Method to add pointer down even listener to el. 32 | @param {Object} HTMLElement to add event listener on. 33 | @param {Function} Event listener callback. 34 | */ 35 | _addPointerDownEvent (el, fn) { 36 | if (window.navigator.msPointerEnabled) { 37 | el.addEventListener('MSPointerDown', fn); 38 | } else if ( window.ontouchstart !== undefined ) { 39 | el.addEventListener('touchstart', fn); 40 | el.addEventListener('mousedown', fn); 41 | } else { 42 | el.addEventListener('mousedown', fn); 43 | } 44 | } 45 | /* 46 | Method to add pointer up even listener to el. 47 | @param {Object} HTMLElement to add event listener on. 48 | @param {Function} Event listener callback. 49 | */ 50 | _addPointerUpEvent (el, fn) { 51 | if (window.navigator.msPointerEnabled) { 52 | el.addEventListener('MSPointerUp', fn); 53 | } else if ( window.ontouchstart !== undefined ) { 54 | el.addEventListener('touchend', fn); 55 | el.addEventListener('mouseup', fn); 56 | } else { 57 | el.addEventListener('mouseup', fn); 58 | } 59 | } 60 | /* 61 | Method to check if variable holds link to a function. 62 | @param {Function?} A variable to check. 63 | @returns {Boolean} If passed variable is a function. 64 | */ 65 | _isFunction ( fn ) { return ( typeof fn === 'function' ); } 66 | /* 67 | Method to a function or silently fail. 68 | @param {Function?} A variable to check. 69 | @param {Array like} Arguments. 70 | */ 71 | _callIfFunction ( fn ) { 72 | Array.prototype.shift.call( arguments ); 73 | this._isFunction( fn ) && fn.apply( this, arguments ); 74 | } 75 | /* 76 | Method to declare module's variables. 77 | @private 78 | */ 79 | _vars () { } 80 | /* 81 | Method to render on initialization. 82 | @private 83 | */ 84 | _render () { this._addMainElement(); } 85 | /* 86 | Method to add `this.el` on the module. 87 | @private 88 | @param {String} Tag name of the element. 89 | */ 90 | _addMainElement ( tagName = 'div' ) { 91 | let p = this._props; 92 | 93 | this.el = this._createElement( tagName ); 94 | this._addMainClasses(); 95 | 96 | let method = ( p.isPrepend ) ? 'prepend' : 'append' ; 97 | this[ `_${ method }Child` ]( p.parent, this.el ); 98 | } 99 | /* 100 | Method to classes on `this.el`. 101 | @private 102 | */ 103 | _addMainClasses () { 104 | let p = this._props; 105 | if ( p.className instanceof Array ) { 106 | for (var i = 0; i < p.className.length; i++) { 107 | this._addClass( this.el, p.className[i] ); 108 | } 109 | } else { this._addClass( this.el, p.className ); } 110 | } 111 | /* 112 | Method to add a class on el. 113 | @private 114 | @param {Object} HTML element to add the class on. 115 | @param {String} Class name to add. 116 | */ 117 | _addClass ( el, className ) { className && el.classList.add( className ); } 118 | /* 119 | Method to set property on the module. 120 | @private 121 | @param {String, Object} Name of the property to set 122 | or object with properties to set. 123 | @param {Any} Value for the property to set. Could be 124 | undefined if the first param is object. 125 | */ 126 | _setProp ( attr, value ) { 127 | if ( typeof attr === 'object' ) { 128 | for ( var key in attr ) { this._assignProp( key, attr[key] ); } 129 | } else { this._assignProp( attr, value ); } 130 | } 131 | /* 132 | Method to assign single property's value. 133 | @private 134 | @param {String} Property name. 135 | @param {Any} Property value. 136 | */ 137 | _assignProp ( key, value ) { 138 | this._props[key] = value; 139 | } 140 | /* 141 | Method to copy `_o` options to `_props` object 142 | with fallback to `_defaults`. 143 | @private 144 | */ 145 | _extendDefaults ( ) { 146 | this._props = {}; 147 | // this._deltas = {}; 148 | for (var key in this._defaults) { 149 | let value = this._o[key]; 150 | this.isIt && console.log(key) 151 | // copy the properties to the _o object 152 | this._assignProp( key, ( value != null ) ? value : this._defaults[key] ); 153 | } 154 | } 155 | /* 156 | Method to create HTMLElement from tag name. 157 | @private 158 | @param {String} Name of the tag to create `HTML` element. 159 | @returns {Object} HtmlElement. 160 | */ 161 | _createElement ( tagName ) { return document.createElement( tagName ); } 162 | /* 163 | Method to create HTMLElement and append it to the `el` with a className. 164 | @private 165 | @param {String} The tagname for the HTMLElement. 166 | @param {String} Optional class name to add to the new child. 167 | @returns {Object} The newely created HTMLElement. 168 | */ 169 | _createChild ( tagName, className ) { 170 | let child = this._createElement( 'div' ); 171 | className && child.classList.add( className ); 172 | this.el.appendChild( child ); 173 | return child; 174 | } 175 | /* 176 | Method to prepend child to the el. 177 | @private 178 | @param {Object} Parent HTMLElement. 179 | @param {Object} Child HTMLElement. 180 | */ 181 | _appendChild ( el, childEl ) { el.appendChild( childEl ); } 182 | /* 183 | Method to prepend child to the el. 184 | @private 185 | @param {Object} Parent HTMLElement. 186 | @param {Object} Child HTMLElement. 187 | */ 188 | _prependChild ( el, childEl ) { el.insertBefore(childEl, el.firstChild); } 189 | } 190 | 191 | export default Module; 192 | -------------------------------------------------------------------------------- /js/components/opacity-switch.babel.js: -------------------------------------------------------------------------------- 1 | import Icon from './icon'; 2 | import ButtonSwitch from './button-switch'; 3 | 4 | require('../../css/blocks/opacity-switch.postcss.css'); 5 | let CLASSES = require('../../css/blocks/opacity-switch.postcss.css.json'); 6 | 7 | class OpacitySwitch extends ButtonSwitch { 8 | /* 9 | Method to decalre defaults. 10 | @private 11 | @overrides @ ButtonSwitch 12 | */ 13 | _declareDefaults () { 14 | super._declareDefaults(); 15 | this._defaults.icon = ''; 16 | this._defaults.iconSize = ''; 17 | } 18 | /* 19 | Method to render the module. 20 | @private 21 | @overrides @ ButtonSwitch 22 | */ 23 | _render () { 24 | super._render(); 25 | this.el.classList.add( CLASSES[ 'opacity-switch' ] ); 26 | 27 | let p = this._props, 28 | icon = new Icon({ 29 | parent: this.el, 30 | shape: p.icon, 31 | size: p.iconSize, 32 | className: CLASSES[ 'icon' ], 33 | prefix: p.prefix 34 | }); 35 | this.el.appendChild( icon.el ); 36 | } 37 | /* 38 | Method to react to switch state change. 39 | @private 40 | @overrides @ ButtonSwitch 41 | */ 42 | _setState () { 43 | let method = ( this._props.isOn ) ? 'add' : 'remove'; 44 | this.el.classList[ method ]( CLASSES[ 'is-on' ] ); 45 | } 46 | } 47 | 48 | export default OpacitySwitch; 49 | -------------------------------------------------------------------------------- /js/components/play-button.babel.js: -------------------------------------------------------------------------------- 1 | 2 | import IconFork from './icon-fork'; 3 | 4 | require('../../css/blocks/play-button.postcss.css'); 5 | let CLASSES = require('../../css/blocks/play-button.postcss.css.json'); 6 | // PLAYER_BTN_CLASSES = require('css/blocks/player-button.postcss.css.json'); 7 | 8 | class PlayButton extends IconFork { 9 | /* 10 | Method to declare defaults on the module. 11 | @private 12 | @overrides @ ButtonSwitch 13 | */ 14 | _declareDefaults () { 15 | super._declareDefaults(); 16 | this._defaults.icon1 = 'pause'; 17 | this._defaults.icon2 = 'play'; 18 | this._defaults.title = 'play/pause (alt + p)'; 19 | } 20 | /* 21 | Method to render the module. 22 | @private 23 | */ 24 | _render () { 25 | super._render(); 26 | this._addClass( this.el, CLASSES[ 'play-button' ] ); 27 | } 28 | } 29 | 30 | export default PlayButton; 31 | -------------------------------------------------------------------------------- /js/components/player-slider.babel.js: -------------------------------------------------------------------------------- 1 | import Slider from './slider'; 2 | import Module from './module'; 3 | 4 | require('../../css/blocks/player-slider.postcss.css'); 5 | let CLASSES = require('../../css/blocks/player-slider.postcss.css.json'); 6 | let SLIDER_CLASSES = require('../../css/blocks/slider.postcss.css.json'); 7 | 8 | class PlayerSlider extends Module { 9 | /* 10 | Method to declare _defaults. 11 | @private 12 | @overrides @ Module 13 | */ 14 | _declareDefaults () { 15 | this._defaults = { 16 | className: CLASSES['player-slider'], 17 | parent: document.body, 18 | progress: 0, 19 | leftProgress: 0, 20 | rightProgress: 1, 21 | isBounds: false, 22 | onLeftProgress: null, 23 | onProgress: null, 24 | onRightProgress: null, 25 | onSeekStart: null, 26 | onSeekEnd: null 27 | } 28 | } 29 | /* 30 | Method to disable bounds. 31 | @public 32 | @returns this. 33 | */ 34 | disableBounds () { 35 | this.track.setBounds( 0, 1 ); 36 | this.rightBound.hide(); 37 | this.leftBound.hide(); 38 | return this; 39 | } 40 | /* 41 | Method to enable bounds. 42 | @public 43 | @returns this. 44 | */ 45 | enableBounds () { 46 | let p = this._props; 47 | this.track.setBounds( p.leftProgress, p.rightProgress ); 48 | this.rightBound.show(); 49 | this.leftBound.show(); 50 | return this; 51 | } 52 | /* 53 | Method to set progress of the track. 54 | @public 55 | @param {Number} Progress to set [0...1]. 56 | @returns this. 57 | */ 58 | setTrackProgress ( p ) { 59 | this.track.setProgress( p ); 60 | return this; 61 | } 62 | /* 63 | Method to decrease progress value. 64 | @public 65 | @param {Number} Value that the slider should be decreased by. 66 | @returns this. 67 | */ 68 | decreaseProgress ( amount = 0.01 ) { 69 | let progress = this.track._progress; 70 | progress -= amount; 71 | progress = ( progress < 0 ) ? 0 : progress; 72 | this.setTrackProgress( progress ); 73 | return this; 74 | } 75 | /* 76 | Method to inclease progress value. 77 | @public 78 | @param {Number} Value that the slider should be increased by. 79 | @returns this. 80 | */ 81 | increaseProgress ( amount = 0.01 ) { 82 | let progress = this.track._progress; 83 | progress += amount; 84 | progress = ( progress > 1 ) ? 1 : progress; 85 | this.setTrackProgress( progress ); 86 | return this; 87 | } 88 | /* 89 | Initial render method. 90 | @private 91 | @overrides @ Module 92 | @returns this 93 | */ 94 | _render () { 95 | let p = this._props; 96 | 97 | this._addMainElement(); 98 | this.el.classList.add( SLIDER_CLASSES.slider ); 99 | 100 | this.leftBound = new Slider({ 101 | isBound: true, 102 | parent: this.el, 103 | isRipple: false, 104 | onProgress: this._onLeftBoundProgress.bind(this), 105 | onSeekStart: p.onSeekStart, 106 | onSeekEnd: p.onSeekEnd 107 | }); 108 | 109 | this.track = new Slider({ 110 | parent: this.el, 111 | className: CLASSES.slider, 112 | onProgress: this._onTrackProgress.bind(this), 113 | onSeekStart: p.onSeekStart, 114 | onSeekEnd: p.onSeekEnd 115 | }); 116 | this.rightBound = new Slider({ 117 | isBound: true, 118 | parent: this.el, 119 | isRipple: false, 120 | isInversed: true, 121 | onProgress: this._onRightBoundProgress.bind(this), 122 | onSeekStart: p.onSeekStart, 123 | onSeekEnd: p.onSeekEnd 124 | }); 125 | 126 | this.rightBound.setProgress( p.rightProgress ); 127 | this.track.setProgress( p.progress ); 128 | this.leftBound.setProgress( p.leftProgress ); 129 | 130 | p.parent.appendChild( this.el ); 131 | 132 | } 133 | /* 134 | Method that should be called on track update. 135 | @private 136 | @param {Number} Track progress value [0...1]. 137 | */ 138 | _onTrackProgress ( p ) { 139 | this._callIfFunction( this._props.onProgress, p ); 140 | } 141 | /* 142 | Method that should be called on left bound update. 143 | @private 144 | @param {Number} Track progress value [0...1]. 145 | */ 146 | _onLeftBoundProgress ( p ) { 147 | if ( !this._props.isBounds ) { return; } 148 | this._props.leftProgress = p; 149 | this.track.setMinBound( p ); 150 | this.rightBound.setMinBound( p ); 151 | this._callIfFunction( this._props.onLeftProgress, p ); 152 | } 153 | /* 154 | Method that should be called on right bound update. 155 | @private 156 | @param {Number} Track progress value [0...1]. 157 | */ 158 | _onRightBoundProgress ( p ) { 159 | if ( !this._props.isBounds ) { return; } 160 | this._props.rightProgress = p; 161 | this.track.setMaxBound( p ); 162 | this.leftBound.setMaxBound( p ); 163 | this._callIfFunction( this._props.onRightProgress, p ); 164 | } 165 | } 166 | 167 | export default PlayerSlider; 168 | -------------------------------------------------------------------------------- /js/components/repeat-button.babel.js: -------------------------------------------------------------------------------- 1 | import OpacitySwitch from './opacity-switch'; 2 | 3 | require('../../css/blocks/repeat-button.postcss.css'); 4 | let CLASSES = require('../../css/blocks/repeat-button.postcss.css.json'); 5 | 6 | class RepeatButton extends OpacitySwitch { 7 | /* 8 | Method to declare defaults. 9 | @private 10 | @overrides @ OpacitySwitch 11 | */ 12 | _declareDefaults () { 13 | super._declareDefaults(); 14 | this._defaults.icon = 'repeat'; 15 | this._defaults.iconSize = 'x2'; 16 | this._defaults.title = 'repeat (alt + r)'; 17 | } 18 | /* 19 | Initial render method. 20 | @private 21 | @overrides @ Button 22 | @returns this 23 | */ 24 | _render () { 25 | super._render(); 26 | this._addClass( this.el, CLASSES[ 'repeat-button' ] ); 27 | } 28 | } 29 | 30 | export default RepeatButton; 31 | -------------------------------------------------------------------------------- /js/components/ripple.babel.js: -------------------------------------------------------------------------------- 1 | import Module from './module'; 2 | 3 | class Ripple extends Module { 4 | /* 5 | Method to declare defaults. 6 | @private 7 | @overrides @ Module. 8 | */ 9 | _declareDefaults () { 10 | super._declareDefaults(); 11 | this._defaults.withHold = true; 12 | } 13 | /* 14 | Method to render the component. 15 | @private 16 | @overrides @ Module 17 | */ 18 | _render () { 19 | super._render(); 20 | this.curtain = document.createElement('div'); 21 | // this.curtain.style.background = 'rgba(255,255,255,.15)'; 22 | // this.curtain.style.background = 'yellow'; 23 | this.curtain.style.position = 'absolute'; 24 | this.curtain.style.width = '100%'; 25 | this.curtain.style.height = '100%'; 26 | this.curtain.style.left = 0; 27 | this.curtain.style.top = 0; 28 | this.curtain.style.zIndex = 1; 29 | 30 | this.el.appendChild(this.curtain); 31 | 32 | if (mojs.Shape) { 33 | this._addRipple(); 34 | } 35 | } 36 | /* 37 | Method to construct ripple object. 38 | @private 39 | */ 40 | _addRipple () { 41 | this.shape = new mojs.Shape({ 42 | parent: this.el, 43 | left: 0, top: this._o.top || 0, 44 | // strokeWidth: 10, 45 | strokeWidth: { 10 : 0 }, 46 | fill: 'none', 47 | stroke: 'hotpink', 48 | fill: 'hotpink', 49 | fillOpacity: .75, 50 | opacity: { .85: 0 }, 51 | radius: 40, 52 | scale: { 0: 1 }, 53 | isShowEnd: false, 54 | // duration: 15000, 55 | // isForce3d: true, 56 | onStart: () => { this.isStart = true; }, 57 | onUpdate: this._onUpdate.bind(this), 58 | onComplete: () => { this.isStart = false; } 59 | }); 60 | } 61 | /* 62 | Method that is invoked on ripple update. 63 | @private 64 | @param {Number} Curret progress [0...1]. 65 | */ 66 | _onUpdate(p) { 67 | if (!this._props.withHold) { return; } 68 | if (p >= .15 && this.isStart && !this.isRelease) { 69 | this.isStart = false; 70 | 71 | if (mojs.Shape) { 72 | this.shape.setSpeed(.02); 73 | } 74 | } 75 | } 76 | /* 77 | Method that should be run on touch serface release. 78 | @private 79 | */ 80 | _release () { 81 | if ( !this._props.withHold ) { return; } 82 | this.isRelease = true; 83 | 84 | if (mojs.Shape) { 85 | this.shape.setSpeed( 1 ).play(); 86 | } 87 | } 88 | /* 89 | Method that should be run on touch serface hold. 90 | @private 91 | @param {Object} Origin event object. 92 | */ 93 | _hold ( e ) { 94 | let x = ( e.offsetX != null ) ? e.offsetX : e.layerX, 95 | y = ( e.offsetY != null ) ? e.offsetY : e.layerY; 96 | 97 | this.isRelease = false; 98 | if (mojs.Shape) { 99 | this.shape.tune({ x: x, y: y }).replay(); 100 | } 101 | } 102 | /* 103 | Method that should be run on touch serface cancel. 104 | @private 105 | */ 106 | _cancel () { 107 | if ( !this._props.withHold ) { return; } 108 | this.isRelease = true; 109 | 110 | if (mojs.Shape) { 111 | this.shape 112 | .pause() 113 | .setSpeed( 1 ) 114 | .playBackward(); 115 | } 116 | } 117 | } 118 | 119 | export default Ripple; 120 | -------------------------------------------------------------------------------- /js/components/slider.babel.js: -------------------------------------------------------------------------------- 1 | import Module from './module'; 2 | import Handle from './handle'; 3 | import Track from './track'; 4 | 5 | require('../../css/blocks/slider.postcss.css'); 6 | let CLASSES = require('../../css/blocks/slider.postcss.css.json'); 7 | 8 | class Slider extends Module { 9 | /* 10 | Method to declare _defaults. 11 | @private 12 | @overrides @ Module 13 | */ 14 | _declareDefaults () { 15 | this._defaults = { 16 | className: '', 17 | parent: document.body, 18 | isBound: false, 19 | isInversed: false, 20 | isRipple: true, 21 | isProgress: true, 22 | onProgress: null, 23 | onSeekStart: null, 24 | onSeekEnd: null, 25 | direction: 'x', 26 | snapPoint: 0, 27 | snapStrength: 0 28 | } 29 | } 30 | /* 31 | Method to set slider progress. 32 | @public 33 | @param {Number} Progress to set. 34 | @returns this. 35 | */ 36 | setProgress ( progress ) { 37 | this.handle.setProgress( progress ); 38 | this.track.setProgress( progress ); 39 | return this; 40 | } 41 | /* 42 | Method to set bounds of progress. 43 | @public 44 | @param {Number} Min bound to set [0...1]. 45 | @param {Number} Max bound to set [0...1]. 46 | @returns this. 47 | */ 48 | setBounds ( min, max ) { 49 | this.handle.setBounds( min, max ); 50 | this.track.setBounds( min, max ); 51 | return this; 52 | } 53 | /* 54 | Method to set min bound of progress. 55 | @public 56 | @param {Number} Min bound to set [0...1]. 57 | @returns this. 58 | */ 59 | setMinBound ( min ) { 60 | this.handle.setMinBound( min ); 61 | this.track.setMinBound( min ); 62 | return this; 63 | } 64 | /* 65 | Method to set max bound of progress. 66 | @public 67 | @param {Number} Max bound to set [0...1]. 68 | @returns this. 69 | */ 70 | setMaxBound ( max ) { 71 | this.handle.setMaxBound( max ); 72 | this.track.setMaxBound( max ); 73 | return this; 74 | } 75 | /* 76 | Method to hide elements. 77 | @public 78 | */ 79 | show () { 80 | this.track.el.style.display = 'block'; 81 | this.handle.el.style.display = 'block'; 82 | } 83 | /* 84 | Method to hide elements. 85 | @public 86 | */ 87 | hide () { 88 | this.track.el.style.display = 'none'; 89 | this.handle.el.style.display = 'none'; 90 | } 91 | /* 92 | Method to render the component. 93 | @private 94 | @overrides @ Module 95 | */ 96 | _render () { 97 | var p = this._props; 98 | 99 | if ( !p.isBound ) { 100 | let el = this._createElement( 'div' ), 101 | classList = el.classList; 102 | this.el = el; 103 | 104 | this.inner = this._createElement( 'div' ); 105 | this.inner.classList.add( CLASSES[ 'slider__inner' ] ) 106 | this.el.appendChild( this.inner ); 107 | 108 | 109 | classList.add( CLASSES.slider ); 110 | ( p.direction === 'y' ) && classList.add( CLASSES[ 'is-y' ] ); 111 | p.className && classList.add( p.className ); 112 | p.parent.appendChild( el ); 113 | } 114 | 115 | let rootEl = ( !p.isBound ) ? this.inner : p.parent; 116 | 117 | this.track = new Track({ 118 | className: CLASSES.track, 119 | onProgress: this._onTrackProgress.bind(this), 120 | onSeekStart: p.onSeekStart, 121 | onSeekEnd: p.onSeekEnd, 122 | isBound: p.isBound, 123 | isInversed: p.isInversed, 124 | isRipple: p.isRipple, 125 | isProgress: p.isProgress, 126 | parent: rootEl, 127 | direction: p.direction, 128 | snapPoint: p.snapPoint, 129 | snapStrength: p.snapStrength 130 | }); 131 | rootEl.appendChild( this.track.el ); 132 | 133 | let handleClass = [ CLASSES.handle ]; 134 | if ( !p.isBound ) { handleClass.push( CLASSES[ 'progress-handle' ] ) } 135 | 136 | this.handle = new Handle({ 137 | className: handleClass, 138 | onProgress: this._onHandleProgress.bind(this), 139 | onSeekStart: p.onSeekStart, 140 | onSeekEnd: p.onSeekEnd, 141 | isBound: p.isBound, 142 | isInversed: p.isInversed, 143 | parent: rootEl, 144 | direction: p.direction, 145 | snapPoint: p.snapPoint, 146 | snapStrength: p.snapStrength 147 | }); 148 | rootEl.appendChild( this.handle.el ); 149 | } 150 | /* 151 | Method that is invoked on handle progress change. 152 | @private 153 | @param {Number} Progress [0...1]. 154 | */ 155 | _onHandleProgress ( p ) { 156 | this.track.setProgress( p, false ); 157 | this._onProgress( p ); 158 | } 159 | /* 160 | Method that is invoked on track progress change. 161 | @private 162 | @param {Number} Progress [0...1]. 163 | */ 164 | _onTrackProgress ( p ) { 165 | this.handle.setProgress( p, false ); 166 | this._onProgress( p ); 167 | } 168 | /* 169 | Method to call onProgress callback. 170 | @private 171 | @param {Number} Progress value [0...1]. 172 | */ 173 | _onProgress ( progress ) { 174 | let p = this._props; 175 | if ( typeof p.onProgress === 'function' && this._progress !== progress) { 176 | this._progress = progress; 177 | p.onProgress.call( this, progress ); 178 | } 179 | } 180 | } 181 | 182 | export default Slider; 183 | -------------------------------------------------------------------------------- /js/components/speed-control.babel.js: -------------------------------------------------------------------------------- 1 | 2 | import Module from './module' 3 | import LabelButton from './label-button'; 4 | import Slider from './slider'; 5 | 6 | require('../../css/blocks/speed-control.postcss.css'); 7 | let CLASSES = require('../../css/blocks/speed-control.postcss.css.json'); 8 | 9 | class SpeedControl extends Module { 10 | /* 11 | Method to declare defaults for the module. 12 | @private 13 | @overrides @ Module 14 | */ 15 | _declareDefaults () { 16 | super._declareDefaults(); 17 | this._defaults.isOn = false; 18 | this._defaults.speed = 1; 19 | this._defaults.progress = .5; 20 | this._defaults.onSpeedChange = null; 21 | this._defaults.onIsSpeed = null 22 | } 23 | /* 24 | Method to reset speed to 1x. 25 | @public 26 | @returns this 27 | */ 28 | reset () { this._onDoubleTap(); } 29 | /* 30 | Method to decrease speed value. 31 | @public 32 | @param {Number} Value that the slider should be decreased by. 33 | @returns this. 34 | */ 35 | decreaseSpeed ( amount = 0.01 ) { 36 | let p = this._props; 37 | p.progress -= amount; 38 | p.progress = ( p.progress < 0 ) ? 0 : p.progress; 39 | this.slider.setProgress( p.progress ); 40 | return this; 41 | } 42 | /* 43 | Method to inclease speed value. 44 | @public 45 | @param {Number} Value that the slider should be increased by. 46 | @returns this. 47 | */ 48 | increaseSpeed ( amount = 0.01 ) { 49 | let p = this._props; 50 | p.progress += amount; 51 | p.progress = ( p.progress > 1 ) ? 1 : p.progress; 52 | this.slider.setProgress( p.progress ); 53 | return this; 54 | } 55 | /* 56 | Initial render method. 57 | @private 58 | @overrides @ Module 59 | */ 60 | _render () { 61 | let p = this._props, 62 | className = 'speed-control', 63 | slider = this._createElement( 'div' ), 64 | sliderIn = this._createElement( 'div' ), 65 | icon = this._createElement( 'div' ); 66 | 67 | this._addMainElement(); 68 | this.el.classList.add( CLASSES[ className ] ); 69 | // places for child components 70 | slider.classList.add( CLASSES[ `${ className }__slider` ] ); 71 | // sliderIn.classList.add( CLASSES[ `${ className }__slider-inner` ] ); 72 | // slider.appendChild( sliderIn ); 73 | this.el.appendChild( slider ); 74 | // child components 75 | this.labelButton = new LabelButton({ 76 | parent: this.el, 77 | isOn: p.isOn, 78 | className: CLASSES[ `${ className }__icon` ], 79 | onStateChange: this._onButtonStateChange.bind( this ), 80 | onDoubleTap: this._onDoubleTap.bind( this ) 81 | }); 82 | this.slider = new Slider({ 83 | parent: slider, 84 | isProgress: false, 85 | direction: 'y', 86 | onProgress: this._onSliderProgress.bind( this ), 87 | snapPoint: .5, 88 | snapStrength: .05 89 | }); 90 | 91 | this.slider.setProgress( this._speedToProgress( this._props.speed ) ); 92 | } 93 | /* 94 | Method that is invoked on slider progress. 95 | @private 96 | @param {Number} Progress of the slider. 97 | */ 98 | _onSliderProgress ( p ) { 99 | // progress should be at least 0.01 100 | p = Math.max( p, 0.0001 ); 101 | 102 | let props = this._props, 103 | args = [ ]; 104 | 105 | this._callIfFunction( props.onSpeedChange, this._progressToSpeed(p), p ); 106 | this.labelButton.setLabelText( this._progressToLabel( props.progress = p ) ); 107 | } 108 | /* 109 | Method that is invoked on button state change. 110 | @private 111 | @param {Boolean} State of the button switch. 112 | */ 113 | _onButtonStateChange ( isOn ) { 114 | let method = ( isOn ) ? 'add' : 'remove' ; 115 | this.el.classList[ method ]( CLASSES[ 'is-on' ] ); 116 | this._callIfFunction( this._props.onIsSpeed, isOn ); 117 | } 118 | /* 119 | Method to recalc progress to label string. 120 | @private 121 | @param {Number} Progress [0...1]. 122 | @returns {String} String for a label to set. 123 | */ 124 | _progressToLabel ( progress ) { 125 | let text = this._progressToSpeed(progress).toFixed( 2 ), 126 | zeros = /\.+00$/; 127 | 128 | if ( text.match( zeros ) ) { text = text.replace( zeros, '' ); } 129 | 130 | return `${ text }x`; 131 | } 132 | /* 133 | Method to recalc progress to speed. 134 | @private 135 | @param {Number} Progress [0...1]. 136 | @returns {Number} Speed [0...10]. 137 | */ 138 | _progressToSpeed ( progress ) { 139 | let speed = progress; 140 | if ( progress < .5 ) { 141 | speed = 2*progress; 142 | } 143 | if ( progress === .5 ) { speed = 1; } 144 | if ( progress > .5 ) { 145 | progress -= .5; 146 | speed = 1 + progress*18; 147 | // console.log( speed/10, mojs.easing.cubic.out( speed/10 ) ); 148 | // console.log( .5 + ( speed - 1 ) / 18 ); 149 | } 150 | return speed; 151 | } 152 | /* 153 | Method to recalc progress to speed. 154 | @private 155 | @param {Number} Progress [0...1]. 156 | @returns {Number} Speed [0...10]. 157 | */ 158 | _speedToProgress ( speed ) { 159 | let progress = speed; 160 | if ( speed < 1 ) { progress = speed/2; } 161 | if ( speed === 1 ) { progress = .5; } 162 | if ( speed > 1 ) { 163 | progress = .5 + ( ( speed - 1 ) / 18 ); 164 | } 165 | return progress; 166 | } 167 | /* 168 | Method that is invoked on double button tap. 169 | @private 170 | */ 171 | _onDoubleTap () { 172 | this.slider.setProgress( .5 ); 173 | this.labelButton.off(); 174 | } 175 | } 176 | 177 | export default SpeedControl; 178 | -------------------------------------------------------------------------------- /js/components/stop-button.babel.js: -------------------------------------------------------------------------------- 1 | import IconButton from './icon-button'; 2 | 3 | require('../../css/blocks/stop-button.postcss.css'); 4 | let CLASSES = require('../../css/blocks/stop-button.postcss.css.json'); 5 | 6 | class StopButton extends IconButton { 7 | _declareDefaults () { 8 | super._declareDefaults(); 9 | this._defaults.icon = 'stop'; 10 | this._defaults.title = 'stop (alt + s)'; 11 | } 12 | /* 13 | Initial render method. 14 | @private 15 | @overrides @ Button 16 | @returns this 17 | */ 18 | _render () { 19 | super._render(); 20 | this._addClass( this.el, CLASSES[ 'stop-button' ] ); 21 | } 22 | } 23 | 24 | export default StopButton; 25 | -------------------------------------------------------------------------------- /js/components/track.babel.js: -------------------------------------------------------------------------------- 1 | import Handle from './handle'; 2 | import HamerJS from 'hammerjs'; 3 | import Ripple from './ripple'; 4 | 5 | require('../../css/blocks/track.postcss.css'); 6 | let CLASSES = require('../../css/blocks/track.postcss.css.json'); 7 | 8 | class Track extends Handle { 9 | /* 10 | Method to declare _defaults. 11 | @private 12 | @overrides @ Handle 13 | */ 14 | _declareDefaults () { 15 | super._declareDefaults(); 16 | this._defaults.isProgress = true; 17 | this._defaults.isRipple = true; 18 | } 19 | /* 20 | Method to render the component. 21 | @private 22 | @overrides @ Handle 23 | */ 24 | _render () { 25 | super._render(); 26 | if ( !this._props.isRipple ) { return; } 27 | this.ripple = new Ripple({ 28 | withHold: false, 29 | className: CLASSES[ `track__ripple` ], 30 | // top: '50%', 31 | parent: this.el 32 | }); 33 | } 34 | /* 35 | Method to apply shift to the DOMElement. 36 | @private 37 | @overrides @ Handle. 38 | @param {Number} Shift in pixels.x 39 | */ 40 | _applyShift ( shift ) { 41 | if ( !this._props.isProgress ) { return; } 42 | if ( this._props.isInversed ) { shift = this._maxWidth - shift; } 43 | let transform = `scaleX( ${shift} ) translateZ(0)`; 44 | this.trackProgressEl.style.transform = transform; 45 | // this.trackProgressEl.style.width = `${shift}px`; 46 | } 47 | /* 48 | Method to add classes on `this.el`. 49 | @private 50 | @overrides @ Handle. 51 | */ 52 | _addMainClasses () { 53 | let p = this._props, 54 | classList = this.el.classList; 55 | 56 | classList.add( CLASSES.track ); 57 | if ( p.isInversed ) { classList.add( CLASSES[ 'is-inversed' ] ); } 58 | if ( p.isBound ) { classList.add( CLASSES[ 'is-bound' ] ); } 59 | if ( p.direction === 'y' ) { classList.add( CLASSES[ 'is-y' ] ); } 60 | } 61 | /* 62 | Method to add DOM elements on render. 63 | @private 64 | */ 65 | _addElements () { 66 | let p = this._props; 67 | 68 | if ( p.isProgress ) { 69 | // progress track 70 | const trackP = document.createElement('div'); 71 | trackP.classList.add(`${ CLASSES['track__track-progress'] }`); 72 | this.trackProgressEl = trackP; 73 | this.el.appendChild( trackP ); 74 | } 75 | // track 76 | if ( !p.isBound ) { 77 | let track = document.createElement('div'); 78 | track.classList.add(`${ CLASSES.track__track }`); 79 | this.el.appendChild( track ); 80 | } 81 | 82 | } 83 | /* 84 | Callback for pointer down on main el. 85 | @private 86 | @param {Object} Original event object. 87 | @overrides @ Handle 88 | */ 89 | _pointerDown ( e ) { 90 | let p = this._props, 91 | x = (p.direction === 'x' ) ? e.layerX : e.layerY; 92 | this._isPointerDown = true; 93 | 94 | if ( p.direction === 'y' ) { x = this._maxWidth - e.layerY; } 95 | x = ( this._props.isInversed && x < 0 ) ? this._maxWidth + x : x; 96 | 97 | // if near the snap point - set it to the snap point 98 | let progress = this._shiftToProgress( x ); 99 | progress = ( Math.abs( p.snapPoint - progress ) < p.snapStrength ) 100 | ? p.snapPoint : progress; 101 | this.setProgress( progress ); 102 | 103 | p.isRipple && this.ripple._hold( e ); 104 | this._callIfFunction( p.onSeekStart, e ); 105 | } 106 | } 107 | 108 | export default Track; 109 | -------------------------------------------------------------------------------- /js/mojs-player.babel.js: -------------------------------------------------------------------------------- 1 | import Polyfill from 'classlist-polyfill'; 2 | import Icons from './components/icons'; 3 | import Module from './components/module'; 4 | import PlayerSlider from './components/player-slider'; 5 | import IconButton from './components/icon-button'; 6 | import SpeedControl from './components/speed-control'; 7 | import PlayButton from './components/play-button'; 8 | import StopButton from './components/stop-button'; 9 | import RepeatButton from './components/repeat-button'; 10 | import BoundsButton from './components/bounds-button'; 11 | import HideButton from './components/hide-button'; 12 | 13 | // TODO 14 | 15 | require('../css/blocks/mojs-player.postcss.css'); 16 | let CLASSES = require('../css/blocks/mojs-player.postcss.css.json'); 17 | 18 | class MojsPlayer extends Module { 19 | constructor ( o ) { 20 | if ( typeof mojs === 'undefined' ) { 21 | throw new Error(`MojsPlayer relies on mojs^0.225.2, please include it before player initialization. [ https://github.com/mojs/mojs ] `); 22 | } 23 | super( o ); 24 | } 25 | /* 26 | Method to declare defaults. 27 | @private 28 | @overrides @ Module 29 | */ 30 | _declareDefaults () { 31 | super._declareDefaults(); 32 | 33 | this._defaults.isSaveState = true; 34 | this._defaults.isPlaying = false; 35 | this._defaults.progress = 0; 36 | this._defaults.isRepeat = false; 37 | this._defaults.isBounds = false; 38 | this._defaults.leftBound = 0; 39 | this._defaults.rightBound = 1; 40 | this._defaults.isSpeed = false; 41 | this._defaults.speed = 1; 42 | this._defaults.isHidden = false; 43 | this._defaults.precision = 0.1; 44 | this._defaults.name = 'mojs-player'; 45 | this._defaults.onToggleHide = null; 46 | this._defaults.onPlayStateChange = null; 47 | this._defaults.onSeekStart = null; 48 | this._defaults.onSeekEnd = null; 49 | this._defaults.onProgress = null; 50 | 51 | this._play = this._play.bind(this); 52 | 53 | this.revision = '1.3.0'; 54 | 55 | let str = this._fallbackTo( this._o.name, this._defaults.name ); 56 | str += ( str === this._defaults.name ) ? '' : `__${this._defaults.name}`; 57 | this._localStorage = `${str}__${ this._hashCode( str ) }`; 58 | } 59 | /* 60 | Method to copy `_o` options to `_props` object 61 | with fallback to `localStorage` and `_defaults`. 62 | @private 63 | */ 64 | _extendDefaults () { 65 | this._props = {}; 66 | let p = this._props, 67 | o = this._o, 68 | defs = this._defaults; 69 | 70 | // get localstorage regarding isSaveState option 71 | p.isSaveState = this._fallbackTo( o.isSaveState, defs.isSaveState ); 72 | let m = ( p.isSaveState ) 73 | ? JSON.parse( localStorage.getItem(this._localStorage) ) || {} 74 | : {}; 75 | 76 | for (let key in defs) { 77 | let value = this._fallbackTo( m[ key ], o[ key ] ); 78 | this._assignProp( key, this._fallbackTo( value, defs[ key ] ) ); 79 | } 80 | // get raw-speed option 81 | this._props[ 'raw-speed' ] = this._fallbackTo( m[ 'raw-speed' ], .5 ); 82 | } 83 | /* 84 | Callback for keyup on document. 85 | @private 86 | @param {Object} Original event object. 87 | */ 88 | _keyUp ( e ) { 89 | if ( e.altKey ) { 90 | switch ( e.keyCode ) { 91 | case 80: // alt + P => PLAY/PAUSE TOGGLE 92 | this._props.isPlaying = !this._props.isPlaying; 93 | this._onPlayStateChange( this._props.isPlaying ); 94 | break; 95 | case 189: // alt + - => DECREASE PROGRESS 96 | this.playButton.off(); 97 | this.playerSlider.decreaseProgress( ( e.shiftKey ) ? .1 : .01 ); 98 | break; 99 | case 187: // alt + + => INCREASE PROGRESS 100 | this.playButton.off(); 101 | this.playerSlider.increaseProgress( ( e.shiftKey ) ? .1 : .01 ); 102 | break; 103 | case 83: // alt + S => STOP 104 | this._onStop(); 105 | break; 106 | case 82: // alt + R => REPEAT TOGGLE 107 | this._props.isRepeat = !this._props.isRepeat; 108 | var method = ( this._props.isRepeat ) ? 'on' : 'off'; 109 | this.repeatButton[ method ](); 110 | break; 111 | case 66: // alt + B => BOUNDS TOGGLE 112 | this._props.isBounds = !this._props.isBounds; 113 | var method = ( this._props.isBounds ) ? 'on' : 'off'; 114 | this.boundsButton[ method ](); 115 | break; 116 | case 72: // alt + H => HIDE PLAYER TOGGLE 117 | this._props.isHidden = !this._props.isHidden; 118 | this._onHideStateChange( this._props.isHidden ); 119 | var method = ( this._props.isHidden ) ? 'on' : 'off'; 120 | this.hideButton[ method ](); 121 | break; 122 | // case 49: // alt + 1 => RESET SPEED TO 1x 123 | case 81: // alt + q => RESET SPEED TO 1x 124 | this.speedControl.reset(); 125 | break; 126 | case 50: // alt + 2 => DECREASE SPEEED by .05 127 | this.speedControl.decreaseSpeed( ( e.shiftKey ) ? .05 : .01 ); 128 | break; 129 | case 51: // alt + 3 => INCREASE SPEED by .05 130 | this.speedControl.increaseSpeed( ( e.shiftKey ) ? .05 : .01 ); 131 | break; 132 | } 133 | } 134 | } 135 | /* 136 | Method to declare properties. 137 | @private 138 | @overrides @ Module 139 | */ 140 | _vars () { 141 | this._hideCount = 0; 142 | } 143 | /* 144 | Method to render the module. 145 | @private 146 | @overrides @ Module 147 | */ 148 | _render () { 149 | this._initTimeline(); 150 | let p = this._props, 151 | className = 'mojs-player', 152 | icons = new Icons({ prefix: this._props.prefix }); 153 | super._render(); 154 | // this.el.classList.add(p.classNAme ); 155 | this.el.classList.add( CLASSES[ className ] ); 156 | this.el.setAttribute( 'id', 'js-mojs-player' ); 157 | 158 | let left = this._createChild( 'div', CLASSES[ `${ className }__left` ] ), 159 | mid = this._createChild( 'div', CLASSES[ `${ className }__mid` ] ), 160 | right = this._createChild( 'div', CLASSES[ `${ className }__right` ] ); 161 | 162 | this.repeatButton = new RepeatButton({ 163 | parent: left, 164 | isOn: p.isRepeat, 165 | onStateChange: this._onRepeatStateChange.bind( this ), 166 | prefix: this._props.prefix 167 | }); 168 | 169 | this.playerSlider = new PlayerSlider({ 170 | parent: mid, 171 | isBounds: p.isBounds, 172 | leftProgress: p.leftBound, 173 | rightProgress: p.rightBound, 174 | progress: p.progress, 175 | onLeftProgress: this._onLeftProgress.bind( this ), 176 | onProgress: this._onProgress.bind( this ), 177 | onRightProgress: this._onRightProgress.bind( this ), 178 | onSeekStart: this._onSeekStart.bind( this ), 179 | onSeekEnd: this._onSeekEnd.bind( this ) 180 | }); 181 | 182 | this.boundsButton = new BoundsButton({ 183 | isOn: p.isBounds, 184 | parent: left, 185 | onStateChange: this._boundsStateChange.bind( this ), 186 | prefix: this._props.prefix 187 | }); 188 | 189 | this.speedControl = new SpeedControl({ 190 | parent: left, 191 | // progress: p.speed, 192 | speed: p.speed, 193 | isOn: p.isSpeed, 194 | onSpeedChange: this._onSpeedChange.bind( this ), 195 | onIsSpeed: this._onIsSpeed.bind( this ), 196 | prefix: this._props.prefix 197 | }); 198 | 199 | let proc = 0, 200 | progress = [], 201 | procToSpeed = [], 202 | speedToProc = []; 203 | 204 | this.stopButton = new StopButton({ 205 | parent: left, 206 | isPrepend: true, 207 | onPointerUp: this._onStop.bind( this ), 208 | prefix: this._props.prefix 209 | }); 210 | 211 | this.playButton = new PlayButton({ 212 | parent: left, 213 | isOn: p.isPlaying, 214 | isPrepend: true, 215 | onStateChange: this._onPlayStateChange.bind( this ), 216 | prefix: this._props.prefix 217 | }); 218 | 219 | this.mojsButton = new IconButton({ 220 | parent: right, 221 | className: CLASSES[ `${ className }__mojs-logo` ], 222 | icon: 'mojs', 223 | target: '_blank', 224 | link: 'https://github.com/mojs/mojs-player', 225 | title: 'mo • js', 226 | prefix: this._props.prefix 227 | }); 228 | 229 | this.hideButton = new HideButton({ 230 | parent: this.el, 231 | className: CLASSES[ `${ className }__hide-button` ], 232 | isOn: p.isHidden, 233 | onStateChange: this._onHideStateChange.bind( this ), 234 | prefix: this._props.prefix 235 | }); 236 | 237 | this._listen(); 238 | } 239 | /* 240 | Method to initialize event listeners. 241 | @private 242 | */ 243 | _listen () { 244 | const unloadEvent = ('onpagehide' in window) ? 'pagehide' : 'beforeunload'; 245 | window.addEventListener( unloadEvent, this._onUnload.bind(this) ); 246 | document.addEventListener( 'keyup' , this._keyUp.bind(this) ); 247 | } 248 | /* 249 | Method that is invoked when user touches the track. 250 | @private 251 | @param {Object} Original event object. 252 | */ 253 | _onSeekStart ( e ) { 254 | this._sysTween.pause(); 255 | 256 | const { onSeekStart } = this._props; 257 | if (this._isFunction(onSeekStart)) { 258 | onSeekStart(e); 259 | } 260 | } 261 | /* 262 | Method that is invoked when user touches the track. 263 | @private 264 | @param {Object} Original event object. 265 | */ 266 | _onSeekEnd ( e ) { 267 | clearTimeout( this._endTimer ); 268 | this._endTimer = setTimeout( () => { 269 | this._props.isPlaying && this._play(); 270 | }, 20 ); 271 | } 272 | /* 273 | Method to init timeline. 274 | @private 275 | */ 276 | _initTimeline () { 277 | this.timeline = new mojs.Timeline({}); 278 | 279 | let add = this._o.add; 280 | // check whether the `add` option meets the next criterias: 281 | let isUndefined = typeof add === 'undefined'; 282 | 283 | if ( !isUndefined ) { add = add.timeline || add.tween || add; } 284 | 285 | let isAdd = !!add.setProgress; 286 | 287 | if ( isUndefined || !isAdd ) { 288 | throw new Error('MojsPlayer expects Tween/Timeline/Module as `add` option in constructor call. [ new MojsPlayer({ add: new mojs.Tween }); ]'); 289 | return; 290 | } 291 | 292 | this.timeline.add(this._o.add); 293 | 294 | const { _props } = this.timeline; 295 | const duration = (_props.repeatTime !== void 0) ? _props : _props.delay + _props.duration; 296 | 297 | this._sysTween = new mojs.Tween({ 298 | easing: 'linear.none', 299 | duration, 300 | onUpdate: this._onSysProgress.bind( this ), 301 | onComplete: this._onSysTweenComplete.bind( this ), 302 | onPlaybackStop: () => { this._setPlayState( 'off' ); }, 303 | onPlaybackPause: () => { this._setPlayState( 'off' ); }, 304 | onPlaybackStart: () => { this._setPlayState( 'on' ); } 305 | }); 306 | } 307 | /* 308 | Method that is invoked on system tween progress. 309 | @private 310 | @param {Number} Progress value [0...1]. 311 | */ 312 | _onSysProgress(p) { 313 | this.playerSlider.setTrackProgress(p); 314 | 315 | let rightBound = ( this._props.isBounds ) ? this._props.rightBound : 1, 316 | leftBound = ( this._props.isBounds ) ? this._props.leftBound : -1; 317 | 318 | // since js is really bed in numbers precision, 319 | // if we set a progress in the `_play` method it returns slighly 320 | // different when piped thru tween, so add `0.01` gap to soften that 321 | if ( p < leftBound - 0.01 && p !== 0 ) { 322 | this._reset(); 323 | requestAnimationFrame(this._play); 324 | } 325 | 326 | if ( p >= rightBound ) { 327 | this._reset( rightBound === 1 ); 328 | 329 | if (this._props.isRepeat) { 330 | requestAnimationFrame(this._play); 331 | } else { this._props.isPlaying = false; } 332 | } 333 | } 334 | /* 335 | Method to play system tween from progress. 336 | @private 337 | */ 338 | _play() { 339 | const p = this._props; 340 | let leftBound = (p.isBounds) ? p.leftBound : p.progress; 341 | let progress = (p.progress >= this._getBound('right')) 342 | ? leftBound : p.progress; 343 | 344 | if (progress === 1) { progress = (p.isBounds) ? p.leftBound : 0 }; 345 | if (progress !== 0) { this._sysTween.setProgress(progress); }; 346 | 347 | this._sysTween.play(); 348 | } 349 | /* 350 | Method to reset sysTween and timeline. 351 | @param {Boolean} If should not set progress to 0. 352 | @private 353 | */ 354 | _reset(isPause) { 355 | this._sysTween.reset(); 356 | 357 | // if ( !isPause ) { 358 | // const p = this._props, 359 | // progress = p.progress; 360 | // 361 | // let start = progress, 362 | // leftBound = (p.isBounds) ? p.leftBound : 0; 363 | // 364 | // // while ( (start - p.precision) >= leftBound ) { 365 | // // start -= p.precision; 366 | // // this.timeline.setProgress( start ); 367 | // // } 368 | // } 369 | 370 | this.timeline.reset(); 371 | } 372 | /* 373 | Method to set play button state. 374 | @private 375 | @param {String} Method name to call it on playButton. 376 | */ 377 | _setPlayState ( method ) { 378 | clearTimeout( this._playTimeout ); 379 | this._playTimeout = setTimeout( () => { 380 | this.playButton && this.playButton[ method ]( false ); 381 | }, 20); 382 | } 383 | /* 384 | Method that is invoked on system tween completion. 385 | @private 386 | @param {Boolean} If forward direction. 387 | */ 388 | _onSysTweenComplete ( isForward ) { 389 | // console.log(' complete ', this._props.isPlaying, isForward, this._props.isRepeat); 390 | // if ( this._props.isPlaying && isForward ) { 391 | // if ( this._props.isRepeat ) { 392 | // console.log('reset 2') 393 | // // this._sysTween.reset(); 394 | // // this._play(); 395 | // } 396 | // } 397 | } 398 | /* 399 | Method that is invoked play button state change. 400 | @private 401 | @param {Boolean} Repeat button state. 402 | */ 403 | _onPlayStateChange ( isPlay ) { 404 | this._props.isPlaying = isPlay; 405 | if ( isPlay ) { this._play(); } else { this._sysTween.pause(); } 406 | 407 | const { onPlayStateChange } = this._props; 408 | if (this._isFunction(onPlayStateChange)) { 409 | onPlayStateChange(isPlay); 410 | } 411 | } 412 | /* 413 | Callback for hide button change state. 414 | @private 415 | @param {Boolean} 416 | */ 417 | _onHideStateChange ( isHidden ) { 418 | this._props.isHidden = isHidden; 419 | const { onToggleHide } = this._props; 420 | if (this._isFunction(onToggleHide)) { 421 | onToggleHide(isHidden); 422 | } 423 | 424 | let method = ( isHidden ) ? 'add' : 'remove'; 425 | this.el.classList[ method ]( CLASSES[ 'is-hidden' ] ); 426 | // enable CSS transition on subsequent calls 427 | if ( this._hideCount++ === 1 ) { 428 | this.el.classList.add( CLASSES[ 'is-transition' ] ); 429 | } 430 | } 431 | /* 432 | Method that is invoked on stop button tap. 433 | @private 434 | */ 435 | _onStop() { 436 | const p = this._props; 437 | p.isPlaying = false; 438 | 439 | const leftBound = ( p.isBounds ) ? p.leftBound : 0; 440 | // set sysTween progress twice because it could be _reset already 441 | this._sysTween.setProgress(leftBound + 0.01); 442 | this._sysTween.setProgress(leftBound); 443 | 444 | this._reset(); 445 | } 446 | /* 447 | Method that is invoked on repeat switch state change. 448 | @private 449 | @param {Boolean} Repeat button state. 450 | */ 451 | _onRepeatStateChange ( isOn ) { this._props.isRepeat = isOn; } 452 | /* 453 | Method that is invoked on bounds switch state change. 454 | @private 455 | @param {Boolean} Bounds state. 456 | */ 457 | _boundsStateChange ( isOn ) { 458 | this.playerSlider._props.isBounds = isOn; 459 | this.playerSlider[ `${ ( isOn ) ? 'enable' : 'disable' }Bounds` ](); 460 | this._props.isBounds = isOn; 461 | } 462 | /* 463 | Method that is invoked on speed value change. 464 | @private 465 | @param {Number} Speed value. 466 | @param {Number} Slider progress. 467 | */ 468 | _onSpeedChange(speed, progress) { 469 | this._props[ 'raw-speed' ] = progress; 470 | this._props.speed = speed; 471 | this._sysTween.setSpeed(speed); 472 | } 473 | /* 474 | Method that is invoked on speed state change. 475 | @private 476 | @param {Boolean} Speed control state. 477 | */ 478 | _onIsSpeed(isOn) { this._props.isSpeed = isOn; } 479 | /* 480 | Method that is invoked on timeline's left bound progress. 481 | @private 482 | @param {Number} Progress value [0...1]. 483 | */ 484 | _onLeftProgress(progress) { this._props.leftBound = progress; } 485 | /* 486 | Method that is invoked on timeline progress. 487 | @private 488 | @param {Number} Progress value [0...1]. 489 | */ 490 | _onProgress(progress) { 491 | this._props.progress = progress; 492 | // if timeline was reset - refresh it's state 493 | // by incremental updates until progress (0 always) 494 | // if ( !this.timeline._prevTime && progress > 0 ) { 495 | // let start = 0; 496 | // do { 497 | // this.timeline.setProgress( start ); 498 | // start += this._props.precision; 499 | // } while ( start + this._props.precision < progress ); 500 | // } 501 | // console.log(`timeline.setProgress: ${progress}`); 502 | this.timeline.setProgress(progress); 503 | } 504 | /* 505 | Method that is invoked on timeline's right bound progress. 506 | @private 507 | @param {Number} Progress value [0...1]. 508 | */ 509 | _onRightProgress ( progress ) { this._props.rightBound = progress; } 510 | /* 511 | Method that is invoked on window unload. 512 | @private 513 | @param {Object} Original even object. 514 | */ 515 | _onUnload ( e ) { 516 | if ( !this._props.isSaveState ) { 517 | return localStorage.removeItem( this._localStorage ); 518 | } 519 | 520 | const props = { ...this._props }; 521 | delete props.parent; 522 | delete props.className; 523 | delete props.isSaveState; 524 | delete props.precision; 525 | 526 | localStorage.setItem(this._localStorage, JSON.stringify( props ) ); 527 | } 528 | /* 529 | Method that returns the second argument if the first one isn't set. 530 | @private 531 | @param {Any} Property to set. 532 | @param {Any} Property to return as fallback. 533 | @returns {Any} If set - the first property, if not - the second. 534 | */ 535 | _fallbackTo ( prop, fallback ) { return ( prop != null ) ? prop : fallback; } 536 | /* 537 | Method to get bound regarding isBound option. 538 | @private 539 | @param {String} Bound name. 540 | */ 541 | _getBound ( boundName ) { 542 | let p = this._props, 543 | fallback = ( boundName === 'left' ) ? 0 : 1; 544 | 545 | return ( p.isBounds ) ? p[ `${ boundName }Bound` ] : fallback; 546 | } 547 | /* 548 | Method to defer a method. 549 | @private 550 | @param {Function} Function that should be defered. 551 | */ 552 | _defer (fn) { setTimeout( fn.bind(this), 1 ); } 553 | /* 554 | Method to generate hash code. 555 | @private 556 | @return {String} Hash code. 557 | */ 558 | _hashCode ( str ) { 559 | var hash = 0, i, chr, len; 560 | if (str.length === 0) return hash; 561 | for (i = 0, len = str.length; i < len; i++) { 562 | chr = str.charCodeAt(i); 563 | hash = ((hash << 5) - hash) + chr; 564 | hash |= 0; // Convert to 32bit integer 565 | } 566 | return Math.abs( hash ); 567 | } 568 | 569 | /* 570 | Method to determine if variable is a function 571 | @private 572 | @param {Function} Function to be guarenteed. 573 | @return {Boolean} true/false whether variable reference was a function 574 | */ 575 | _isFunction (fn) { return typeof fn === 'function'; } 576 | } 577 | 578 | if ( (typeof define === "function") && define.amd ) { 579 | define(function () { return MojsPlayer; }); 580 | } 581 | if ( (typeof module === "object") && (typeof module.exports === "object") ) { 582 | module.exports = MojsPlayer; 583 | } 584 | 585 | let _global = ( typeof global !== 'undefined' ) ? global : window; 586 | _global.MojsPlayer = MojsPlayer; 587 | 588 | export default MojsPlayer; 589 | -------------------------------------------------------------------------------- /lib/components/bounds-button.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _repeatButton = require('./repeat-button'); 18 | 19 | var _repeatButton2 = _interopRequireDefault(_repeatButton); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | // require('css/blocks/repeat-button.postcss.css'); 24 | // let CLASSES = require('css/blocks/repeat-button.postcss.css.json'); 25 | 26 | var BoundsButton = function (_RepeatButton) { 27 | (0, _inherits3.default)(BoundsButton, _RepeatButton); 28 | 29 | function BoundsButton() { 30 | (0, _classCallCheck3.default)(this, BoundsButton); 31 | return (0, _possibleConstructorReturn3.default)(this, _RepeatButton.apply(this, arguments)); 32 | } 33 | 34 | /* 35 | Method to declare defaults. 36 | @private 37 | @overrides @ RepeatButton 38 | */ 39 | BoundsButton.prototype._declareDefaults = function _declareDefaults() { 40 | _RepeatButton.prototype._declareDefaults.call(this); 41 | this._defaults.icon = 'bounds'; 42 | this._defaults.title = 'progress bounds (alt + b)'; 43 | }; 44 | 45 | return BoundsButton; 46 | }(_repeatButton2.default); 47 | 48 | exports.default = BoundsButton; -------------------------------------------------------------------------------- /lib/components/button-switch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _button = require('./button'); 18 | 19 | var _button2 = _interopRequireDefault(_button); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | require('../../css/blocks/button-switch.postcss.css'); 24 | var CLASSES = require('../../css/blocks/button-switch.postcss.css.json'); 25 | 26 | var ButtonSwitch = function (_Button) { 27 | (0, _inherits3.default)(ButtonSwitch, _Button); 28 | 29 | function ButtonSwitch() { 30 | (0, _classCallCheck3.default)(this, ButtonSwitch); 31 | return (0, _possibleConstructorReturn3.default)(this, _Button.apply(this, arguments)); 32 | } 33 | 34 | /* 35 | Method to declare _defaults. 36 | @private 37 | @overrides @ Button 38 | */ 39 | ButtonSwitch.prototype._declareDefaults = function _declareDefaults() { 40 | _Button.prototype._declareDefaults.call(this); 41 | this._defaults.isOn = false; 42 | this._defaults.onStateChange = null; 43 | }; 44 | /* 45 | Method to set the state to `true`. 46 | @public 47 | @param {Boolean} If should invoke callback. 48 | */ 49 | 50 | 51 | ButtonSwitch.prototype.on = function on() { 52 | var isCallback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; 53 | 54 | // set to true because the next step is toggle 55 | this._props.isOn = true; 56 | this._reactOnStateChange(isCallback); 57 | }; 58 | /* 59 | Method to set the state to `false`. 60 | @public 61 | @param {Boolean} If should invoke callback. 62 | */ 63 | 64 | 65 | ButtonSwitch.prototype.off = function off() { 66 | var isCallback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; 67 | 68 | // set to true because the next step is toggle 69 | this._props.isOn = false; 70 | this._reactOnStateChange(isCallback); 71 | }; 72 | 73 | // --- 74 | 75 | /* 76 | Initial render method. 77 | @private 78 | @overrides @ Button 79 | @returns this 80 | */ 81 | 82 | 83 | ButtonSwitch.prototype._render = function _render() { 84 | _Button.prototype._render.call(this); 85 | this.el.classList.add(CLASSES['button-switch']); 86 | this._setState(); 87 | this._reactOnStateChange(); 88 | }; 89 | /* 90 | Method to invoke onPointerUp callback if excist. 91 | @private 92 | @overrides @ Button 93 | @param {Object} Original event object. 94 | */ 95 | 96 | 97 | ButtonSwitch.prototype._pointerUp = function _pointerUp(e) { 98 | if (!this.wasTouched) { 99 | this.wasTouched = false; 100 | e.stopPropagation(); 101 | return; 102 | } 103 | this._changeState(); 104 | _Button.prototype._pointerUp.call(this, e); 105 | }; 106 | /* 107 | Method to switch icons. 108 | @private 109 | */ 110 | 111 | 112 | ButtonSwitch.prototype._changeState = function _changeState() { 113 | this._props.isOn = !this._props.isOn; 114 | this._reactOnStateChange(); 115 | }; 116 | /* 117 | Method to react on state change. 118 | @private 119 | @param {Boolean} If should invoke callback. 120 | */ 121 | 122 | 123 | ButtonSwitch.prototype._reactOnStateChange = function _reactOnStateChange() { 124 | var isCallback = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : true; 125 | 126 | if (isCallback) { 127 | this._callIfFunction(this._props.onStateChange, this._props.isOn); 128 | } 129 | this._setState(); 130 | }; 131 | /* 132 | Method that have been called on switch state change. 133 | @private 134 | */ 135 | 136 | 137 | ButtonSwitch.prototype._setState = function _setState() { 138 | // console.log('change'); 139 | }; 140 | 141 | return ButtonSwitch; 142 | }(_button2.default); 143 | 144 | exports.default = ButtonSwitch; -------------------------------------------------------------------------------- /lib/components/button.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _module = require('./module'); 18 | 19 | var _module2 = _interopRequireDefault(_module); 20 | 21 | var _hammerjs = require('hammerjs'); 22 | 23 | var _hammerjs2 = _interopRequireDefault(_hammerjs); 24 | 25 | var _ripple = require('./ripple'); 26 | 27 | var _ripple2 = _interopRequireDefault(_ripple); 28 | 29 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 30 | 31 | require('../../css/blocks/button.postcss.css'); 32 | var CLASSES = require('../../css/blocks/button.postcss.css.json'); 33 | 34 | var Button = function (_Module) { 35 | (0, _inherits3.default)(Button, _Module); 36 | 37 | function Button() { 38 | (0, _classCallCheck3.default)(this, Button); 39 | return (0, _possibleConstructorReturn3.default)(this, _Module.apply(this, arguments)); 40 | } 41 | 42 | /* 43 | Method to declare defaults for the module. 44 | @private 45 | @overrides @ Module 46 | */ 47 | Button.prototype._declareDefaults = function _declareDefaults() { 48 | _Module.prototype._declareDefaults.call(this); 49 | this._defaults.link = null; 50 | this._defaults.title = ''; 51 | this._defaults.target = null; 52 | this._defaults.onPointerDown = null; 53 | this._defaults.onPointerUp = null; 54 | this._defaults.onDoubleTap = null; 55 | }; 56 | /* 57 | Initial render method. 58 | @private 59 | @overrides @ Module 60 | */ 61 | 62 | 63 | Button.prototype._render = function _render() { 64 | var p = this._props, 65 | className = 'button', 66 | tagName = p.link != null ? 'a' : 'div'; 67 | 68 | this._addMainElement(tagName); 69 | this.el.classList.add(CLASSES[className]); 70 | this.el.setAttribute('title', p.title); 71 | p.link && this.el.setAttribute('href', p.link); 72 | p.link && p.target && this.el.setAttribute('target', p.target); 73 | this._addListeners(); 74 | 75 | this._createRipple(); 76 | }; 77 | /* 78 | Method to create ripple. 79 | @private 80 | */ 81 | 82 | 83 | Button.prototype._createRipple = function _createRipple() { 84 | this.ripple = new _ripple2.default({ 85 | className: CLASSES['button__ripple'], 86 | parent: this.el 87 | }); 88 | }; 89 | /* 90 | Method to add event listeners to the icon. 91 | @private 92 | */ 93 | 94 | 95 | Button.prototype._addListeners = function _addListeners() { 96 | this._addPointerDownEvent(this.el, this._pointerDown.bind(this)); 97 | this._addPointerUpEvent(this.el, this._pointerUp.bind(this)); 98 | this._addPointerUpEvent(document, this._pointerCancel.bind(this)); 99 | (0, _hammerjs2.default)(this.el).on('doubletap', this._doubleTap.bind(this)); 100 | }; 101 | /* 102 | Method to invoke onPointerDown callback if exist. 103 | @private 104 | @param {Object} Original event object. 105 | */ 106 | 107 | 108 | Button.prototype._pointerDown = function _pointerDown(e) { 109 | this.wasTouched = true; 110 | this._callIfFunction(this._props.onPointerDown); 111 | this.ripple._hold(e); 112 | }; 113 | /* 114 | Method to invoke onPointerUp callback if exist. 115 | @private 116 | @param {Object} Original event object. 117 | */ 118 | 119 | 120 | Button.prototype._pointerUp = function _pointerUp(e) { 121 | if (!this.wasTouched) { 122 | e.stopPropagation();return; 123 | } 124 | 125 | this.wasTouched = false; 126 | this._callIfFunction(this._props.onPointerUp); 127 | this.ripple._release(); 128 | e.preventDefault(); 129 | return false; 130 | }; 131 | /* 132 | Method to invoke onPointerCancel callback if exist. 133 | @private 134 | @param {Object} Original event object. 135 | */ 136 | 137 | 138 | Button.prototype._pointerCancel = function _pointerCancel(e) { 139 | if (!this.wasTouched) { 140 | return; 141 | }; 142 | this.wasTouched = false; 143 | this.ripple._cancel(); 144 | }; 145 | /* 146 | Method to invoke onDoubleTap callback if exist. 147 | @private 148 | @param {Object} Original event object. 149 | */ 150 | 151 | 152 | Button.prototype._doubleTap = function _doubleTap(e) { 153 | this._callIfFunction(this._props.onDoubleTap); 154 | }; 155 | 156 | return Button; 157 | }(_module2.default); 158 | 159 | exports.default = Button; -------------------------------------------------------------------------------- /lib/components/handle.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _module = require('./module'); 18 | 19 | var _module2 = _interopRequireDefault(_module); 20 | 21 | var _hammerjs = require('hammerjs'); 22 | 23 | var _hammerjs2 = _interopRequireDefault(_hammerjs); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | require('../../css/blocks/handle.postcss.css'); 28 | var CLASSES = require('../../css/blocks/handle.postcss.css.json'); 29 | 30 | var Handle = function (_Module) { 31 | (0, _inherits3.default)(Handle, _Module); 32 | 33 | function Handle() { 34 | (0, _classCallCheck3.default)(this, Handle); 35 | return (0, _possibleConstructorReturn3.default)(this, _Module.apply(this, arguments)); 36 | } 37 | 38 | /* 39 | Method to declare _defaults. 40 | @private 41 | @overrides @ Module 42 | */ 43 | Handle.prototype._declareDefaults = function _declareDefaults() { 44 | _Module.prototype._declareDefaults.call(this); 45 | this._defaults.minBound = 0; 46 | this._defaults.maxBound = 1; 47 | this._defaults.isBound = false; 48 | this._defaults.isInversed = false; 49 | this._defaults.direction = 'x'; 50 | this._defaults.onSeekStart = null; 51 | this._defaults.onSeekEnd = null; 52 | this._defaults.onProgress = null; 53 | this._defaults.snapPoint = 0; 54 | this._defaults.snapStrength = 0; 55 | }; 56 | /* 57 | Method to set handle progress. 58 | @public 59 | @param {Number} Progress [0...1]. 60 | @param {Boolean} If should invoke onProgress callback. 61 | @returns this. 62 | */ 63 | 64 | 65 | Handle.prototype.setProgress = function setProgress(progress) { 66 | var isCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; 67 | 68 | var shift = this._progressToShift(progress); 69 | this._setShift(shift, isCallback); 70 | // calc delta and save it 71 | this._delta = shift - this._shift; 72 | this._saveDelta(); 73 | return this; 74 | }; 75 | /* 76 | Method to set bounds of progress. 77 | @public 78 | @param {Number} Min bound to set [0...1]. 79 | @param {Number} Max bound to set [0...1]. 80 | @returns this. 81 | */ 82 | 83 | 84 | Handle.prototype.setBounds = function setBounds(min, max) { 85 | this.setMinBound(min); 86 | this.setMaxBound(max); 87 | return this; 88 | }; 89 | /* 90 | Method to set min bound of progress. 91 | @public 92 | @param {Number} Min bound to set [0...1]. 93 | @returns this. 94 | */ 95 | 96 | 97 | Handle.prototype.setMinBound = function setMinBound(min) { 98 | this._props.minBound = Math.max(min, 0); 99 | if (this._progress < min) { 100 | this.setProgress(min); 101 | } 102 | return this; 103 | }; 104 | /* 105 | Method to set max bound of progress. 106 | @public 107 | @param {Number} Max bound to set [0...1]. 108 | @returns this. 109 | */ 110 | 111 | 112 | Handle.prototype.setMaxBound = function setMaxBound(max) { 113 | this._props.maxBound = Math.min(max, 1); 114 | if (this._progress > max) { 115 | this.setProgress(max); 116 | } 117 | return this; 118 | }; 119 | /* 120 | Method to declare properties. 121 | @private 122 | @overrides @ Module. 123 | */ 124 | 125 | 126 | Handle.prototype._vars = function _vars() { 127 | // `progress` of the handle [0..1] 128 | this._progress = 0; 129 | // `shift` of the handle ( position in `px` ) 130 | this._shift = 0; 131 | // `delta` deviation from the current `shift` 132 | this._delta = 0; 133 | }; 134 | /* 135 | Method to set handle shift. 136 | @private 137 | @param {Number} Shift in `px`. 138 | @param {Boolean} If should invoke onProgress callback. 139 | @returns {Number}. 140 | */ 141 | 142 | 143 | Handle.prototype._setShift = function _setShift(shift) { 144 | var isCallback = arguments.length > 1 && arguments[1] !== undefined ? arguments[1] : true; 145 | 146 | var p = this._props, 147 | minBound = p.minBound * this._maxWidth, 148 | maxBound = p.maxBound * this._maxWidth; 149 | 150 | shift = this.clamp(shift, minBound, maxBound); 151 | this._applyShift(shift); 152 | if (isCallback) { 153 | this._onProgress(shift); 154 | } else { 155 | this._progress = this._shiftToProgress(shift); 156 | } 157 | return shift; 158 | }; 159 | 160 | /** 161 | * clamp - functiboundson to clamp a `value` between `min` and `max` 162 | * 163 | * @param {Number} value Value to clamp. 164 | * @param {Number} min Min bound 165 | * @param {Number} max Max bound 166 | * @return {Number} Clamped value. 167 | */ 168 | 169 | 170 | Handle.prototype.clamp = function clamp(value, min, max) { 171 | return Math.min(Math.max(value, min), max); 172 | }; 173 | 174 | /* 175 | Method to apply shift to the DOMElement. 176 | @private 177 | @param {Number} Shift in pixels. 178 | */ 179 | 180 | 181 | Handle.prototype._applyShift = function _applyShift(shift) { 182 | var p = this._props; 183 | // translateZ(0) 184 | this.el.style.transform = p.direction === 'x' ? 'translateX( ' + shift + 'px )' : 'translateY( ' + -shift + 'px )'; 185 | }; 186 | /* 187 | Method to get max width of the parent. 188 | @private 189 | */ 190 | 191 | 192 | Handle.prototype._getMaxWidth = function _getMaxWidth() { 193 | var p = this._props, 194 | parent = p.parent; 195 | 196 | this._maxWidth = p.direction === 'x' ? parent.clientWidth : parent.clientHeight; 197 | }; 198 | /* 199 | Method to render the component. 200 | @private 201 | @overrides @ Module 202 | */ 203 | 204 | 205 | Handle.prototype._render = function _render() { 206 | _Module.prototype._render.call(this); 207 | this._addElements(); 208 | this._getMaxWidth(); 209 | this._hammerTime(); 210 | }; 211 | /* 212 | Method to classes on `this.el`. 213 | @private 214 | @overrides @ Module 215 | */ 216 | 217 | 218 | Handle.prototype._addMainClasses = function _addMainClasses() { 219 | _Module.prototype._addMainClasses.call(this); 220 | 221 | var p = this._props, 222 | classList = this.el.classList; 223 | 224 | classList.add(CLASSES.handle); 225 | if (p.isBound) { 226 | classList.add(CLASSES['is-bound']); 227 | } 228 | if (p.isInversed) { 229 | classList.add(CLASSES['is-inversed']); 230 | } 231 | }; 232 | /* 233 | Method to add DOM elements on render. 234 | @private 235 | */ 236 | 237 | 238 | Handle.prototype._addElements = function _addElements() { 239 | var inner = this._createElement('div'), 240 | shadow = this._createElement('div'); 241 | 242 | inner.classList.add('' + CLASSES.handle__inner); 243 | shadow.classList.add('' + CLASSES.handle__shadow); 244 | this.el.appendChild(shadow); 245 | this.el.appendChild(inner); 246 | }; 247 | /* 248 | Method to initialize HammerJS an set up all even listeners. 249 | @private 250 | */ 251 | 252 | 253 | Handle.prototype._hammerTime = function _hammerTime() { 254 | var p = this._props, 255 | direction = p.direction === 'x' ? 'HORIZONTAL' : 'VERTICAL', 256 | hm = new _hammerjs2.default.Manager(this.el, { 257 | recognizers: [[_hammerjs2.default.Pan, { direction: _hammerjs2.default['DIRECTION_' + direction] }]] 258 | }); 259 | 260 | hm.on('pan', this._pan.bind(this)); 261 | hm.on('panend', this._panEnd.bind(this)); 262 | this._addPointerDownEvent(this.el, this._pointerDown.bind(this)); 263 | this._addPointerUpEvent(this.el, this._pointerUp.bind(this)); 264 | // add listener on document to cover edge cases 265 | // like when you press -> leave the element -> release 266 | this._addPointerUpEvent(document, this._pointerUpDoc.bind(this)); 267 | 268 | window.addEventListener('resize', this._onWindowResize.bind(this)); 269 | }; 270 | /* 271 | Callback for pan end on main el. 272 | @private 273 | @param {Object} Original event object. 274 | */ 275 | 276 | 277 | Handle.prototype._pan = function _pan(e) { 278 | var p = this._props; 279 | this._delta = p.direction === 'x' ? e.deltaX : -e.deltaY; 280 | // get progress from the shift to undestand how far is the snapPoint 281 | var shift = this._shift + this._delta, 282 | proc = this._shiftToProgress(shift); 283 | // if progress is around snapPoint set it to the snap point 284 | proc = Math.abs(proc - p.snapPoint) < p.snapStrength ? p.snapPoint : proc; 285 | // recalculate the progress to shift and set it 286 | this._setShift(this._progressToShift(proc)); 287 | }; 288 | /* 289 | Callback for pan end on main el. 290 | @private 291 | @param {Object} Original event object. 292 | */ 293 | 294 | 295 | Handle.prototype._panEnd = function _panEnd(e) { 296 | this._saveDelta(); 297 | this._callIfFunction(this._props.onSeekEnd, e); 298 | }; 299 | /* 300 | Callback for pointer down on main el. 301 | @private 302 | @param {Object} Original event object. 303 | */ 304 | 305 | 306 | Handle.prototype._pointerDown = function _pointerDown(e) { 307 | var p = this._props; 308 | this._isPointerDown = true; 309 | this._callIfFunction(p.onSeekStart, e); 310 | }; 311 | /* 312 | Callback for pointer up on main el. 313 | @private 314 | @param {Object} Original event object. 315 | */ 316 | 317 | 318 | Handle.prototype._pointerUp = function _pointerUp(e) { 319 | this._callIfFunction(this._props.onSeekEnd, e); 320 | e.preventDefault(); 321 | return false; 322 | }; 323 | /* 324 | Callback for pointer up on document. 325 | @private 326 | @param {Object} Original event object. 327 | */ 328 | 329 | 330 | Handle.prototype._pointerUpDoc = function _pointerUpDoc(e) { 331 | if (!this._isPointerDown) { 332 | return; 333 | } 334 | this._callIfFunction(this._props.onSeekEnd, e); 335 | this._isPointerDown = false; 336 | }; 337 | /* 338 | Method to add _delta to _shift. 339 | @private 340 | */ 341 | 342 | 343 | Handle.prototype._saveDelta = function _saveDelta() { 344 | this._shift += this._delta; 345 | }; 346 | /* 347 | Method to call onProgress callback. 348 | @private 349 | @param {Number} Shift in `px`. 350 | */ 351 | 352 | 353 | Handle.prototype._onProgress = function _onProgress(shift) { 354 | var p = this._props, 355 | progress = this._shiftToProgress(shift); 356 | 357 | if (this._progress !== progress) { 358 | this._progress = progress; 359 | if (this._isFunction(p.onProgress)) { 360 | p.onProgress.call(this, progress); 361 | } 362 | } 363 | }; 364 | /* 365 | Method to recalc shift to progress. 366 | @private 367 | @param {Number} Shift in `px`. 368 | @returns {Number} Progress [0...1]. 369 | */ 370 | 371 | 372 | Handle.prototype._shiftToProgress = function _shiftToProgress(shift) { 373 | return shift / this._maxWidth; 374 | }; 375 | /* 376 | Method to progress shift to shift. 377 | @private 378 | @param {Number} Progress [0...1]. 379 | @returns {Number} Shift in `px`. 380 | */ 381 | 382 | 383 | Handle.prototype._progressToShift = function _progressToShift(progress) { 384 | return progress * this._maxWidth; 385 | }; 386 | /* 387 | Callback for window resize event. 388 | @private 389 | @param {Object} Original event object. 390 | */ 391 | 392 | 393 | Handle.prototype._onWindowResize = function _onWindowResize(e) { 394 | this._getMaxWidth(); 395 | this.setProgress(this._progress); 396 | }; 397 | 398 | return Handle; 399 | }(_module2.default); 400 | 401 | exports.default = Handle; -------------------------------------------------------------------------------- /lib/components/hide-button.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _buttonSwitch = require('./button-switch'); 18 | 19 | var _buttonSwitch2 = _interopRequireDefault(_buttonSwitch); 20 | 21 | var _icon = require('./icon'); 22 | 23 | var _icon2 = _interopRequireDefault(_icon); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | require('../../css/blocks/hide-button.postcss.css'); 28 | var CLASSES = require('../../css/blocks/hide-button.postcss.css.json'), 29 | className = 'hide-button'; 30 | 31 | var HideButton = function (_ButtonSwitch) { 32 | (0, _inherits3.default)(HideButton, _ButtonSwitch); 33 | 34 | function HideButton() { 35 | (0, _classCallCheck3.default)(this, HideButton); 36 | return (0, _possibleConstructorReturn3.default)(this, _ButtonSwitch.apply(this, arguments)); 37 | } 38 | 39 | HideButton.prototype._declareDefaults = function _declareDefaults() { 40 | _ButtonSwitch.prototype._declareDefaults.call(this); 41 | this._defaults.title = 'hide (alt + h)'; 42 | }; 43 | /* 44 | Initial render method. 45 | @private 46 | @overrides @ Button 47 | @returns this 48 | */ 49 | 50 | 51 | HideButton.prototype._render = function _render() { 52 | _ButtonSwitch.prototype._render.call(this); 53 | this.el.classList.add(CLASSES[className]); 54 | this._addIcon(); 55 | }; 56 | /* 57 | Method to add icon. 58 | @private 59 | */ 60 | 61 | 62 | HideButton.prototype._addIcon = function _addIcon() { 63 | this.icon = new _icon2.default({ 64 | parent: this.el, 65 | className: CLASSES[className + '__icon'], 66 | shape: 'hide', 67 | prefix: this._props.prefix 68 | }); 69 | }; 70 | /* 71 | Method that have been called on switch state change. 72 | @private 73 | @override @ ButtonSwitch 74 | */ 75 | 76 | 77 | HideButton.prototype._setState = function _setState() { 78 | var method = this._props.isOn ? 'add' : 'remove'; 79 | this.el.classList[method](CLASSES['is-hidden']); 80 | }; 81 | 82 | return HideButton; 83 | }(_buttonSwitch2.default); 84 | 85 | exports.default = HideButton; -------------------------------------------------------------------------------- /lib/components/icon-button.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _icon = require('./icon'); 18 | 19 | var _icon2 = _interopRequireDefault(_icon); 20 | 21 | var _button = require('./button'); 22 | 23 | var _button2 = _interopRequireDefault(_button); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | require('../../css/blocks/icon-button.postcss.css'); 28 | var CLASSES = require('../../css/blocks/icon-button.postcss.css.json'); 29 | 30 | var IconButton = function (_Button) { 31 | (0, _inherits3.default)(IconButton, _Button); 32 | 33 | function IconButton() { 34 | (0, _classCallCheck3.default)(this, IconButton); 35 | return (0, _possibleConstructorReturn3.default)(this, _Button.apply(this, arguments)); 36 | } 37 | 38 | /* 39 | Method to declare _defaults. 40 | @private 41 | @overrides @ Button 42 | */ 43 | IconButton.prototype._declareDefaults = function _declareDefaults() { 44 | _Button.prototype._declareDefaults.call(this); 45 | this._defaults.icon = ''; 46 | this._defaults.iconClass = ''; 47 | }; 48 | /* 49 | Initial render method. 50 | @private 51 | @overrides @ Button 52 | @returns this 53 | */ 54 | 55 | 56 | IconButton.prototype._render = function _render() { 57 | _Button.prototype._render.call(this); 58 | var p = this._props, 59 | className = 'icon-button'; 60 | this.el.classList.add(CLASSES[className]); 61 | 62 | var icon = new _icon2.default({ 63 | shape: p.icon, 64 | parent: this.el, 65 | className: [CLASSES['icon'], p.iconClass], 66 | prefix: p.prefix 67 | }); 68 | }; 69 | 70 | return IconButton; 71 | }(_button2.default); 72 | 73 | exports.default = IconButton; -------------------------------------------------------------------------------- /lib/components/icon-fork.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _buttonSwitch = require('./button-switch'); 18 | 19 | var _buttonSwitch2 = _interopRequireDefault(_buttonSwitch); 20 | 21 | var _icon = require('./icon'); 22 | 23 | var _icon2 = _interopRequireDefault(_icon); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | // import HammerJS from 'hammerjs' 28 | 29 | require('../../css/blocks/icon-fork.postcss.css'); 30 | var CLASSES = require('../../css/blocks/icon-fork.postcss.css.json'); 31 | 32 | var IconFork = function (_ButtonSwitch) { 33 | (0, _inherits3.default)(IconFork, _ButtonSwitch); 34 | 35 | function IconFork() { 36 | (0, _classCallCheck3.default)(this, IconFork); 37 | return (0, _possibleConstructorReturn3.default)(this, _ButtonSwitch.apply(this, arguments)); 38 | } 39 | 40 | /* 41 | Initial render method. 42 | @private 43 | @overrides @ Icon 44 | @returns this 45 | */ 46 | IconFork.prototype._render = function _render() { 47 | _ButtonSwitch.prototype._render.call(this); 48 | this.el.classList.add(CLASSES['icon-fork']); 49 | var p = this._props, 50 | prefix = p.prefix, 51 | parent = this.el, 52 | className = CLASSES.icon; 53 | 54 | this.icon1 = new _icon2.default({ shape: p.icon1, prefix: prefix, parent: parent, className: className }); 55 | this.icon2 = new _icon2.default({ shape: p.icon2, prefix: prefix, parent: parent, className: className }); 56 | }; 57 | /* 58 | Method that should be called on state change. 59 | @private 60 | @override @ IconSwitch 61 | */ 62 | 63 | 64 | IconFork.prototype._setState = function _setState() { 65 | var p = this._props, 66 | classList = this.el.classList, 67 | method = p.isOn ? 'add' : 'remove'; 68 | 69 | classList[method](CLASSES['is-on']); 70 | }; 71 | 72 | return IconFork; 73 | }(_buttonSwitch2.default); 74 | 75 | exports.default = IconFork; -------------------------------------------------------------------------------- /lib/components/icon.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _module = require('./module'); 18 | 19 | var _module2 = _interopRequireDefault(_module); 20 | 21 | var _hammerjs = require('hammerjs'); 22 | 23 | var _hammerjs2 = _interopRequireDefault(_hammerjs); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | require('../../css/blocks/icon.postcss.css'); 28 | var CLASSES = require('../../css/blocks/icon.postcss.css.json'); 29 | 30 | var Icon = function (_Module) { 31 | (0, _inherits3.default)(Icon, _Module); 32 | 33 | function Icon() { 34 | (0, _classCallCheck3.default)(this, Icon); 35 | return (0, _possibleConstructorReturn3.default)(this, _Module.apply(this, arguments)); 36 | } 37 | 38 | /* 39 | Method to declare _defaults. 40 | @private 41 | @overrides @ Module 42 | */ 43 | Icon.prototype._declareDefaults = function _declareDefaults() { 44 | _Module.prototype._declareDefaults.call(this); 45 | this._defaults.shape = ''; 46 | this._defaults.size = 'x1'; 47 | this.NS = 'http://www.w3.org/2000/svg'; 48 | }; 49 | /* 50 | Initial render method. 51 | @private 52 | @overrides @ Module 53 | @returns this 54 | */ 55 | 56 | 57 | Icon.prototype._render = function _render() { 58 | this._addMainElement(); 59 | this.el.classList.add(CLASSES.icon); 60 | this.el.classList.add(CLASSES['is-' + this._props.size]); 61 | this.el.setAttribute('data-component', 'icon'); 62 | this._renderIcon(); 63 | }; 64 | /* 65 | Method to render svg icon into the el. 66 | @private 67 | */ 68 | 69 | 70 | Icon.prototype._renderIcon = function _renderIcon() { 71 | var p = this._props, 72 | svg = document.createElementNS(this.NS, 'svg'), 73 | content = ''; 74 | svg.setAttribute('viewBox', '0 0 32 32'); 75 | this._addSVGHtml(svg, content); 76 | this.el.appendChild(svg); 77 | }; 78 | /* 79 | Add HTML to SVG element. 80 | @private 81 | @param {Object} SVG node. 82 | @param {String} SVG content to add. 83 | */ 84 | 85 | 86 | Icon.prototype._addSVGHtml = function _addSVGHtml(svg, content) { 87 | var receptacle = this._createElement('div'), 88 | svgfragment = ' ' + content + ' '; 89 | receptacle.innerHTML = svgfragment; 90 | var nodes = Array.prototype.slice.call(receptacle.childNodes[0].childNodes); 91 | for (var i = 0; i < nodes.length; i++) { 92 | svg.appendChild(nodes[i]); 93 | } 94 | }; 95 | 96 | return Icon; 97 | }(_module2.default); 98 | 99 | exports.default = Icon; -------------------------------------------------------------------------------- /lib/components/icons.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _module = require('./module'); 18 | 19 | var _module2 = _interopRequireDefault(_module); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | var Icons = function (_Module) { 24 | (0, _inherits3.default)(Icons, _Module); 25 | 26 | function Icons() { 27 | (0, _classCallCheck3.default)(this, Icons); 28 | return (0, _possibleConstructorReturn3.default)(this, _Module.apply(this, arguments)); 29 | } 30 | 31 | /* 32 | Initial render method. 33 | @private 34 | @overrides @ Module 35 | */ 36 | Icons.prototype._render = function _render() { 37 | this.el = this._createElement('div'); 38 | this.el.innerHTML = this.getIcons(); 39 | this.el.setAttribute('id', this._props.prefix + 'icons'); 40 | this._prependChild(document.body, this.el); 41 | }; 42 | /* 43 | Method to get icons shapes. 44 | @private 45 | */ 46 | 47 | 48 | Icons.prototype.getIcons = function getIcons() { 49 | var prefix = this._props.prefix; 50 | return '\n \n \n \n \n \n \n \n \n \n \n '; 51 | }; 52 | 53 | return Icons; 54 | }(_module2.default); 55 | 56 | exports.default = Icons; -------------------------------------------------------------------------------- /lib/components/label-button.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _buttonSwitch = require('./button-switch'); 18 | 19 | var _buttonSwitch2 = _interopRequireDefault(_buttonSwitch); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | require('../../css/blocks/label-button.postcss.css'); 24 | var CLASSES = require('../../css/blocks/label-button.postcss.css.json'); 25 | 26 | var LabelButton = function (_ButtonSwitch) { 27 | (0, _inherits3.default)(LabelButton, _ButtonSwitch); 28 | 29 | function LabelButton() { 30 | (0, _classCallCheck3.default)(this, LabelButton); 31 | return (0, _possibleConstructorReturn3.default)(this, _ButtonSwitch.apply(this, arguments)); 32 | } 33 | 34 | /* 35 | Method to declare defaults. 36 | @private 37 | @overrides @ OpacitySwitch 38 | */ 39 | LabelButton.prototype._declareDefaults = function _declareDefaults() { 40 | _ButtonSwitch.prototype._declareDefaults.call(this); 41 | this._defaults.title = 'speed (reset: alt + 1)'; 42 | }; 43 | /* 44 | Method to populate the label with progress text. 45 | @public 46 | @param {String} Text to set. 47 | */ 48 | 49 | 50 | LabelButton.prototype.setLabelText = function setLabelText(text) { 51 | this.label.innerHTML = text; 52 | }; 53 | 54 | /* 55 | ^ PUBLIC ^ 56 | v PPRIVATE v 57 | */ 58 | 59 | /* 60 | Initial render method. 61 | @private 62 | @overrides @ Button 63 | @returns this 64 | */ 65 | 66 | 67 | LabelButton.prototype._render = function _render() { 68 | _ButtonSwitch.prototype._render.call(this); 69 | this._addClass(this.el, CLASSES['label-button']); 70 | this._addLabel(); 71 | // this.setLabelText( this._props.progress ); 72 | }; 73 | /* 74 | Method to add label to the `el`. 75 | @private 76 | */ 77 | 78 | 79 | LabelButton.prototype._addLabel = function _addLabel() { 80 | this.label = this._createElement('div'); 81 | this.label.classList.add(CLASSES['label-button__label']); 82 | this.el.appendChild(this.label); 83 | }; 84 | 85 | return LabelButton; 86 | }(_buttonSwitch2.default); 87 | 88 | exports.default = LabelButton; -------------------------------------------------------------------------------- /lib/components/module.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _typeof2 = require('babel-runtime/helpers/typeof'); 6 | 7 | var _typeof3 = _interopRequireDefault(_typeof2); 8 | 9 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 10 | 11 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 12 | 13 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 14 | 15 | /* 16 | Base class for all modules. 17 | Extends _defaults to _props 18 | */ 19 | var Module = function () { 20 | /* 21 | constructor method calls scaffolding methods. 22 | */ 23 | function Module() { 24 | var o = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : {}; 25 | (0, _classCallCheck3.default)(this, Module); 26 | 27 | this._o = o; 28 | this._index = this._o.index || 0; 29 | this._declareDefaults(); 30 | this._extendDefaults(); 31 | this._vars(); 32 | this._render(); 33 | } 34 | /* 35 | Method to declare defaults. 36 | @private 37 | */ 38 | 39 | 40 | Module.prototype._declareDefaults = function _declareDefaults() { 41 | this._defaults = { 42 | className: '', 43 | parent: document.body, 44 | isPrepend: false, 45 | isRipple: false, 46 | prefix: '' 47 | }; 48 | }; 49 | /* 50 | Method to add pointer down even listener to el. 51 | @param {Object} HTMLElement to add event listener on. 52 | @param {Function} Event listener callback. 53 | */ 54 | 55 | 56 | Module.prototype._addPointerDownEvent = function _addPointerDownEvent(el, fn) { 57 | if (window.navigator.msPointerEnabled) { 58 | el.addEventListener('MSPointerDown', fn); 59 | } else if (window.ontouchstart !== undefined) { 60 | el.addEventListener('touchstart', fn); 61 | el.addEventListener('mousedown', fn); 62 | } else { 63 | el.addEventListener('mousedown', fn); 64 | } 65 | }; 66 | /* 67 | Method to add pointer up even listener to el. 68 | @param {Object} HTMLElement to add event listener on. 69 | @param {Function} Event listener callback. 70 | */ 71 | 72 | 73 | Module.prototype._addPointerUpEvent = function _addPointerUpEvent(el, fn) { 74 | if (window.navigator.msPointerEnabled) { 75 | el.addEventListener('MSPointerUp', fn); 76 | } else if (window.ontouchstart !== undefined) { 77 | el.addEventListener('touchend', fn); 78 | el.addEventListener('mouseup', fn); 79 | } else { 80 | el.addEventListener('mouseup', fn); 81 | } 82 | }; 83 | /* 84 | Method to check if variable holds link to a function. 85 | @param {Function?} A variable to check. 86 | @returns {Boolean} If passed variable is a function. 87 | */ 88 | 89 | 90 | Module.prototype._isFunction = function _isFunction(fn) { 91 | return typeof fn === 'function'; 92 | }; 93 | /* 94 | Method to a function or silently fail. 95 | @param {Function?} A variable to check. 96 | @param {Array like} Arguments. 97 | */ 98 | 99 | 100 | Module.prototype._callIfFunction = function _callIfFunction(fn) { 101 | Array.prototype.shift.call(arguments); 102 | this._isFunction(fn) && fn.apply(this, arguments); 103 | }; 104 | /* 105 | Method to declare module's variables. 106 | @private 107 | */ 108 | 109 | 110 | Module.prototype._vars = function _vars() {}; 111 | /* 112 | Method to render on initialization. 113 | @private 114 | */ 115 | 116 | 117 | Module.prototype._render = function _render() { 118 | this._addMainElement(); 119 | }; 120 | /* 121 | Method to add `this.el` on the module. 122 | @private 123 | @param {String} Tag name of the element. 124 | */ 125 | 126 | 127 | Module.prototype._addMainElement = function _addMainElement() { 128 | var tagName = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 'div'; 129 | 130 | var p = this._props; 131 | 132 | this.el = this._createElement(tagName); 133 | this._addMainClasses(); 134 | 135 | var method = p.isPrepend ? 'prepend' : 'append'; 136 | this['_' + method + 'Child'](p.parent, this.el); 137 | }; 138 | /* 139 | Method to classes on `this.el`. 140 | @private 141 | */ 142 | 143 | 144 | Module.prototype._addMainClasses = function _addMainClasses() { 145 | var p = this._props; 146 | if (p.className instanceof Array) { 147 | for (var i = 0; i < p.className.length; i++) { 148 | this._addClass(this.el, p.className[i]); 149 | } 150 | } else { 151 | this._addClass(this.el, p.className); 152 | } 153 | }; 154 | /* 155 | Method to add a class on el. 156 | @private 157 | @param {Object} HTML element to add the class on. 158 | @param {String} Class name to add. 159 | */ 160 | 161 | 162 | Module.prototype._addClass = function _addClass(el, className) { 163 | className && el.classList.add(className); 164 | }; 165 | /* 166 | Method to set property on the module. 167 | @private 168 | @param {String, Object} Name of the property to set 169 | or object with properties to set. 170 | @param {Any} Value for the property to set. Could be 171 | undefined if the first param is object. 172 | */ 173 | 174 | 175 | Module.prototype._setProp = function _setProp(attr, value) { 176 | if ((typeof attr === 'undefined' ? 'undefined' : (0, _typeof3.default)(attr)) === 'object') { 177 | for (var key in attr) { 178 | this._assignProp(key, attr[key]); 179 | } 180 | } else { 181 | this._assignProp(attr, value); 182 | } 183 | }; 184 | /* 185 | Method to assign single property's value. 186 | @private 187 | @param {String} Property name. 188 | @param {Any} Property value. 189 | */ 190 | 191 | 192 | Module.prototype._assignProp = function _assignProp(key, value) { 193 | this._props[key] = value; 194 | }; 195 | /* 196 | Method to copy `_o` options to `_props` object 197 | with fallback to `_defaults`. 198 | @private 199 | */ 200 | 201 | 202 | Module.prototype._extendDefaults = function _extendDefaults() { 203 | this._props = {}; 204 | // this._deltas = {}; 205 | for (var key in this._defaults) { 206 | var value = this._o[key]; 207 | this.isIt && console.log(key); 208 | // copy the properties to the _o object 209 | this._assignProp(key, value != null ? value : this._defaults[key]); 210 | } 211 | }; 212 | /* 213 | Method to create HTMLElement from tag name. 214 | @private 215 | @param {String} Name of the tag to create `HTML` element. 216 | @returns {Object} HtmlElement. 217 | */ 218 | 219 | 220 | Module.prototype._createElement = function _createElement(tagName) { 221 | return document.createElement(tagName); 222 | }; 223 | /* 224 | Method to create HTMLElement and append it to the `el` with a className. 225 | @private 226 | @param {String} The tagname for the HTMLElement. 227 | @param {String} Optional class name to add to the new child. 228 | @returns {Object} The newely created HTMLElement. 229 | */ 230 | 231 | 232 | Module.prototype._createChild = function _createChild(tagName, className) { 233 | var child = this._createElement('div'); 234 | className && child.classList.add(className); 235 | this.el.appendChild(child); 236 | return child; 237 | }; 238 | /* 239 | Method to prepend child to the el. 240 | @private 241 | @param {Object} Parent HTMLElement. 242 | @param {Object} Child HTMLElement. 243 | */ 244 | 245 | 246 | Module.prototype._appendChild = function _appendChild(el, childEl) { 247 | el.appendChild(childEl); 248 | }; 249 | /* 250 | Method to prepend child to the el. 251 | @private 252 | @param {Object} Parent HTMLElement. 253 | @param {Object} Child HTMLElement. 254 | */ 255 | 256 | 257 | Module.prototype._prependChild = function _prependChild(el, childEl) { 258 | el.insertBefore(childEl, el.firstChild); 259 | }; 260 | 261 | return Module; 262 | }(); 263 | 264 | exports.default = Module; -------------------------------------------------------------------------------- /lib/components/opacity-switch.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _icon = require('./icon'); 18 | 19 | var _icon2 = _interopRequireDefault(_icon); 20 | 21 | var _buttonSwitch = require('./button-switch'); 22 | 23 | var _buttonSwitch2 = _interopRequireDefault(_buttonSwitch); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | require('../../css/blocks/opacity-switch.postcss.css'); 28 | var CLASSES = require('../../css/blocks/opacity-switch.postcss.css.json'); 29 | 30 | var OpacitySwitch = function (_ButtonSwitch) { 31 | (0, _inherits3.default)(OpacitySwitch, _ButtonSwitch); 32 | 33 | function OpacitySwitch() { 34 | (0, _classCallCheck3.default)(this, OpacitySwitch); 35 | return (0, _possibleConstructorReturn3.default)(this, _ButtonSwitch.apply(this, arguments)); 36 | } 37 | 38 | /* 39 | Method to decalre defaults. 40 | @private 41 | @overrides @ ButtonSwitch 42 | */ 43 | OpacitySwitch.prototype._declareDefaults = function _declareDefaults() { 44 | _ButtonSwitch.prototype._declareDefaults.call(this); 45 | this._defaults.icon = ''; 46 | this._defaults.iconSize = ''; 47 | }; 48 | /* 49 | Method to render the module. 50 | @private 51 | @overrides @ ButtonSwitch 52 | */ 53 | 54 | 55 | OpacitySwitch.prototype._render = function _render() { 56 | _ButtonSwitch.prototype._render.call(this); 57 | this.el.classList.add(CLASSES['opacity-switch']); 58 | 59 | var p = this._props, 60 | icon = new _icon2.default({ 61 | parent: this.el, 62 | shape: p.icon, 63 | size: p.iconSize, 64 | className: CLASSES['icon'], 65 | prefix: p.prefix 66 | }); 67 | this.el.appendChild(icon.el); 68 | }; 69 | /* 70 | Method to react to switch state change. 71 | @private 72 | @overrides @ ButtonSwitch 73 | */ 74 | 75 | 76 | OpacitySwitch.prototype._setState = function _setState() { 77 | var method = this._props.isOn ? 'add' : 'remove'; 78 | this.el.classList[method](CLASSES['is-on']); 79 | }; 80 | 81 | return OpacitySwitch; 82 | }(_buttonSwitch2.default); 83 | 84 | exports.default = OpacitySwitch; -------------------------------------------------------------------------------- /lib/components/play-button.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _iconFork = require('./icon-fork'); 18 | 19 | var _iconFork2 = _interopRequireDefault(_iconFork); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | require('../../css/blocks/play-button.postcss.css'); 24 | var CLASSES = require('../../css/blocks/play-button.postcss.css.json'); 25 | // PLAYER_BTN_CLASSES = require('css/blocks/player-button.postcss.css.json'); 26 | 27 | var PlayButton = function (_IconFork) { 28 | (0, _inherits3.default)(PlayButton, _IconFork); 29 | 30 | function PlayButton() { 31 | (0, _classCallCheck3.default)(this, PlayButton); 32 | return (0, _possibleConstructorReturn3.default)(this, _IconFork.apply(this, arguments)); 33 | } 34 | 35 | /* 36 | Method to declare defaults on the module. 37 | @private 38 | @overrides @ ButtonSwitch 39 | */ 40 | PlayButton.prototype._declareDefaults = function _declareDefaults() { 41 | _IconFork.prototype._declareDefaults.call(this); 42 | this._defaults.icon1 = 'pause'; 43 | this._defaults.icon2 = 'play'; 44 | this._defaults.title = 'play/pause (alt + p)'; 45 | }; 46 | /* 47 | Method to render the module. 48 | @private 49 | */ 50 | 51 | 52 | PlayButton.prototype._render = function _render() { 53 | _IconFork.prototype._render.call(this); 54 | this._addClass(this.el, CLASSES['play-button']); 55 | }; 56 | 57 | return PlayButton; 58 | }(_iconFork2.default); 59 | 60 | exports.default = PlayButton; -------------------------------------------------------------------------------- /lib/components/player-slider.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _slider = require('./slider'); 18 | 19 | var _slider2 = _interopRequireDefault(_slider); 20 | 21 | var _module = require('./module'); 22 | 23 | var _module2 = _interopRequireDefault(_module); 24 | 25 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 26 | 27 | require('../../css/blocks/player-slider.postcss.css'); 28 | var CLASSES = require('../../css/blocks/player-slider.postcss.css.json'); 29 | var SLIDER_CLASSES = require('../../css/blocks/slider.postcss.css.json'); 30 | 31 | var PlayerSlider = function (_Module) { 32 | (0, _inherits3.default)(PlayerSlider, _Module); 33 | 34 | function PlayerSlider() { 35 | (0, _classCallCheck3.default)(this, PlayerSlider); 36 | return (0, _possibleConstructorReturn3.default)(this, _Module.apply(this, arguments)); 37 | } 38 | 39 | /* 40 | Method to declare _defaults. 41 | @private 42 | @overrides @ Module 43 | */ 44 | PlayerSlider.prototype._declareDefaults = function _declareDefaults() { 45 | this._defaults = { 46 | className: CLASSES['player-slider'], 47 | parent: document.body, 48 | progress: 0, 49 | leftProgress: 0, 50 | rightProgress: 1, 51 | isBounds: false, 52 | onLeftProgress: null, 53 | onProgress: null, 54 | onRightProgress: null, 55 | onSeekStart: null, 56 | onSeekEnd: null 57 | }; 58 | }; 59 | /* 60 | Method to disable bounds. 61 | @public 62 | @returns this. 63 | */ 64 | 65 | 66 | PlayerSlider.prototype.disableBounds = function disableBounds() { 67 | this.track.setBounds(0, 1); 68 | this.rightBound.hide(); 69 | this.leftBound.hide(); 70 | return this; 71 | }; 72 | /* 73 | Method to enable bounds. 74 | @public 75 | @returns this. 76 | */ 77 | 78 | 79 | PlayerSlider.prototype.enableBounds = function enableBounds() { 80 | var p = this._props; 81 | this.track.setBounds(p.leftProgress, p.rightProgress); 82 | this.rightBound.show(); 83 | this.leftBound.show(); 84 | return this; 85 | }; 86 | /* 87 | Method to set progress of the track. 88 | @public 89 | @param {Number} Progress to set [0...1]. 90 | @returns this. 91 | */ 92 | 93 | 94 | PlayerSlider.prototype.setTrackProgress = function setTrackProgress(p) { 95 | this.track.setProgress(p); 96 | return this; 97 | }; 98 | /* 99 | Method to decrease progress value. 100 | @public 101 | @param {Number} Value that the slider should be decreased by. 102 | @returns this. 103 | */ 104 | 105 | 106 | PlayerSlider.prototype.decreaseProgress = function decreaseProgress() { 107 | var amount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.01; 108 | 109 | var progress = this.track._progress; 110 | progress -= amount; 111 | progress = progress < 0 ? 0 : progress; 112 | this.setTrackProgress(progress); 113 | return this; 114 | }; 115 | /* 116 | Method to inclease progress value. 117 | @public 118 | @param {Number} Value that the slider should be increased by. 119 | @returns this. 120 | */ 121 | 122 | 123 | PlayerSlider.prototype.increaseProgress = function increaseProgress() { 124 | var amount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.01; 125 | 126 | var progress = this.track._progress; 127 | progress += amount; 128 | progress = progress > 1 ? 1 : progress; 129 | this.setTrackProgress(progress); 130 | return this; 131 | }; 132 | /* 133 | Initial render method. 134 | @private 135 | @overrides @ Module 136 | @returns this 137 | */ 138 | 139 | 140 | PlayerSlider.prototype._render = function _render() { 141 | var p = this._props; 142 | 143 | this._addMainElement(); 144 | this.el.classList.add(SLIDER_CLASSES.slider); 145 | 146 | this.leftBound = new _slider2.default({ 147 | isBound: true, 148 | parent: this.el, 149 | isRipple: false, 150 | onProgress: this._onLeftBoundProgress.bind(this), 151 | onSeekStart: p.onSeekStart, 152 | onSeekEnd: p.onSeekEnd 153 | }); 154 | 155 | this.track = new _slider2.default({ 156 | parent: this.el, 157 | className: CLASSES.slider, 158 | onProgress: this._onTrackProgress.bind(this), 159 | onSeekStart: p.onSeekStart, 160 | onSeekEnd: p.onSeekEnd 161 | }); 162 | this.rightBound = new _slider2.default({ 163 | isBound: true, 164 | parent: this.el, 165 | isRipple: false, 166 | isInversed: true, 167 | onProgress: this._onRightBoundProgress.bind(this), 168 | onSeekStart: p.onSeekStart, 169 | onSeekEnd: p.onSeekEnd 170 | }); 171 | 172 | this.rightBound.setProgress(p.rightProgress); 173 | this.track.setProgress(p.progress); 174 | this.leftBound.setProgress(p.leftProgress); 175 | 176 | p.parent.appendChild(this.el); 177 | }; 178 | /* 179 | Method that should be called on track update. 180 | @private 181 | @param {Number} Track progress value [0...1]. 182 | */ 183 | 184 | 185 | PlayerSlider.prototype._onTrackProgress = function _onTrackProgress(p) { 186 | this._callIfFunction(this._props.onProgress, p); 187 | }; 188 | /* 189 | Method that should be called on left bound update. 190 | @private 191 | @param {Number} Track progress value [0...1]. 192 | */ 193 | 194 | 195 | PlayerSlider.prototype._onLeftBoundProgress = function _onLeftBoundProgress(p) { 196 | if (!this._props.isBounds) { 197 | return; 198 | } 199 | this._props.leftProgress = p; 200 | this.track.setMinBound(p); 201 | this.rightBound.setMinBound(p); 202 | this._callIfFunction(this._props.onLeftProgress, p); 203 | }; 204 | /* 205 | Method that should be called on right bound update. 206 | @private 207 | @param {Number} Track progress value [0...1]. 208 | */ 209 | 210 | 211 | PlayerSlider.prototype._onRightBoundProgress = function _onRightBoundProgress(p) { 212 | if (!this._props.isBounds) { 213 | return; 214 | } 215 | this._props.rightProgress = p; 216 | this.track.setMaxBound(p); 217 | this.leftBound.setMaxBound(p); 218 | this._callIfFunction(this._props.onRightProgress, p); 219 | }; 220 | 221 | return PlayerSlider; 222 | }(_module2.default); 223 | 224 | exports.default = PlayerSlider; -------------------------------------------------------------------------------- /lib/components/repeat-button.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _opacitySwitch = require('./opacity-switch'); 18 | 19 | var _opacitySwitch2 = _interopRequireDefault(_opacitySwitch); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | require('../../css/blocks/repeat-button.postcss.css'); 24 | var CLASSES = require('../../css/blocks/repeat-button.postcss.css.json'); 25 | 26 | var RepeatButton = function (_OpacitySwitch) { 27 | (0, _inherits3.default)(RepeatButton, _OpacitySwitch); 28 | 29 | function RepeatButton() { 30 | (0, _classCallCheck3.default)(this, RepeatButton); 31 | return (0, _possibleConstructorReturn3.default)(this, _OpacitySwitch.apply(this, arguments)); 32 | } 33 | 34 | /* 35 | Method to declare defaults. 36 | @private 37 | @overrides @ OpacitySwitch 38 | */ 39 | RepeatButton.prototype._declareDefaults = function _declareDefaults() { 40 | _OpacitySwitch.prototype._declareDefaults.call(this); 41 | this._defaults.icon = 'repeat'; 42 | this._defaults.iconSize = 'x2'; 43 | this._defaults.title = 'repeat (alt + r)'; 44 | }; 45 | /* 46 | Initial render method. 47 | @private 48 | @overrides @ Button 49 | @returns this 50 | */ 51 | 52 | 53 | RepeatButton.prototype._render = function _render() { 54 | _OpacitySwitch.prototype._render.call(this); 55 | this._addClass(this.el, CLASSES['repeat-button']); 56 | }; 57 | 58 | return RepeatButton; 59 | }(_opacitySwitch2.default); 60 | 61 | exports.default = RepeatButton; -------------------------------------------------------------------------------- /lib/components/ripple.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _module = require('./module'); 18 | 19 | var _module2 = _interopRequireDefault(_module); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | var Ripple = function (_Module) { 24 | (0, _inherits3.default)(Ripple, _Module); 25 | 26 | function Ripple() { 27 | (0, _classCallCheck3.default)(this, Ripple); 28 | return (0, _possibleConstructorReturn3.default)(this, _Module.apply(this, arguments)); 29 | } 30 | 31 | /* 32 | Method to declare defaults. 33 | @private 34 | @overrides @ Module. 35 | */ 36 | Ripple.prototype._declareDefaults = function _declareDefaults() { 37 | _Module.prototype._declareDefaults.call(this); 38 | this._defaults.withHold = true; 39 | }; 40 | /* 41 | Method to render the component. 42 | @private 43 | @overrides @ Module 44 | */ 45 | 46 | 47 | Ripple.prototype._render = function _render() { 48 | _Module.prototype._render.call(this); 49 | this.curtain = document.createElement('div'); 50 | // this.curtain.style.background = 'rgba(255,255,255,.15)'; 51 | // this.curtain.style.background = 'yellow'; 52 | this.curtain.style.position = 'absolute'; 53 | this.curtain.style.width = '100%'; 54 | this.curtain.style.height = '100%'; 55 | this.curtain.style.left = 0; 56 | this.curtain.style.top = 0; 57 | this.curtain.style.zIndex = 1; 58 | 59 | this.el.appendChild(this.curtain); 60 | 61 | if (mojs.Shape) { 62 | this._addRipple(); 63 | } 64 | }; 65 | /* 66 | Method to construct ripple object. 67 | @private 68 | */ 69 | 70 | 71 | Ripple.prototype._addRipple = function _addRipple() { 72 | var _this2 = this, 73 | _ref; 74 | 75 | this.shape = new mojs.Shape((_ref = { 76 | parent: this.el, 77 | left: 0, top: this._o.top || 0, 78 | // strokeWidth: 10, 79 | strokeWidth: { 10: 0 }, 80 | fill: 'none', 81 | stroke: 'hotpink' 82 | }, _ref['fill'] = 'hotpink', _ref.fillOpacity = .75, _ref.opacity = { .85: 0 }, _ref.radius = 40, _ref.scale = { 0: 1 }, _ref.isShowEnd = false, _ref.onStart = function onStart() { 83 | _this2.isStart = true; 84 | }, _ref.onUpdate = this._onUpdate.bind(this), _ref.onComplete = function onComplete() { 85 | _this2.isStart = false; 86 | }, _ref)); 87 | }; 88 | /* 89 | Method that is invoked on ripple update. 90 | @private 91 | @param {Number} Curret progress [0...1]. 92 | */ 93 | 94 | 95 | Ripple.prototype._onUpdate = function _onUpdate(p) { 96 | if (!this._props.withHold) { 97 | return; 98 | } 99 | if (p >= .15 && this.isStart && !this.isRelease) { 100 | this.isStart = false; 101 | 102 | if (mojs.Shape) { 103 | this.shape.setSpeed(.02); 104 | } 105 | } 106 | }; 107 | /* 108 | Method that should be run on touch serface release. 109 | @private 110 | */ 111 | 112 | 113 | Ripple.prototype._release = function _release() { 114 | if (!this._props.withHold) { 115 | return; 116 | } 117 | this.isRelease = true; 118 | 119 | if (mojs.Shape) { 120 | this.shape.setSpeed(1).play(); 121 | } 122 | }; 123 | /* 124 | Method that should be run on touch serface hold. 125 | @private 126 | @param {Object} Origin event object. 127 | */ 128 | 129 | 130 | Ripple.prototype._hold = function _hold(e) { 131 | var x = e.offsetX != null ? e.offsetX : e.layerX, 132 | y = e.offsetY != null ? e.offsetY : e.layerY; 133 | 134 | this.isRelease = false; 135 | if (mojs.Shape) { 136 | this.shape.tune({ x: x, y: y }).replay(); 137 | } 138 | }; 139 | /* 140 | Method that should be run on touch serface cancel. 141 | @private 142 | */ 143 | 144 | 145 | Ripple.prototype._cancel = function _cancel() { 146 | if (!this._props.withHold) { 147 | return; 148 | } 149 | this.isRelease = true; 150 | 151 | if (mojs.Shape) { 152 | this.shape.pause().setSpeed(1).playBackward(); 153 | } 154 | }; 155 | 156 | return Ripple; 157 | }(_module2.default); 158 | 159 | exports.default = Ripple; -------------------------------------------------------------------------------- /lib/components/slider.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _module = require('./module'); 18 | 19 | var _module2 = _interopRequireDefault(_module); 20 | 21 | var _handle = require('./handle'); 22 | 23 | var _handle2 = _interopRequireDefault(_handle); 24 | 25 | var _track = require('./track'); 26 | 27 | var _track2 = _interopRequireDefault(_track); 28 | 29 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 30 | 31 | require('../../css/blocks/slider.postcss.css'); 32 | var CLASSES = require('../../css/blocks/slider.postcss.css.json'); 33 | 34 | var Slider = function (_Module) { 35 | (0, _inherits3.default)(Slider, _Module); 36 | 37 | function Slider() { 38 | (0, _classCallCheck3.default)(this, Slider); 39 | return (0, _possibleConstructorReturn3.default)(this, _Module.apply(this, arguments)); 40 | } 41 | 42 | /* 43 | Method to declare _defaults. 44 | @private 45 | @overrides @ Module 46 | */ 47 | Slider.prototype._declareDefaults = function _declareDefaults() { 48 | this._defaults = { 49 | className: '', 50 | parent: document.body, 51 | isBound: false, 52 | isInversed: false, 53 | isRipple: true, 54 | isProgress: true, 55 | onProgress: null, 56 | onSeekStart: null, 57 | onSeekEnd: null, 58 | direction: 'x', 59 | snapPoint: 0, 60 | snapStrength: 0 61 | }; 62 | }; 63 | /* 64 | Method to set slider progress. 65 | @public 66 | @param {Number} Progress to set. 67 | @returns this. 68 | */ 69 | 70 | 71 | Slider.prototype.setProgress = function setProgress(progress) { 72 | this.handle.setProgress(progress); 73 | this.track.setProgress(progress); 74 | return this; 75 | }; 76 | /* 77 | Method to set bounds of progress. 78 | @public 79 | @param {Number} Min bound to set [0...1]. 80 | @param {Number} Max bound to set [0...1]. 81 | @returns this. 82 | */ 83 | 84 | 85 | Slider.prototype.setBounds = function setBounds(min, max) { 86 | this.handle.setBounds(min, max); 87 | this.track.setBounds(min, max); 88 | return this; 89 | }; 90 | /* 91 | Method to set min bound of progress. 92 | @public 93 | @param {Number} Min bound to set [0...1]. 94 | @returns this. 95 | */ 96 | 97 | 98 | Slider.prototype.setMinBound = function setMinBound(min) { 99 | this.handle.setMinBound(min); 100 | this.track.setMinBound(min); 101 | return this; 102 | }; 103 | /* 104 | Method to set max bound of progress. 105 | @public 106 | @param {Number} Max bound to set [0...1]. 107 | @returns this. 108 | */ 109 | 110 | 111 | Slider.prototype.setMaxBound = function setMaxBound(max) { 112 | this.handle.setMaxBound(max); 113 | this.track.setMaxBound(max); 114 | return this; 115 | }; 116 | /* 117 | Method to hide elements. 118 | @public 119 | */ 120 | 121 | 122 | Slider.prototype.show = function show() { 123 | this.track.el.style.display = 'block'; 124 | this.handle.el.style.display = 'block'; 125 | }; 126 | /* 127 | Method to hide elements. 128 | @public 129 | */ 130 | 131 | 132 | Slider.prototype.hide = function hide() { 133 | this.track.el.style.display = 'none'; 134 | this.handle.el.style.display = 'none'; 135 | }; 136 | /* 137 | Method to render the component. 138 | @private 139 | @overrides @ Module 140 | */ 141 | 142 | 143 | Slider.prototype._render = function _render() { 144 | var p = this._props; 145 | 146 | if (!p.isBound) { 147 | var el = this._createElement('div'), 148 | classList = el.classList; 149 | this.el = el; 150 | 151 | this.inner = this._createElement('div'); 152 | this.inner.classList.add(CLASSES['slider__inner']); 153 | this.el.appendChild(this.inner); 154 | 155 | classList.add(CLASSES.slider); 156 | p.direction === 'y' && classList.add(CLASSES['is-y']); 157 | p.className && classList.add(p.className); 158 | p.parent.appendChild(el); 159 | } 160 | 161 | var rootEl = !p.isBound ? this.inner : p.parent; 162 | 163 | this.track = new _track2.default({ 164 | className: CLASSES.track, 165 | onProgress: this._onTrackProgress.bind(this), 166 | onSeekStart: p.onSeekStart, 167 | onSeekEnd: p.onSeekEnd, 168 | isBound: p.isBound, 169 | isInversed: p.isInversed, 170 | isRipple: p.isRipple, 171 | isProgress: p.isProgress, 172 | parent: rootEl, 173 | direction: p.direction, 174 | snapPoint: p.snapPoint, 175 | snapStrength: p.snapStrength 176 | }); 177 | rootEl.appendChild(this.track.el); 178 | 179 | var handleClass = [CLASSES.handle]; 180 | if (!p.isBound) { 181 | handleClass.push(CLASSES['progress-handle']); 182 | } 183 | 184 | this.handle = new _handle2.default({ 185 | className: handleClass, 186 | onProgress: this._onHandleProgress.bind(this), 187 | onSeekStart: p.onSeekStart, 188 | onSeekEnd: p.onSeekEnd, 189 | isBound: p.isBound, 190 | isInversed: p.isInversed, 191 | parent: rootEl, 192 | direction: p.direction, 193 | snapPoint: p.snapPoint, 194 | snapStrength: p.snapStrength 195 | }); 196 | rootEl.appendChild(this.handle.el); 197 | }; 198 | /* 199 | Method that is invoked on handle progress change. 200 | @private 201 | @param {Number} Progress [0...1]. 202 | */ 203 | 204 | 205 | Slider.prototype._onHandleProgress = function _onHandleProgress(p) { 206 | this.track.setProgress(p, false); 207 | this._onProgress(p); 208 | }; 209 | /* 210 | Method that is invoked on track progress change. 211 | @private 212 | @param {Number} Progress [0...1]. 213 | */ 214 | 215 | 216 | Slider.prototype._onTrackProgress = function _onTrackProgress(p) { 217 | this.handle.setProgress(p, false); 218 | this._onProgress(p); 219 | }; 220 | /* 221 | Method to call onProgress callback. 222 | @private 223 | @param {Number} Progress value [0...1]. 224 | */ 225 | 226 | 227 | Slider.prototype._onProgress = function _onProgress(progress) { 228 | var p = this._props; 229 | if (typeof p.onProgress === 'function' && this._progress !== progress) { 230 | this._progress = progress; 231 | p.onProgress.call(this, progress); 232 | } 233 | }; 234 | 235 | return Slider; 236 | }(_module2.default); 237 | 238 | exports.default = Slider; -------------------------------------------------------------------------------- /lib/components/speed-control.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _module = require('./module'); 18 | 19 | var _module2 = _interopRequireDefault(_module); 20 | 21 | var _labelButton = require('./label-button'); 22 | 23 | var _labelButton2 = _interopRequireDefault(_labelButton); 24 | 25 | var _slider = require('./slider'); 26 | 27 | var _slider2 = _interopRequireDefault(_slider); 28 | 29 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 30 | 31 | require('../../css/blocks/speed-control.postcss.css'); 32 | var CLASSES = require('../../css/blocks/speed-control.postcss.css.json'); 33 | 34 | var SpeedControl = function (_Module) { 35 | (0, _inherits3.default)(SpeedControl, _Module); 36 | 37 | function SpeedControl() { 38 | (0, _classCallCheck3.default)(this, SpeedControl); 39 | return (0, _possibleConstructorReturn3.default)(this, _Module.apply(this, arguments)); 40 | } 41 | 42 | /* 43 | Method to declare defaults for the module. 44 | @private 45 | @overrides @ Module 46 | */ 47 | SpeedControl.prototype._declareDefaults = function _declareDefaults() { 48 | _Module.prototype._declareDefaults.call(this); 49 | this._defaults.isOn = false; 50 | this._defaults.speed = 1; 51 | this._defaults.progress = .5; 52 | this._defaults.onSpeedChange = null; 53 | this._defaults.onIsSpeed = null; 54 | }; 55 | /* 56 | Method to reset speed to 1x. 57 | @public 58 | @returns this 59 | */ 60 | 61 | 62 | SpeedControl.prototype.reset = function reset() { 63 | this._onDoubleTap(); 64 | }; 65 | /* 66 | Method to decrease speed value. 67 | @public 68 | @param {Number} Value that the slider should be decreased by. 69 | @returns this. 70 | */ 71 | 72 | 73 | SpeedControl.prototype.decreaseSpeed = function decreaseSpeed() { 74 | var amount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.01; 75 | 76 | var p = this._props; 77 | p.progress -= amount; 78 | p.progress = p.progress < 0 ? 0 : p.progress; 79 | this.slider.setProgress(p.progress); 80 | return this; 81 | }; 82 | /* 83 | Method to inclease speed value. 84 | @public 85 | @param {Number} Value that the slider should be increased by. 86 | @returns this. 87 | */ 88 | 89 | 90 | SpeedControl.prototype.increaseSpeed = function increaseSpeed() { 91 | var amount = arguments.length > 0 && arguments[0] !== undefined ? arguments[0] : 0.01; 92 | 93 | var p = this._props; 94 | p.progress += amount; 95 | p.progress = p.progress > 1 ? 1 : p.progress; 96 | this.slider.setProgress(p.progress); 97 | return this; 98 | }; 99 | /* 100 | Initial render method. 101 | @private 102 | @overrides @ Module 103 | */ 104 | 105 | 106 | SpeedControl.prototype._render = function _render() { 107 | var p = this._props, 108 | className = 'speed-control', 109 | slider = this._createElement('div'), 110 | sliderIn = this._createElement('div'), 111 | icon = this._createElement('div'); 112 | 113 | this._addMainElement(); 114 | this.el.classList.add(CLASSES[className]); 115 | // places for child components 116 | slider.classList.add(CLASSES[className + '__slider']); 117 | // sliderIn.classList.add( CLASSES[ `${ className }__slider-inner` ] ); 118 | // slider.appendChild( sliderIn ); 119 | this.el.appendChild(slider); 120 | // child components 121 | this.labelButton = new _labelButton2.default({ 122 | parent: this.el, 123 | isOn: p.isOn, 124 | className: CLASSES[className + '__icon'], 125 | onStateChange: this._onButtonStateChange.bind(this), 126 | onDoubleTap: this._onDoubleTap.bind(this) 127 | }); 128 | this.slider = new _slider2.default({ 129 | parent: slider, 130 | isProgress: false, 131 | direction: 'y', 132 | onProgress: this._onSliderProgress.bind(this), 133 | snapPoint: .5, 134 | snapStrength: .05 135 | }); 136 | 137 | this.slider.setProgress(this._speedToProgress(this._props.speed)); 138 | }; 139 | /* 140 | Method that is invoked on slider progress. 141 | @private 142 | @param {Number} Progress of the slider. 143 | */ 144 | 145 | 146 | SpeedControl.prototype._onSliderProgress = function _onSliderProgress(p) { 147 | // progress should be at least 0.01 148 | p = Math.max(p, 0.0001); 149 | 150 | var props = this._props, 151 | args = []; 152 | 153 | this._callIfFunction(props.onSpeedChange, this._progressToSpeed(p), p); 154 | this.labelButton.setLabelText(this._progressToLabel(props.progress = p)); 155 | }; 156 | /* 157 | Method that is invoked on button state change. 158 | @private 159 | @param {Boolean} State of the button switch. 160 | */ 161 | 162 | 163 | SpeedControl.prototype._onButtonStateChange = function _onButtonStateChange(isOn) { 164 | var method = isOn ? 'add' : 'remove'; 165 | this.el.classList[method](CLASSES['is-on']); 166 | this._callIfFunction(this._props.onIsSpeed, isOn); 167 | }; 168 | /* 169 | Method to recalc progress to label string. 170 | @private 171 | @param {Number} Progress [0...1]. 172 | @returns {String} String for a label to set. 173 | */ 174 | 175 | 176 | SpeedControl.prototype._progressToLabel = function _progressToLabel(progress) { 177 | var text = this._progressToSpeed(progress).toFixed(2), 178 | zeros = /\.+00$/; 179 | 180 | if (text.match(zeros)) { 181 | text = text.replace(zeros, ''); 182 | } 183 | 184 | return text + 'x'; 185 | }; 186 | /* 187 | Method to recalc progress to speed. 188 | @private 189 | @param {Number} Progress [0...1]. 190 | @returns {Number} Speed [0...10]. 191 | */ 192 | 193 | 194 | SpeedControl.prototype._progressToSpeed = function _progressToSpeed(progress) { 195 | var speed = progress; 196 | if (progress < .5) { 197 | speed = 2 * progress; 198 | } 199 | if (progress === .5) { 200 | speed = 1; 201 | } 202 | if (progress > .5) { 203 | progress -= .5; 204 | speed = 1 + progress * 18; 205 | // console.log( speed/10, mojs.easing.cubic.out( speed/10 ) ); 206 | // console.log( .5 + ( speed - 1 ) / 18 ); 207 | } 208 | return speed; 209 | }; 210 | /* 211 | Method to recalc progress to speed. 212 | @private 213 | @param {Number} Progress [0...1]. 214 | @returns {Number} Speed [0...10]. 215 | */ 216 | 217 | 218 | SpeedControl.prototype._speedToProgress = function _speedToProgress(speed) { 219 | var progress = speed; 220 | if (speed < 1) { 221 | progress = speed / 2; 222 | } 223 | if (speed === 1) { 224 | progress = .5; 225 | } 226 | if (speed > 1) { 227 | progress = .5 + (speed - 1) / 18; 228 | } 229 | return progress; 230 | }; 231 | /* 232 | Method that is invoked on double button tap. 233 | @private 234 | */ 235 | 236 | 237 | SpeedControl.prototype._onDoubleTap = function _onDoubleTap() { 238 | this.slider.setProgress(.5); 239 | this.labelButton.off(); 240 | }; 241 | 242 | return SpeedControl; 243 | }(_module2.default); 244 | 245 | exports.default = SpeedControl; -------------------------------------------------------------------------------- /lib/components/stop-button.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _iconButton = require('./icon-button'); 18 | 19 | var _iconButton2 = _interopRequireDefault(_iconButton); 20 | 21 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 22 | 23 | require('../../css/blocks/stop-button.postcss.css'); 24 | var CLASSES = require('../../css/blocks/stop-button.postcss.css.json'); 25 | 26 | var StopButton = function (_IconButton) { 27 | (0, _inherits3.default)(StopButton, _IconButton); 28 | 29 | function StopButton() { 30 | (0, _classCallCheck3.default)(this, StopButton); 31 | return (0, _possibleConstructorReturn3.default)(this, _IconButton.apply(this, arguments)); 32 | } 33 | 34 | StopButton.prototype._declareDefaults = function _declareDefaults() { 35 | _IconButton.prototype._declareDefaults.call(this); 36 | this._defaults.icon = 'stop'; 37 | this._defaults.title = 'stop (alt + s)'; 38 | }; 39 | /* 40 | Initial render method. 41 | @private 42 | @overrides @ Button 43 | @returns this 44 | */ 45 | 46 | 47 | StopButton.prototype._render = function _render() { 48 | _IconButton.prototype._render.call(this); 49 | this._addClass(this.el, CLASSES['stop-button']); 50 | }; 51 | 52 | return StopButton; 53 | }(_iconButton2.default); 54 | 55 | exports.default = StopButton; -------------------------------------------------------------------------------- /lib/components/track.js: -------------------------------------------------------------------------------- 1 | 'use strict'; 2 | 3 | exports.__esModule = true; 4 | 5 | var _classCallCheck2 = require('babel-runtime/helpers/classCallCheck'); 6 | 7 | var _classCallCheck3 = _interopRequireDefault(_classCallCheck2); 8 | 9 | var _possibleConstructorReturn2 = require('babel-runtime/helpers/possibleConstructorReturn'); 10 | 11 | var _possibleConstructorReturn3 = _interopRequireDefault(_possibleConstructorReturn2); 12 | 13 | var _inherits2 = require('babel-runtime/helpers/inherits'); 14 | 15 | var _inherits3 = _interopRequireDefault(_inherits2); 16 | 17 | var _handle = require('./handle'); 18 | 19 | var _handle2 = _interopRequireDefault(_handle); 20 | 21 | var _hammerjs = require('hammerjs'); 22 | 23 | var _hammerjs2 = _interopRequireDefault(_hammerjs); 24 | 25 | var _ripple = require('./ripple'); 26 | 27 | var _ripple2 = _interopRequireDefault(_ripple); 28 | 29 | function _interopRequireDefault(obj) { return obj && obj.__esModule ? obj : { default: obj }; } 30 | 31 | require('../../css/blocks/track.postcss.css'); 32 | var CLASSES = require('../../css/blocks/track.postcss.css.json'); 33 | 34 | var Track = function (_Handle) { 35 | (0, _inherits3.default)(Track, _Handle); 36 | 37 | function Track() { 38 | (0, _classCallCheck3.default)(this, Track); 39 | return (0, _possibleConstructorReturn3.default)(this, _Handle.apply(this, arguments)); 40 | } 41 | 42 | /* 43 | Method to declare _defaults. 44 | @private 45 | @overrides @ Handle 46 | */ 47 | Track.prototype._declareDefaults = function _declareDefaults() { 48 | _Handle.prototype._declareDefaults.call(this); 49 | this._defaults.isProgress = true; 50 | this._defaults.isRipple = true; 51 | }; 52 | /* 53 | Method to render the component. 54 | @private 55 | @overrides @ Handle 56 | */ 57 | 58 | 59 | Track.prototype._render = function _render() { 60 | _Handle.prototype._render.call(this); 61 | if (!this._props.isRipple) { 62 | return; 63 | } 64 | this.ripple = new _ripple2.default({ 65 | withHold: false, 66 | className: CLASSES['track__ripple'], 67 | // top: '50%', 68 | parent: this.el 69 | }); 70 | }; 71 | /* 72 | Method to apply shift to the DOMElement. 73 | @private 74 | @overrides @ Handle. 75 | @param {Number} Shift in pixels.x 76 | */ 77 | 78 | 79 | Track.prototype._applyShift = function _applyShift(shift) { 80 | if (!this._props.isProgress) { 81 | return; 82 | } 83 | if (this._props.isInversed) { 84 | shift = this._maxWidth - shift; 85 | } 86 | var transform = 'scaleX( ' + shift + ' ) translateZ(0)'; 87 | this.trackProgressEl.style.transform = transform; 88 | // this.trackProgressEl.style.width = `${shift}px`; 89 | }; 90 | /* 91 | Method to add classes on `this.el`. 92 | @private 93 | @overrides @ Handle. 94 | */ 95 | 96 | 97 | Track.prototype._addMainClasses = function _addMainClasses() { 98 | var p = this._props, 99 | classList = this.el.classList; 100 | 101 | classList.add(CLASSES.track); 102 | if (p.isInversed) { 103 | classList.add(CLASSES['is-inversed']); 104 | } 105 | if (p.isBound) { 106 | classList.add(CLASSES['is-bound']); 107 | } 108 | if (p.direction === 'y') { 109 | classList.add(CLASSES['is-y']); 110 | } 111 | }; 112 | /* 113 | Method to add DOM elements on render. 114 | @private 115 | */ 116 | 117 | 118 | Track.prototype._addElements = function _addElements() { 119 | var p = this._props; 120 | 121 | if (p.isProgress) { 122 | // progress track 123 | var trackP = document.createElement('div'); 124 | trackP.classList.add('' + CLASSES['track__track-progress']); 125 | this.trackProgressEl = trackP; 126 | this.el.appendChild(trackP); 127 | } 128 | // track 129 | if (!p.isBound) { 130 | var track = document.createElement('div'); 131 | track.classList.add('' + CLASSES.track__track); 132 | this.el.appendChild(track); 133 | } 134 | }; 135 | /* 136 | Callback for pointer down on main el. 137 | @private 138 | @param {Object} Original event object. 139 | @overrides @ Handle 140 | */ 141 | 142 | 143 | Track.prototype._pointerDown = function _pointerDown(e) { 144 | var p = this._props, 145 | x = p.direction === 'x' ? e.layerX : e.layerY; 146 | this._isPointerDown = true; 147 | 148 | if (p.direction === 'y') { 149 | x = this._maxWidth - e.layerY; 150 | } 151 | x = this._props.isInversed && x < 0 ? this._maxWidth + x : x; 152 | 153 | // if near the snap point - set it to the snap point 154 | var progress = this._shiftToProgress(x); 155 | progress = Math.abs(p.snapPoint - progress) < p.snapStrength ? p.snapPoint : progress; 156 | this.setProgress(progress); 157 | 158 | p.isRipple && this.ripple._hold(e); 159 | this._callIfFunction(p.onSeekStart, e); 160 | }; 161 | 162 | return Track; 163 | }(_handle2.default); 164 | 165 | exports.default = Track; -------------------------------------------------------------------------------- /logo.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojs/mojs-player/1efc22e32ae2a4dec52609495e477a67b17371e5/logo.png -------------------------------------------------------------------------------- /mockups/mojs-player.sketch: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojs/mojs-player/1efc22e32ae2a4dec52609495e477a67b17371e5/mockups/mojs-player.sketch -------------------------------------------------------------------------------- /mockups/mojs-player@x4.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/mojs/mojs-player/1efc22e32ae2a4dec52609495e477a67b17371e5/mockups/mojs-player@x4.png -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "@mojs/player", 3 | "description": "GUI player to control your animations", 4 | "version": "1.3.0", 5 | "license": "MIT", 6 | "private": false, 7 | "scripts": { 8 | "start": "webpack" 9 | }, 10 | "source": "js/mojs-player.babel.js", 11 | "main": "build/mojs-player.min.js", 12 | "browser": "build/mojs-player.min.js", 13 | "unpkg": "build/mojs-player.min.js", 14 | "keywords": [ 15 | "motion", 16 | "graphics", 17 | "toolbelt", 18 | "effects", 19 | "animation", 20 | "mojs", 21 | "player" 22 | ], 23 | "author": { 24 | "name": "Oleg Solomka", 25 | "email": "legomushroom@gmail.com", 26 | "url": "https://twitter.com/legomushroom", 27 | "github": "@legomushroom" 28 | }, 29 | "repository": { 30 | "type": "git", 31 | "url": "git+https://github.com/mojs/mojs-player.git" 32 | }, 33 | "bugs": { 34 | "url": "https://github.com/mojs/mojs-player/issues" 35 | }, 36 | "homepage": "https://github.com/mojs/mojs-player", 37 | "engines": { 38 | "node": "^20", 39 | "npm": "^10" 40 | }, 41 | "dependencies": { 42 | "classlist-polyfill": "^1.0.2", 43 | "hammerjs": "^2.0.6" 44 | }, 45 | "devDependencies": { 46 | "@mojs/core": "^0.288.2", 47 | "autoprefixer": "^6.3.5", 48 | "babel-core": "^6.7.6", 49 | "babel-loader": "^6.2.4", 50 | "babel-plugin-transform-runtime": "^6.7.5", 51 | "babel-preset-es2015": "^6.6.0", 52 | "babel-preset-es2015-loose": "^7.0.0", 53 | "babel-preset-stage-2": "^6.5.0", 54 | "babel-runtime": "^6.6.1", 55 | "css-loader": "^0.23.1", 56 | "gulp": "^3.9.1", 57 | "gulp-babel": "^6.1.2", 58 | "gulp-changed": "^1.3.0", 59 | "gulp-concat": "^2.6.0", 60 | "gulp-insert": "^0.5.0", 61 | "gulp-json-editor": "^2.5.7", 62 | "gulp-livereload": "^3.8.1", 63 | "gulp-plumber": "^1.1.0", 64 | "gulp-rename": "^1.2.2", 65 | "gulp-shell": "^0.8.0", 66 | "gulp-uglify": "^1.5.3", 67 | "json-loader": "^0.5.4", 68 | "postcss-cssnext": "^2.5.1", 69 | "postcss-loader": "^0.8.2", 70 | "postcss-modules": "^0.4.1", 71 | "precss": "^1.4.0", 72 | "run-sequence": "^1.1.5", 73 | "style-loader": "^0.13.1", 74 | "webpack": "^1.13.1" 75 | } 76 | } 77 | -------------------------------------------------------------------------------- /webpack.config.js: -------------------------------------------------------------------------------- 1 | var path = require('path'); 2 | var webpack = require('webpack'); 3 | 4 | module.exports = { 5 | watch: true, 6 | context: __dirname + "/", 7 | entry: [ 8 | __dirname + '/js/mojs-player.babel.js' 9 | ], 10 | module: { 11 | loaders: [ 12 | { test: /\.(json)$/, exclude: /node_modules/, loaders: ['json-loader'] }, 13 | { test: /\.(jsx|es6.js|babel.js|.js)$/, 14 | exclude: /node_modules/, 15 | loader: 'babel-loader', 16 | query: { 17 | presets: [ 'es2015-loose', 'babel-preset-stage-2' ], 18 | plugins: [ 'transform-runtime' ] 19 | } 20 | }, 21 | { test: /\.jade$/, loaders: ['jade'] }, 22 | { test: /\.(postcss.css)$/, loader: "style-loader!css-loader!postcss-loader" }, 23 | { test: /\.html$/, loader: 'raw-loader' }, 24 | { 25 | test: /\.(eot|woff|ttf|svg|png|jpg|wav|mp3)$/, 26 | loader: 'url-loader?limit=30000&name=[name]-[hash].[ext]', 27 | } 28 | ] 29 | }, 30 | postcss: function () { 31 | return [ require('precss'), require('postcss-cssnext'), require('postcss-modules') ]; 32 | }, 33 | output: { 34 | path: __dirname + '/build', 35 | filename: 'mojs-player.js', 36 | publicPath: 'build/', 37 | library: 'mojs-player', 38 | libraryTarget: 'umd', 39 | umdNamedDefine: true 40 | }, 41 | plugins: [], 42 | resolve: { 43 | root: [ path.resolve('./') ], 44 | moduleDirectories: ['node_modules'], 45 | target: 'node', 46 | extensions: [ 47 | '', '.js', '.es6', '.babel.js', '.coffee', 48 | '.postcss.css', '.css', '.json' 49 | ] 50 | } 51 | }; 52 | --------------------------------------------------------------------------------