├── docs ├── images │ └── .gitkeep ├── css │ └── demo.css └── index.html ├── .travis.yml ├── .jshintrc ├── .editorconfig ├── package.json ├── dist ├── tinyModal.css.map ├── tinyModal.css ├── tinyModal.min.js └── tinyModal.js ├── .gitignore ├── tinyModal.json ├── src ├── tinyModal.test.js ├── tinyModal.scss └── tinyModal.js ├── LICENSE ├── Gruntfile.js └── README.md /docs/images/.gitkeep: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: node_js 2 | node_js: 3 | - 0.10 4 | -------------------------------------------------------------------------------- /.jshintrc: -------------------------------------------------------------------------------- 1 | { 2 | "boss": true, 3 | "curly": true, 4 | "eqeqeq": true, 5 | "eqnull": true, 6 | "expr": true, 7 | "immed": true, 8 | "noarg": true, 9 | "onevar": true, 10 | "quotmark": "double", 11 | "smarttabs": true, 12 | "trailing": true, 13 | "unused": true, 14 | "node": true 15 | } 16 | -------------------------------------------------------------------------------- /.editorconfig: -------------------------------------------------------------------------------- 1 | # This file is for unifying the coding style for different editors and IDEs 2 | 3 | root = true 4 | 5 | [*] 6 | indent_style = space 7 | indent_size = 2 8 | end_of_line = lf 9 | insert_final_newline = true 10 | charset = utf-8 11 | trim_trailing_whitespace = true 12 | insert_final_newline = true 13 | -------------------------------------------------------------------------------- /package.json: -------------------------------------------------------------------------------- 1 | { 2 | "private": true, 3 | "devDependencies": { 4 | "grunt": "~1.6.1", 5 | "grunt-cli": "~1.4.3", 6 | "grunt-contrib-concat": "^0.5.0", 7 | "grunt-contrib-jshint": "^3.2.0", 8 | "grunt-contrib-uglify": "^5.2.2", 9 | "grunt-contrib-watch": "^1.1.0", 10 | "grunt-sass-scss": "^0.1.9" 11 | }, 12 | "scripts": { 13 | "test": "grunt testjs --verbose" 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /dist/tinyModal.css.map: -------------------------------------------------------------------------------- 1 | {"version":3,"sourceRoot":"","sources":["file:///Users/jorgeepunan/Sites/tinyModal/src/tinyModal.scss"],"names":[],"mappings":"AAAA;AAAA;AAAA;AAAA;AAKA;EACE;EACA;EACA;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAGF;EACE;EACA;EACA;;;AAIA;EACE;EACA;;AAEF;EACE;EACA;;;AAIJ;AAAA;AAAA;AAAA;AAIA;EACE;;;AAGF;EACE;EACA;EACA;EACA;EACA;EACA;;;AAIA;EACE;;;AAIJ;AAAA;EAEE;;;AAGF;AAAA;EAEE","file":"tinyModal.css"} -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | .DS_Store 2 | 3 | # Logs 4 | logs 5 | *.log 6 | npm-debug.log* 7 | 8 | # Runtime data 9 | pids 10 | *.pid 11 | *.seed 12 | 13 | # Directory for instrumented libs generated by jscoverage/JSCover 14 | lib-cov 15 | 16 | # Coverage directory used by tools like istanbul 17 | coverage 18 | 19 | # Grunt intermediate storage (http://gruntjs.com/creating-plugins#storing-task-files) 20 | .grunt 21 | 22 | # node-waf configuration 23 | .lock-wscript 24 | 25 | # Compiled binary addons (http://nodejs.org/api/addons.html) 26 | build/Release 27 | 28 | # Dependency directory 29 | node_modules 30 | 31 | # Optional npm cache directory 32 | .npm 33 | 34 | # Optional REPL history 35 | .node_repl_history 36 | 37 | .sass-cache 38 | -------------------------------------------------------------------------------- /tinyModal.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "tinyModal", 3 | "title": "Tiny Modal", 4 | "homepage": "https://github.com/juanbrujo/tinyModal", 5 | "description": "Clean, Fast, Modular and customizable Modal Window controller", 6 | "demo": "http://juanbrujo.github.io/tinyModal/", 7 | "keywords": [ 8 | "javascript", 9 | "plugin", 10 | "modal", 11 | "window" 12 | ], 13 | "version": "1.1.0", 14 | "author": { 15 | "name": "Jorge Epuñan H.", 16 | "url": "https://github.com/juanbrujo", 17 | "twitter": "@csslab" 18 | }, 19 | "licenses": [ 20 | { 21 | "type": "MIT", 22 | "url": "http://mit-license.org/", 23 | "copyright": "©2015 - Jorge Epuñan H." 24 | } 25 | ], 26 | "bugs": "https://github.com/juanbrujo/tinyModal/issues", 27 | "docs": "https://github.com/juanbrujo/tinyModal#readme", 28 | "download": "https://github.com/juanbrujo/tinyModal/archive/master.zip" 29 | } 30 | -------------------------------------------------------------------------------- /src/tinyModal.test.js: -------------------------------------------------------------------------------- 1 | import { TinyModal } from 'tinymodal'; 2 | 3 | describe('TinyModal', () => { 4 | it('should be able to open a modal', () => { 5 | const modal = new TinyModal({ 6 | title: 'This is a modal', 7 | content: 'This is the content of the modal', 8 | }); 9 | modal.open(); 10 | expect(document.querySelector('.tinymodal-window')).toBeTruthy(); 11 | }); 12 | 13 | it('should be able to close a modal', () => { 14 | const modal = new TinyModal({ 15 | title: 'This is a modal', 16 | content: 'This is the content of the modal', 17 | }); 18 | modal.open(); 19 | modal.close(); 20 | expect(document.querySelector('.tinymodal-window')).toBeFalsy(); 21 | }); 22 | 23 | it('should be able to customize the modal', () => { 24 | const modal = new TinyModal({ 25 | title: 'This is a modal', 26 | content: 'This is the content of the modal', 27 | closeButtonText: 'Close', 28 | backdropClose: false, 29 | }); 30 | modal.open(); 31 | expect(document.querySelector('.tinymodal-window .close')).toHaveText('Close'); 32 | expect(document.querySelector('.tinymodal-window').classList.contains('tinymodal-backdrop-close')).toBeFalsy(); 33 | }); 34 | }); 35 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | The MIT License (MIT) 2 | 3 | <<<<<<< HEAD 4 | Copyright (c) 2015 Jorge Epuñan 5 | ======= 6 | Copyright (c) 2016 Jorge Epuñan 7 | >>>>>>> 53f11a48022581629081359f68f1e6831e09c39a 8 | 9 | Permission is hereby granted, free of charge, to any person obtaining a copy 10 | of this software and associated documentation files (the "Software"), to deal 11 | in the Software without restriction, including without limitation the rights 12 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 13 | copies of the Software, and to permit persons to whom the Software is 14 | furnished to do so, subject to the following conditions: 15 | 16 | The above copyright notice and this permission notice shall be included in all 17 | copies or substantial portions of the Software. 18 | 19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 20 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 21 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 22 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 23 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 24 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 25 | SOFTWARE. 26 | <<<<<<< HEAD 27 | 28 | ======= 29 | >>>>>>> 53f11a48022581629081359f68f1e6831e09c39a 30 | -------------------------------------------------------------------------------- /dist/tinyModal.css: -------------------------------------------------------------------------------- 1 | /*! 2 | * Base styles 3 | * without this tinyModal probably won't work as expected 4 | **/ 5 | .tinymodal-cover { 6 | position: fixed; 7 | width: 100%; 8 | height: 100%; 9 | top: 0; 10 | left: 0; 11 | z-index: 1; 12 | visibility: hidden; 13 | opacity: 0; 14 | } 15 | 16 | .tinymodal-window { 17 | position: fixed; 18 | left: 50%; 19 | top: 50%; 20 | visibility: hidden; 21 | opacity: 0; 22 | z-index: 2; 23 | } 24 | 25 | .tinymodal-inner { 26 | position: relative; 27 | height: 100%; 28 | overflow-y: auto; 29 | } 30 | 31 | .tinymodal-active .tinymodal-cover { 32 | visibility: visible; 33 | opacity: 1; 34 | } 35 | .tinymodal-active .tinymodal-window-open { 36 | visibility: visible; 37 | opacity: 1; 38 | } 39 | 40 | /*! 41 | * Base Design 42 | * can be overriden by your own styles in this or your own stylesheet 43 | **/ 44 | .tinymodal-cover { 45 | background: rgba(0, 0, 0, 0.5); 46 | } 47 | 48 | .tinymodal-window { 49 | padding: 20px; 50 | background: white; 51 | box-shadow: rgba(0, 0, 0, 0.5) 0 0 20px; 52 | border-radius: 3px; 53 | color: #333; 54 | transform: translate(-50%, -50%) scale(0.9); 55 | } 56 | 57 | .tinymodal-active .tinymodal-window-open { 58 | transform: translate(-50%, -50%) scale(1); 59 | } 60 | 61 | .tinymodal-window-open .tinymodal-close, 62 | .tinymodal-window-open button { 63 | background-color: #91cd85; 64 | } 65 | 66 | .tinymodal-ready .tinymodal-window, 67 | .tinymodal-ready .tinymodal-cover { 68 | transition: 0.3s all ease-in-out; 69 | } 70 | 71 | /*# sourceMappingURL=tinyModal.css.map */ -------------------------------------------------------------------------------- /src/tinyModal.scss: -------------------------------------------------------------------------------- 1 | /*! 2 | * Base styles 3 | * without this tinyModal probably won't work as expected 4 | **/ 5 | 6 | .tinymodal-cover { 7 | position: fixed; 8 | width: 100%; 9 | height: 100%; 10 | top: 0; 11 | left: 0; 12 | z-index: 1; 13 | visibility: hidden; 14 | opacity: 0; 15 | } 16 | 17 | .tinymodal-window { 18 | position: fixed; 19 | left: 50%; 20 | top: 50%; 21 | visibility: hidden; 22 | opacity: 0; 23 | z-index: 2; 24 | } 25 | 26 | .tinymodal-inner { 27 | position: relative; 28 | height: 100%; 29 | overflow-y: auto; // if modal height is lower than inner content, add a scrollbar 30 | } 31 | 32 | .tinymodal-active { 33 | .tinymodal-cover { 34 | visibility: visible; 35 | opacity: 1; 36 | } 37 | .tinymodal-window-open { 38 | visibility: visible; 39 | opacity: 1; 40 | } 41 | } 42 | 43 | /*! 44 | * Base Design 45 | * can be overriden by your own styles in this or your own stylesheet 46 | **/ 47 | .tinymodal-cover { 48 | background: rgba(0, 0, 0, 0.5); 49 | } 50 | 51 | .tinymodal-window { 52 | padding: 20px; 53 | background: white; 54 | box-shadow: rgba(0, 0, 0, 0.5) 0 0 20px; 55 | border-radius: 3px; 56 | color: #333; 57 | transform: translate(-50%, -50%) scale(0.9); 58 | } 59 | 60 | .tinymodal-active { 61 | .tinymodal-window-open { 62 | transform: translate(-50%, -50%) scale(1); 63 | } 64 | } 65 | 66 | .tinymodal-window-open .tinymodal-close, 67 | .tinymodal-window-open button { 68 | background-color: #91cd85; 69 | } 70 | 71 | .tinymodal-ready .tinymodal-window, 72 | .tinymodal-ready .tinymodal-cover { 73 | transition: 0.3s all ease-in-out; 74 | } 75 | -------------------------------------------------------------------------------- /docs/css/demo.css: -------------------------------------------------------------------------------- 1 | body { 2 | color: #fff; 3 | background-color: #155799; 4 | background-image: linear-gradient(120deg, #155799, #159957); 5 | background-position: fixed; 6 | font-family: "Open Sans", sans-serif; 7 | } 8 | 9 | article { 10 | position: relative; 11 | padding: 20px; 12 | max-width: 800px; 13 | margin: auto; 14 | } 15 | 16 | h1 { 17 | font-size: 2.5em; 18 | } 19 | 20 | h2 { 21 | font-size: 1.4em; 22 | } 23 | 24 | blockquote { 25 | font-family: monospace; 26 | font-size: 1.2em; 27 | border: 1px solid rgba(255, 255, 255, .2); 28 | padding: 1em; 29 | } 30 | 31 | p { 32 | margin: 10px 0; 33 | font-size: 1em; 34 | line-height: 1.4; 35 | } 36 | 37 | .center { 38 | text-align: center; 39 | } 40 | 41 | a { 42 | color: #91cd85; 43 | transition: 0.2s color ease; 44 | } 45 | a:hover { 46 | color: #fff; 47 | } 48 | 49 | button { 50 | display: inline-block; 51 | margin-bottom: 1em; 52 | padding: .5em .75em; 53 | color: rgba(255, 255, 255, .7); 54 | background-color: rgba(255, 255, 255, .08); 55 | border: 1px solid rgba(255, 255, 255, .2); 56 | border-radius: .3em; 57 | font-size: 1em; 58 | cursor: pointer; 59 | transition: .2s; 60 | } 61 | button:hover { 62 | color: rgba(255, 255, 255, .8); 63 | background-color: rgba(255, 255, 255, .2); 64 | border-color: rgba(255, 255, 255, .3); 65 | } 66 | button:active { 67 | background: #91cd85; 68 | } 69 | button+button { 70 | margin-left: 1em; 71 | } 72 | 73 | .tinymodal-close { 74 | position: absolute; 75 | top: 0; 76 | right: 0; 77 | } 78 | 79 | .image-responsive { 80 | max-width: 100%; 81 | } 82 | -------------------------------------------------------------------------------- /Gruntfile.js: -------------------------------------------------------------------------------- 1 | module.exports = function(grunt) { 2 | grunt.initConfig({ 3 | pkg: grunt.file.readJSON("tinyModal.json"), 4 | meta: { 5 | banner: "/*\n" + 6 | " * <%= pkg.title || pkg.name %> - v<%= pkg.version %>\n" + 7 | " * <%= pkg.description %>\n" + 8 | " *\n" + 9 | " * <%= pkg.homepage %>\n" + 10 | " * Demo: <%= pkg.demo %>\n" + 11 | " *\n" + 12 | " * Author: <%= pkg.author.name %> | <%= pkg.author.twitter %>\n" + 13 | " * License: <%= pkg.licenses[0].type %>\n" + 14 | " * <%= pkg.licenses[0].copyright %>\n" + 15 | " */\n" 16 | }, 17 | sass: { 18 | options: { 19 | sass: { 20 | sourceMap: true 21 | } 22 | }, 23 | main: { 24 | files: { 25 | "dist/tinyModal.css": "src/tinyModal.scss" 26 | } 27 | } 28 | }, 29 | concat: { 30 | dist: { 31 | src: ["src/tinyModal.js"], 32 | dest: "dist/tinyModal.js" 33 | }, 34 | options: { 35 | stripBanners: true, 36 | banner: "<%= meta.banner %>", 37 | } 38 | }, 39 | jshint: { 40 | files: ["src/tinyModal.js"], 41 | options: { 42 | jshintrc: ".jshintrc" 43 | } 44 | }, 45 | uglify: { 46 | my_target: { 47 | src: ["src/tinyModal.js"], 48 | dest: "dist/tinyModal.min.js" 49 | }, 50 | options: { 51 | banner: "<%= meta.banner %>" 52 | } 53 | }, 54 | watch: { 55 | options: { 56 | livereload: true 57 | }, 58 | sass: { 59 | files: ['src/*.scss'], 60 | tasks: ['sass'] 61 | }, 62 | scripts: { 63 | files: ['src/*.js'], 64 | tasks: ['uglify','concat'], 65 | options: { 66 | spawn: false 67 | } 68 | }, 69 | html: { 70 | files: ['demo/*.html'], 71 | }, 72 | tasks: ['default'] 73 | } 74 | }); 75 | 76 | grunt.loadNpmTasks("grunt-sass-scss"); 77 | grunt.loadNpmTasks("grunt-contrib-concat"); 78 | grunt.loadNpmTasks("grunt-contrib-jshint"); 79 | grunt.loadNpmTasks("grunt-contrib-uglify"); 80 | grunt.loadNpmTasks("grunt-contrib-watch"); 81 | 82 | grunt.registerTask("default", ["sass", "concat", "uglify"]); 83 | grunt.registerTask("testjs", ["jshint"]); 84 | 85 | }; 86 | -------------------------------------------------------------------------------- /dist/tinyModal.min.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Tiny Modal - v1.1.0 3 | * Clean, Fast, Modular and customizable Modal Window controller 4 | * 5 | * https://github.com/juanbrujo/tinyModal 6 | * Demo: http://juanbrujo.github.io/tinyModal/ 7 | * 8 | * Author: Jorge Epuñan H. | @csslab 9 | * License: MIT 10 | * ©2015 - Jorge Epuñan H. 11 | */ 12 | var tinyModal=function(){function a(a,b){a.className=a.className.replace(/\s+$/gi,"")+" "+b}function b(a,b){a&&(a.className=a.className.replace(b,""))}function c(){var b=document.createElement("div");a(b,"tinymodal-cover"),document.body.appendChild(b)}function d(){var a=document.querySelector(".tinymodal-cover");a&&a.parentNode.removeChild(a)}function e(a){27===a.keyCode&&j()}function f(a){a.target!==cover&&a.target!==close||j()}function g(a){var b=a.getAttribute("data-size");if(b){var c=b.split(",");a.setAttribute("style","width:"+c[0]+";height:"+c[1]+";")}}function h(b){var c=b.getAttribute("data-newclass");c&&a(b,c)}function i(d){c();var f=document.querySelector(".tinymodal-cover"),i=document.querySelectorAll(".tinymodal-close");if(i.length)for(var k=0;k-1?n=document.querySelector(b):b.match(/.*(\.(jpg|png|gif))$/i)&&(n=document.createElement("aside"),n.setAttribute("class","tinymodal-window tinymodal-new"),n.innerHTML='
',document.body.appendChild(n)),a(n,"tinymodal-window-open"),i(""),c&&"function"==typeof c&&c.call(n),this}function l(a){j(),a&&"function"==typeof a&&a.call(n)}if(!(document.querySelector&&"className"in document.body))return!1;var m=document.body,n=document.querySelector(".tinymodal-window-open"),o=null;return m.className=m.className.replace(/\s+$/gi,"")+" tinymodal-ready",{openModal:k,closeModal:l}}(); -------------------------------------------------------------------------------- /src/tinyModal.js: -------------------------------------------------------------------------------- 1 | var tinyModal = (function(){ 2 | 3 | if (!document.querySelector || !("className" in document.body)) { 4 | return false; 5 | } 6 | 7 | var container = document.body, 8 | popup = document.querySelector(".tinymodal-window-open"), 9 | status = null; 10 | 11 | container.className = container.className.replace(/\s+$/gi, "") + " tinymodal-ready"; 12 | 13 | // utils 14 | function addClass(element, name) { 15 | element.className = element.className.replace(/\s+$/gi,"") + " " + name; 16 | } 17 | function removeClass(element, name) { 18 | if( element ) { 19 | element.className = element.className.replace(name, ""); 20 | } 21 | } 22 | 23 | // add cover 24 | function addCover(){ 25 | var newCover = document.createElement("div"); 26 | addClass(newCover,"tinymodal-cover"); 27 | document.body.appendChild(newCover); 28 | } 29 | // remove cover 30 | function removeCover(){ 31 | var actualCover = document.querySelector(".tinymodal-cover"); 32 | if( actualCover ) { 33 | actualCover.parentNode.removeChild(actualCover); 34 | } 35 | } 36 | // deactivate on ESC key 37 | function onEscKey(event) { 38 | if(event.keyCode === 27) { 39 | deactivate(); 40 | } 41 | } 42 | // deactivate on cover click 43 | function onCoverClick(event) { 44 | if(event.target === cover || event.target === close) { 45 | deactivate(); 46 | } 47 | } 48 | 49 | // get and set modal size by data-size 50 | function getSize(element){ 51 | var size = element.getAttribute("data-size"); 52 | if(size) { 53 | var sizes = size.split(","); 54 | element.setAttribute("style", "width:" + sizes[0] + ";height:" + sizes[1] + ";"); 55 | } 56 | } 57 | 58 | // get and set modal class if available, by data-classname 59 | function getNewClass(element){ 60 | var newClass = element.getAttribute("data-newclass"); 61 | if(newClass) { 62 | addClass(element, newClass); 63 | } 64 | } 65 | 66 | // activate function 67 | function activate(state) { 68 | addCover(); 69 | var cover = document.querySelector(".tinymodal-cover"), 70 | close = document.querySelectorAll(".tinymodal-close"); 71 | if(close.length) { 72 | for (var i = 0; i < close.length; i++) { 73 | close[i].addEventListener("click", deactivate, false); 74 | } 75 | } 76 | document.addEventListener("keyup", onEscKey, false); 77 | cover.addEventListener("click", deactivate, false); 78 | cover.addEventListener("touchstart", deactivate, false); 79 | removeClass(popup,status); 80 | addClass(popup,state); 81 | getSize(popup); 82 | getNewClass(popup); 83 | setTimeout(function(){ 84 | addClass(container, "tinymodal-active"); 85 | }, 0); 86 | status = state; 87 | } 88 | 89 | // deactivate function 90 | function deactivate() { 91 | document.removeEventListener("keyup", onEscKey, false); 92 | document.removeEventListener("click", onCoverClick, false); 93 | document.removeEventListener("touchstart", onCoverClick, false); 94 | removeCover(); 95 | removeClass(container, "tinymodal-active"); 96 | removeClass(popup, "tinymodal-window-open"); 97 | if(popup) { 98 | if(popup.classList.contains("tinymodal-new")) { 99 | setTimeout(function(){ 100 | popup.parentNode.removeChild(popup); 101 | }, 300); 102 | } 103 | } 104 | } 105 | 106 | // openModal public method, w/ onOpen callback 107 | function openModal(selector, onOpen){ 108 | if (selector.indexOf("#") > -1) { 109 | popup = document.querySelector(selector); 110 | } else if (selector.match(/.*(\.(jpg|png|gif))$/i)) { 111 | popup = document.createElement("aside"); 112 | popup.setAttribute("class","tinymodal-window tinymodal-new"); 113 | popup.innerHTML = "
"; 114 | document.body.appendChild(popup); 115 | } 116 | addClass(popup, "tinymodal-window-open"); 117 | activate(""); 118 | if(onOpen && typeof(onOpen) === "function"){ 119 | onOpen.call(popup); 120 | } 121 | return this; 122 | } 123 | 124 | // closeModal public method, w/ onClose callback 125 | function closeModal(onClose) { 126 | deactivate(); 127 | if(onClose && typeof(onClose) === "function"){ 128 | onClose.call(popup); 129 | } 130 | } 131 | 132 | return { 133 | openModal: openModal, 134 | closeModal: closeModal 135 | }; 136 | 137 | })(); 138 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | tinyModal.js 2 | === 3 | 4 | Clean, Fast, Modular and customizable **Modal Window** controller 5 | 6 | *What? Another one?* 7 | 8 | But this one is **really** flexible. And only 2kb (min). And semantic-oriented (content must be in the document). 9 | 10 | ![tinyModal](https://i.imgur.com/oxvQHsh.gif) 11 | 12 | ## Features 13 | 14 | - Super fast ✔ 15 | - Super lightweight ✔✔✔ 16 | - JS only 2kb (.min) ✔ 17 | - CSS only 0.8kb (.min) ✔ 18 | - IE8+ ✔ 19 | - Total control of design and transition effects ✔✔ 20 | - No need or jQuery or other library (Vanilla JS) ✔✔✔ 21 | - Open Source 🌟 22 | 23 | 24 | Still not convinced? Check out this ↓ complete ↓ comparison ↓ table ↓ 25 | 26 | | | tinyModal | Lightbox | Fancybox 2 | Bootstrap's Modal.js | 27 | |--------------|------------|----------|------------|----------------------| 28 | | Size | 2kb ✔ | 8kb | 23kb | 8kb | 29 | | Dependency | just some CSS ✔ | jQuery (+88kb) | jQuery (+88kb) | jQuery (+88kb) + Bootstrap.js (30kb) | 30 | | Performance | smooth ✔ | heavy repaint | heavy repaint | good | 31 | | Design | your CSS ✔ | own | own | own | 32 | | Effects | your CSS3 ✔ | own | own | own | 33 | | Responsive | sure ✔ | nope | nope | yes | 34 | | Mobile-friendly | yep ✔ | nope | nope | nope | 35 | | Conflict | none ✔ | probably | probably | probably | 36 | | Target | coders ✔ | newbies | newbies | newbies | 37 | 38 | ## Demos 39 | 40 | [tinyModal demo](http://juanbrujo.github.io/tinyModal/) 41 | 42 | 43 | 44 | ## Use 45 | 46 | - Add `tinyModal.css` and `tinyModal.js` to your pages/templates. 47 | 48 | - Create as many modal windows as needed using the following markup and the `tinymodal-window` class: 49 | 50 | ```html 51 | 57 | ``` 58 | 59 | - Then call the modal using a link and `tinymodal-modal` class: 60 | 61 | ```javascript 62 | Open first-modal 63 | ``` 64 | 65 | - Apply the event handler to all links (or other selector): 66 | 67 | ```javascript 68 | var links = document.querySelectorAll('a.tinymodal-modal'); 69 | 70 | for (var i = 0; links.length > i; i++) { 71 | links[i].addEventListener("click", function(event){ // callback 72 | event.preventDefault(); 73 | var element = this.getAttribute("href"); 74 | tinyModal.openModal(element, function(){ 75 | var closeLink = this.querySelectorAll('a[href="javascript:closeModal()"]'); 76 | if (closeLink.length < 1) { 77 | var closeLink = document.createElement("a"); 78 | closeLink.setAttribute("href","javascript:closeModal()"); 79 | closeLink.innerHTML = "X"; 80 | this.appendChild(closeLink); 81 | } 82 | }); 83 | }); 84 | } 85 | ``` 86 | 87 | - If needed, you can open modal windows using JavaScript and the onClick event: 88 | 89 | ```html 90 | 91 | 92 | ``` 93 | 94 | ```javascript 95 | function openModal() { 96 | tinyModal.openModal("#first-modal", function(){ 97 | // callback 98 | console.log('#first-modal opened'); 99 | }); 100 | } 101 | 102 | function closeModal() { 103 | tinyModal.closeModal(function(){ 104 | // callback 105 | console.log('closed by closeModal() function'); 106 | }); 107 | } 108 | ``` 109 | 110 | ## Design 111 | 112 | Base modal styles are included in `tinyModal.scss` but you should add your own styles. Base CSS classes for design are: 113 | 114 | ```css 115 | .tinymodal-cover {} 116 | .tinymodal-window {} 117 | .tinymodal-active {} 118 | .tinymodal-close {} 119 | ``` 120 | 121 | And the functional CSS classes are: 122 | 123 | ```css 124 | .tinymodal-ready {} 125 | .tinymodal-active {} 126 | .tinymodal-window-open {} 127 | .tinymodal-ready {} 128 | ``` 129 | 130 | ## Developing 131 | 132 | Need to change anything? 133 | 134 | ``` 135 | $ git clone https://github.com/juanbrujo/tinyModal.git 136 | $ npm install 137 | $ grunt // build 138 | $ grunt watch // develop 139 | $ grunt testjs // jshint test 140 | ``` 141 | 142 | 143 | ## Bugs? 144 | 145 | [tinyModal issues](https://github.com/juanbrujo/tinyModal/issues) 146 | -------------------------------------------------------------------------------- /dist/tinyModal.js: -------------------------------------------------------------------------------- 1 | /* 2 | * Tiny Modal - v1.1.0 3 | * Clean, Fast, Modular and customizable Modal Window controller 4 | * 5 | * https://github.com/juanbrujo/tinyModal 6 | * Demo: http://juanbrujo.github.io/tinyModal/ 7 | * 8 | * Author: Jorge Epuñan H. | @csslab 9 | * License: MIT 10 | * ©2015 - Jorge Epuñan H. 11 | */ 12 | var tinyModal = (function(){ 13 | 14 | if (!document.querySelector || !("className" in document.body)) { 15 | return false; 16 | } 17 | 18 | var container = document.body, 19 | popup = document.querySelector(".tinymodal-window-open"), 20 | status = null; 21 | 22 | container.className = container.className.replace(/\s+$/gi, "") + " tinymodal-ready"; 23 | 24 | // utils 25 | function addClass(element, name) { 26 | element.className = element.className.replace(/\s+$/gi,"") + " " + name; 27 | } 28 | function removeClass(element, name) { 29 | if( element ) { 30 | element.className = element.className.replace(name, ""); 31 | } 32 | } 33 | 34 | // add cover 35 | function addCover(){ 36 | var newCover = document.createElement("div"); 37 | addClass(newCover,"tinymodal-cover"); 38 | document.body.appendChild(newCover); 39 | } 40 | // remove cover 41 | function removeCover(){ 42 | var actualCover = document.querySelector(".tinymodal-cover"); 43 | if( actualCover ) { 44 | actualCover.parentNode.removeChild(actualCover); 45 | } 46 | } 47 | // deactivate on ESC key 48 | function onEscKey(event) { 49 | if(event.keyCode === 27) { 50 | deactivate(); 51 | } 52 | } 53 | // deactivate on cover click 54 | function onCoverClick(event) { 55 | if(event.target === cover || event.target === close) { 56 | deactivate(); 57 | } 58 | } 59 | 60 | // get and set modal size by data-size 61 | function getSize(element){ 62 | var size = element.getAttribute("data-size"); 63 | if(size) { 64 | var sizes = size.split(","); 65 | element.setAttribute("style", "width:" + sizes[0] + ";height:" + sizes[1] + ";"); 66 | } 67 | } 68 | 69 | // get and set modal class if available, by data-classname 70 | function getNewClass(element){ 71 | var newClass = element.getAttribute("data-newclass"); 72 | if(newClass) { 73 | addClass(element, newClass); 74 | } 75 | } 76 | 77 | // activate function 78 | function activate(state) { 79 | addCover(); 80 | var cover = document.querySelector(".tinymodal-cover"), 81 | close = document.querySelectorAll(".tinymodal-close"); 82 | if(close.length) { 83 | for (var i = 0; i < close.length; i++) { 84 | close[i].addEventListener("click", deactivate, false); 85 | } 86 | } 87 | document.addEventListener("keyup", onEscKey, false); 88 | cover.addEventListener("click", deactivate, false); 89 | cover.addEventListener("touchstart", deactivate, false); 90 | removeClass(popup,status); 91 | addClass(popup,state); 92 | getSize(popup); 93 | getNewClass(popup); 94 | setTimeout(function(){ 95 | addClass(container, "tinymodal-active"); 96 | }, 0); 97 | status = state; 98 | } 99 | 100 | // deactivate function 101 | function deactivate() { 102 | document.removeEventListener("keyup", onEscKey, false); 103 | document.removeEventListener("click", onCoverClick, false); 104 | document.removeEventListener("touchstart", onCoverClick, false); 105 | removeCover(); 106 | removeClass(container, "tinymodal-active"); 107 | removeClass(popup, "tinymodal-window-open"); 108 | if(popup) { 109 | if(popup.classList.contains("tinymodal-new")) { 110 | setTimeout(function(){ 111 | popup.parentNode.removeChild(popup); 112 | }, 300); 113 | } 114 | } 115 | } 116 | 117 | // openModal public method, w/ onOpen callback 118 | function openModal(selector, onOpen){ 119 | if (selector.indexOf("#") > -1) { 120 | popup = document.querySelector(selector); 121 | } else if (selector.match(/.*(\.(jpg|png|gif))$/i)) { 122 | popup = document.createElement("aside"); 123 | popup.setAttribute("class","tinymodal-window tinymodal-new"); 124 | popup.innerHTML = "
"; 125 | document.body.appendChild(popup); 126 | } 127 | addClass(popup, "tinymodal-window-open"); 128 | activate(""); 129 | if(onOpen && typeof(onOpen) === "function"){ 130 | onOpen.call(popup); 131 | } 132 | return this; 133 | } 134 | 135 | // closeModal public method, w/ onClose callback 136 | function closeModal(onClose) { 137 | deactivate(); 138 | if(onClose && typeof(onClose) === "function"){ 139 | onClose.call(popup); 140 | } 141 | } 142 | 143 | return { 144 | openModal: openModal, 145 | closeModal: closeModal 146 | }; 147 | 148 | })(); 149 | -------------------------------------------------------------------------------- /docs/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | tinyModal 7 | 8 | 9 | 10 | 11 | 12 |
13 |

tinyModal.js

14 |

2kb modular modal window controller 15 | GitHub 16 | 17 |

18 |
19 |

Lorem ipsum dolor sit cuchuflí barquillo bacán jote gamba listeilor po cahuín, luca melón con vino pichanga coscacho ni ahí peinar la muñeca chuchada al chancho achoclonar. Chorrocientos pituto ubicatex huevo duro bolsero cachureo el hoyo del queque en cana huevón el año del loly hacerla corta impeque de miedo quilterry la raja longi ñecla. Hilo curado rayuela carrete quina guagua lorea piola ni ahí.

20 |
21 |

Demo: open using function 22 |

23 |

24 | 25 | 26 |

27 |

Demo: open anchor 28 |

29 |

30 | Open first-modal 31 | Open second-modal 32 |

33 |

Demo: open image link 34 |

35 |

36 | 37 | Image placeholder 38 | 39 |

40 |
41 |

Lorem ipsum dolor sit cuchuflí barquillo bacán jote gamba listeilor po cahuín, luca melón con vino pichanga coscacho ni ahí peinar la muñeca chuchada al chancho achoclonar. Chorrocientos pituto ubicatex huevo duro bolsero cachureo el hoyo del queque en cana huevón el año del loly hacerla corta impeque de miedo quilterry la raja longi ñecla. Hilo curado rayuela carrete quina guagua lorea piola ni ahí.

42 |
43 |

44 | GitHub 45 |

46 |
47 | 48 | 49 | 57 | 66 | 67 | 68 | 69 | 103 | 104 | 105 | --------------------------------------------------------------------------------