├── .eslintrc ├── .gitignore ├── LICENSE ├── README.md ├── bower.json ├── cypress.json ├── cypress ├── .eslintrc ├── fixtures │ └── example.json ├── index.html ├── integration │ └── test.js ├── plugins │ └── index.js └── support │ ├── commands.js │ └── index.js ├── index.html ├── index.js ├── jquery.popupoverlay.js ├── package-lock.json └── package.json /.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "extends": "eslint:recommended", 3 | "env": { 4 | "browser": true 5 | }, 6 | "rules": { 7 | } 8 | } -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | /node_modules -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2013 Vast.com, Inc. 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 | # jQuery Popup Overlay 2 | 3 | jQuery plugin for responsive and accessible modal windows and tooltips 4 | 5 | [![NPM version](https://img.shields.io/npm/v/jquery-popup-overlay.svg?style=flat)](https://www.npmjs.com/package/jquery-popup-overlay) 6 | [![NPM dependencies](https://img.shields.io/david/vast-engineering/jquery-popup-overlay.svg?style=flat)](https://david-dm.org/vast-engineering/jquery-popup-overlay) 7 | [![NPM dev dependencies](https://img.shields.io/david/dev/vast-engineering/jquery-popup-overlay.svg?style=flat)](https://david-dm.org/vast-engineering/jquery-popup-overlay?type=dev) 8 | 9 | ## Documentation & demo 10 | [Documentation & demo](https://vast-engineering.github.io/jquery-popup-overlay/) 11 | 12 | ## License 13 | Released under the [MIT license](https://github.com/vast-engineering/jquery-popup-overlay/blob/gh-pages/LICENSE). 14 | -------------------------------------------------------------------------------- /bower.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "jquery-popup-overlay", 3 | "main": "index.js", 4 | "version": "2.0.0", 5 | "homepage": "https://github.com/vast-engineering/jquery-popup-overlay", 6 | "authors": [ 7 | "Vast Engineering https://github.com/orgs/vast-engineering/people" 8 | ], 9 | "description": "jQuery plugin for responsive and accessible modal windows and tooltips", 10 | "moduleType": [ 11 | "commonjs" 12 | ], 13 | "keywords": [ 14 | "jquery", 15 | "popup", 16 | "responsive", 17 | "modal", 18 | "tooltips", 19 | "plugin" 20 | ], 21 | "license": "MIT", 22 | "ignore": [ 23 | "**/.*", 24 | "node_modules", 25 | "bower_components", 26 | "test", 27 | "tests" 28 | ] 29 | } 30 | -------------------------------------------------------------------------------- /cypress.json: -------------------------------------------------------------------------------- 1 | { 2 | "baseUrl": "http://localhost:8080", 3 | "video": false, 4 | "projectId": "of5t69" 5 | } 6 | -------------------------------------------------------------------------------- /cypress/.eslintrc: -------------------------------------------------------------------------------- 1 | { 2 | "env": { 3 | "node": true, 4 | "es6": true, 5 | "mocha": true 6 | }, 7 | "parserOptions": { 8 | "sourceType": "module", 9 | }, 10 | globals: { 11 | "Cypress": true, 12 | "cy": true, 13 | "expect": true 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /cypress/fixtures/example.json: -------------------------------------------------------------------------------- 1 | { 2 | "name": "Using fixtures to represent data", 3 | "email": "hello@cypress.io", 4 | "body": "Fixtures are a great way to mock data for responses to routes" 5 | } -------------------------------------------------------------------------------- /cypress/index.html: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | Test Page 7 | 8 | 9 | 10 | 11 | 12 | 32 | 33 | 34 |
35 |
36 |

Tests

37 |

38 | 39 | Default 40 | Tooltip 41 | Locked 42 | Custom 43 |

44 |

TOP

45 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

46 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

47 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

48 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

49 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

50 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

51 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

52 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

53 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

54 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

55 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

56 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

57 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id. Lorem ipsum dolor sit amet, consectetur adipisicing elit. Minus possimus impedit porro accusamus sed repellat laborum eius a. Accusamus soluta expedita atque quisquam consequatur, dolorum sapiente dolore in! Deleniti, id.

58 |

BOTTOM

59 |
60 |
61 |
62 |

default example

63 | 64 |

Lorem ipsum dolor sit amet, consectetur adipisicing elit. Quisquam, est modi quos placeat ex a? Expedita quidem, odio a vel ex. Quisquam voluptatibus, natus quas, iusto distinctio labore nihil tenetur!

65 | 66 | 67 |
68 |
69 |

tooltip example

70 | 71 |
72 |
73 |

locked example

74 | 75 |
76 |
77 |

custom example

78 | 79 | 80 |
81 | 82 | 88 | 89 | 90 | -------------------------------------------------------------------------------- /cypress/integration/test.js: -------------------------------------------------------------------------------- 1 | // Cypress end-to-end tests 2 | 3 | // Debugging tips: 4 | // - cy.pause() can be placed before and after the assertion. 5 | // - cy.debug() can be useful... cy.get('.ls-btn').click({ force: true }).debug() 6 | // - Also, you can click on Before/After state in Cypress UI. 7 | // - If you want to use a console in Cypress UI dev tools, first click on Inspect Element to get the correct `window` scope. 8 | 9 | 10 | // TODO: 11 | // - add tests for rightedge and leftedge, for tooltips 12 | // - test destroyAll with popups with fadeOut animation and scrolllock 13 | // - add tests with mixed options 14 | // - try to improve some tests if possible: test from user perspective instead of testing CSS properties 15 | // create tests for accessibility and wai-aria 16 | // - add tests for default option to all non-boolean options? 17 | // - try to make the same tests in Jest+Puppeteer to see if there will be less issues (although Puppeteer has no UI for debugging) 18 | 19 | 20 | //----------------------------------------------------------------------------- 21 | // Prepare random options 22 | 23 | const randomOptions = {}; 24 | const allOptions = { 25 | color: ['blue', 'red'], 26 | opacity: [0, 0.5, 1], 27 | background: [true, false] 28 | } 29 | 30 | // Get random value from array 31 | const rand = function (arr) { 32 | return arr[Math.floor(Math.random() * arr.length)]; 33 | } 34 | 35 | // Randomize options 36 | Object.keys(allOptions).forEach(function(key) { 37 | const randomValue = rand(allOptions[key]); 38 | randomOptions[key] = randomValue; // extend randomOptions object 39 | }); 40 | 41 | 42 | //----------------------------------------------------------------------------- 43 | // Tests 44 | 45 | describe("jQuery Popup Overlay", () => { 46 | context("Options", () => { 47 | before(() => { 48 | cy.visit("/cypress/index.html"); 49 | 50 | cy.window().then(win => { 51 | // Extend plugin's defaults with randomOptions 52 | // UNCOMMENT THIS LINE FOR TESTS WITH RANDOM PLUGIN OPTIONS: 53 | // Object.assign(win.$.fn.popup.defaults, randomOptions); 54 | 55 | // Log plugin defaults to console (for debugging) 56 | cy.log('**Defaults:**', JSON.stringify(win.$.fn.popup.defaults)); 57 | win.console.log('**Defaults:**', JSON.stringify(win.$.fn.popup.defaults)); 58 | 59 | // jquery ':focus' selector fails when window is not in focus, replace it with our own version. 60 | // Although, this still doesn't solve an issue when testing :focus styles and such tests will fail. 61 | // If that happens, re-run the tests with window in focus, or without Cypress UI (i.e. headless). 62 | // https://github.com/cypress-io/cypress/issues/2176 63 | win.jQuery.find.selectors.filters.focus = function(elem) { 64 | const doc = elem.ownerDocument; 65 | return elem === doc.activeElement && !!(elem.type || elem.href); 66 | }; 67 | }); 68 | }); 69 | 70 | beforeEach(() => { 71 | cy.window().then(win => { 72 | // Destroy all popups 73 | win.$.fn.popup.destroyall(); 74 | // Add markup for temporary (dynamic) test popup 75 | win 76 | .$( 77 | `
This is a test popup.
` 78 | ) 79 | .appendTo("body"); 80 | }); 81 | 82 | // A bug in Cypress requires focus to be cleared with .blur(), else next .typeEsc() will fail. 83 | cy 84 | .get("#dummy-input") 85 | .focus() 86 | .blur(); 87 | }); 88 | 89 | it("autoopen true", () => { 90 | cy.window().then(win => { 91 | win.$("#dynamic").popup({ autoopen: true }); 92 | }); 93 | cy.get("#dynamic").should("be.visible"); 94 | }); 95 | 96 | it("autoopen false", () => { 97 | cy.window().then(win => { 98 | win.$("#dynamic").popup({ autoopen: false }); 99 | }); 100 | cy.get("#dynamic").should("not.be.visible"); 101 | cy.get("#dynamic_wrapper").should("exist"); 102 | }); 103 | 104 | it("absolute true", () => { 105 | cy.window().then(win => { 106 | win.$("#dynamic").popup({ absolute: true, autoopen: true }); 107 | }); 108 | 109 | cy.log("IMPORTANT: This test might fail in UI, just re-run the tests."); 110 | cy.wait(10); // If we don't wait, rect.bottom will be 0 (another Cypress bug probably) 111 | cy.scrollTo(0, 4000); 112 | 113 | // Manually test for whether elem is out of viewport - https://github.com/cypress-io/cypress/issues/877 114 | cy.get("#dynamic").then($el => { 115 | const rect = $el[0].getBoundingClientRect(); 116 | // expect( rect.bottom ).to.be.lessThan( 0 ); 117 | expect(rect.bottom).to.be.lessThan(0); 118 | }); 119 | }); 120 | 121 | it("absolute false", () => { 122 | cy.window().then(win => { 123 | win.$("#dynamic").popup({ absolute: false, autoopen: true }); 124 | }); 125 | 126 | cy.log("IMPORTANT: This test might fail in UI, just re-run the tests."); 127 | cy.wait(10); // If we don't wait, rect.bottom will be 0 (another Cypress bug probably) 128 | cy.scrollTo(0, 4000); 129 | 130 | // Manually test for whether elem is out of viewport - https://github.com/cypress-io/cypress/issues/877 131 | cy.get("#dynamic").then($el => { 132 | const rect = $el[0].getBoundingClientRect(); 133 | expect(rect.bottom).to.be.greaterThan(0); 134 | }); 135 | }); 136 | 137 | it("type tooltip", () => { 138 | cy.window().then(win => { 139 | win.$("#dynamic").popup({ type: "tooltip", autoopen: true }); 140 | }); 141 | cy.get("#dynamic_wrapper").should("have.css", "position", "absolute"); 142 | cy.get("#dynamic_wrapper").should("have.css", "overflow", "visible"); 143 | cy.get("#dynamic_background").should("not.exist"); 144 | cy.get("body").should("have.css", "overflow", "visible"); 145 | }); 146 | 147 | it("type overlay", () => { 148 | cy.window().then(win => { 149 | win.$("#dynamic").popup({ type: "overlay", autoopen: true }); 150 | }); 151 | cy.get("#dynamic_background").should("exist"); 152 | cy.get("#dynamic_wrapper").should("have.css", "overflow", "auto"); 153 | cy.get("#dynamic_wrapper").should("have.css", "text-align", "center"); 154 | }); 155 | 156 | it("closebutton", () => { 157 | cy.window().then(win => { 158 | win.$("#dynamic").popup({ closebutton: true, autoopen: true }); 159 | }); 160 | cy.get(".dynamic_close").should("exist"); // button should exist 161 | cy.get(".dynamic_close").click(); // button should be clickable 162 | }); 163 | 164 | it("scrolllock true", () => { 165 | cy.window().then(win => { 166 | win.$("#dynamic").popup({ scrolllock: true, autoopen: true }); 167 | }); 168 | cy.get("body").should("have.css", "overflow", "hidden"); 169 | }); 170 | 171 | it("scrolllock false", () => { 172 | cy.window().then(win => { 173 | win.$("#dynamic").popup({ scrolllock: false, autoopen: true }); 174 | }); 175 | cy.get("body").should("have.css", "overflow", "visible"); 176 | }); 177 | 178 | it("background true", () => { 179 | cy.window().then(win => { 180 | win.$("#dynamic").popup({ background: true, autoopen: true }); 181 | }); 182 | cy.get("#dynamic_background").should("exist"); 183 | }); 184 | 185 | it("background false", () => { 186 | cy.window().then(win => { 187 | win 188 | .$("#dynamic") 189 | .popup({ background: false, blur: false, autoopen: true }); 190 | }); 191 | cy.get("#dynamic_background").should("not.exist"); 192 | cy 193 | .get("#dummy-input") 194 | .click() 195 | .focus(); 196 | cy.get("#dynamic_background").should("not.exist"); 197 | }); 198 | 199 | it("color", () => { 200 | cy.window().then(win => { 201 | win.$("#dynamic").popup({ color: "rgb(255, 0, 0)", autoopen: true }); 202 | }); 203 | cy 204 | .get("#dynamic_background") 205 | .should("have.css", "background-color", "rgb(255, 0, 0)"); 206 | }); 207 | 208 | it("opacity", () => { 209 | cy.window().then(win => { 210 | win.$("#dynamic").popup({ opacity: 0.1, autoopen: true }); 211 | }); 212 | cy.get("#dynamic_background").should("have.css", "opacity", "0.1"); 213 | }); 214 | 215 | it("horizontal", () => { 216 | cy.window().then(win => { 217 | win.$("#dynamic").popup({ horizontal: "left", autoopen: true }); 218 | }); 219 | cy.get("#dynamic_wrapper").should("have.css", "text-align", "left"); 220 | }); 221 | 222 | it("vertical", () => { 223 | cy.window().then(win => { 224 | win.$("#dynamic").popup({ vertical: "bottom", autoopen: true }); 225 | }); 226 | cy.get("#dynamic").should("have.css", "vertical-align", "bottom"); 227 | }); 228 | 229 | it("offsettop", () => { 230 | cy.window().then(win => { 231 | win 232 | .$("#dynamic") 233 | .popup({ 234 | offsettop: 100, 235 | vertical: "bottom", 236 | type: "tooltip", 237 | autoopen: true 238 | }); 239 | }); 240 | cy.get("#dynamic_wrapper").should("have.css", "top", "100px"); 241 | }); 242 | 243 | it("offsetleft", () => { 244 | cy.window().then(win => { 245 | win 246 | .$("#dynamic") 247 | .popup({ 248 | offsetleft: 100, 249 | horizontal: "leftedge", 250 | type: "tooltip", 251 | autoopen: true 252 | }); 253 | }); 254 | cy.get("#dynamic_wrapper").should("have.css", "left", "100px"); 255 | }); 256 | 257 | it("escape true", () => { 258 | cy.window().then(win => { 259 | win.$("#dynamic").popup({ escape: true, autoopen: true }); 260 | }); 261 | cy.typeEsc(); 262 | cy.get("#dynamic").should("be.hidden"); 263 | }); 264 | 265 | it("escape false", () => { 266 | cy.window().then(win => { 267 | win.$("#dynamic").popup({ escape: false, autoopen: true }); 268 | }); 269 | cy.typeEsc(); 270 | cy.get("#dynamic").should("be.visible"); 271 | }); 272 | 273 | it("blur true", () => { 274 | cy.window().then(win => { 275 | win.$("#dynamic").popup({ blur: true, autoopen: true }); 276 | }); 277 | // Clicking on the popup content should not hide it (this click is also required for a bug in Cypress with pointer-events:none) 278 | cy.get("#dynamic").click(1, 1); 279 | cy.get("#dynamic").should("be.visible"); 280 | // Clicking outside of the popup 281 | cy.get("#dynamic_wrapper").click(1, 1, { force: true }); // Cypress doesn't respect pointer-events:none; so we have to force the click 282 | cy.get("#dynamic").should("be.hidden"); 283 | }); 284 | 285 | it("blur false", () => { 286 | cy.window().then(win => { 287 | win.$("#dynamic").popup({ blur: false, autoopen: true }); 288 | }); 289 | // Clicking on the popup content should not hide it (this click is also required for a bug in Cypress with pointer-events:none) 290 | cy.get("#dynamic").click(1, 1); 291 | cy.get("#dynamic").should("be.visible"); 292 | // Clicking outside of the popup 293 | cy.get("#dynamic_background").click(1, 1, { force: true }); // Cypress doesn't respect pointer-events:none; so we have to force the click 294 | cy.get("#dynamic").should("be.visible"); 295 | }); 296 | 297 | it("blurignore", () => { 298 | cy.window().then(win => { 299 | win.$("#dynamic").popup({ blurignore: 'h1', blur: true, autoopen: true }); 300 | }); 301 | // Clicking on the popup content should not hide it (this click is also required for a bug in Cypress with pointer-events:none) 302 | cy.get("#dynamic").click(1, 1); 303 | cy.get("#dynamic").should("be.visible"); 304 | // Clicking on h1 to test `blurignore` 305 | cy.get("h1").click({ force: true }); 306 | cy.get("#dynamic").should("be.visible"); 307 | // Clicking outside of the popup 308 | cy.get("#dynamic_wrapper").click(1, 1, { force: true }); // Cypress doesn't respect pointer-events:none; so we have to force the click 309 | cy.get("#dynamic").should("be.hidden"); 310 | }); 311 | 312 | it("setzindex true", () => { 313 | cy.window().then(win => { 314 | win.$("#dynamic").popup({ setzindex: true, autoopen: true }); 315 | }); 316 | cy.get("#dynamic_background").should("have.css", "z-index", "100000"); 317 | cy.get("#dynamic_wrapper").should("have.css", "z-index", "100001"); 318 | }); 319 | 320 | it("setzindex false", () => { 321 | cy.window().then(win => { 322 | win.$("#dynamic").popup({ setzindex: false, autoopen: true }); 323 | }); 324 | cy.get("#dynamic_background").should("have.css", "z-index", "auto"); 325 | cy.get("#dynamic_wrapper").should("have.css", "z-index", "auto"); 326 | }); 327 | 328 | it("autozindex true", () => { 329 | cy.window().then(win => { 330 | win.$("#dynamic").popup({ autozindex: true, autoopen: true }); 331 | }); 332 | cy.get("#dynamic_background").should("have.css", "z-index", "56"); // z-index:55 is set in HTML file 333 | cy.get("#dynamic_wrapper").should("have.css", "z-index", "57"); 334 | }); 335 | 336 | it("autozindex false", () => { 337 | cy.window().then(win => { 338 | win.$("#dynamic").popup({ autozindex: false, autoopen: true }); 339 | }); 340 | cy.get("#dynamic_background").should("have.css", "z-index", "100000"); 341 | cy.get("#dynamic_wrapper").should("have.css", "z-index", "100001"); 342 | }); 343 | 344 | it("keepfocus true", () => { 345 | cy.window().then(win => { 346 | win 347 | .$("#dynamic") 348 | .popup({ keepfocus: true, closebutton: true, autoopen: true }); 349 | }); 350 | cy.focused().should("have.id", "dynamic"); // check if popup gets focus 351 | cy.get(".dynamic_close").focus(); 352 | cy.typeTab(); 353 | cy.focused().should("have.id", "dynamic-dummy-input"); // check if focus stays in popup 354 | }); 355 | 356 | it("keepfocus false", () => { 357 | cy.window().then(win => { 358 | win.$(' 162 | 163 | 164 | Active Bg Absolute 165 | Tooltip 166 | 167 | 168 |

169 | 170 |

Features

171 | 172 | 189 | 190 |

Usage

191 | 192 |
 193 | <!doctype html>
 194 | <html lang="en">
 195 | <head>
 196 |   <meta charset="utf-8">
 197 |   <title>Site Title</title>
 198 | </head>
 199 | <body>
 200 | 
 201 |   <!-- Wrap all page content in a page container (optional, but recommended for screen readers and iOS*) -->
 202 |   <div id="page">
 203 |     <header></header>
 204 |     <main>
 205 |       {{ Page Content }}
 206 |       <!-- Add a button to open the popup (optional) -->
 207 |       <button class="JPO_open">Open popup</button>
 208 |     </main>
 209 |     <footer></footer>
 210 |   </div>
 211 | 
 212 |   <!-- Add content to the popup -->
 213 |   <div id="JPO">
 214 |     {{ Popup Content }}
 215 |     <!-- Add a button to close the popup (optional) -->
 216 |     <button class="JPO_close">Close</button>
 217 |   </div>
 218 | 
 219 |   <!-- Include jQuery -->
 220 |   <script src="https://code.jquery.com/jquery-3.3.1.slim.min.js"></script>
 221 | 
 222 |   <!-- Include jQuery Popup Overlay -->
 223 |   <script src="https://cdn.jsdelivr.net/gh/vast-engineering/jquery-popup-overlay@2/jquery.popupoverlay.min.js">
 224 |   </script>
 225 | 
 226 |   <script>
 227 |     $(document).ready(function() {
 228 | 
 229 |       // Initialize the plugin
 230 |       $('#JPO').popup();
 231 | 
 232 |       // Set default `pagecontainer` for all popups (optional, but recommended for screen readers and iOS*)
 233 |       $.fn.popup.defaults.pagecontainer = '#page'
 234 |     });
 235 |   </script>
 236 | 
 237 | </body>
 238 | </html>
 239 | 
240 | 241 |
242 |

It can also be used as a NPM package:

243 |
npm install jquery-popup-overlay
244 | 245 |

And included as a CommonJS module:

246 |
var popup = require("jquery-popup-overlay");
 247 | 
248 | 249 |

Example on CodePen

250 |

See the Pen jquery-popup-overlay example by Vladimirs (@vladimirs) on CodePen.

251 | 252 | 253 |

Options

254 | 255 |
256 | 257 | 258 | 259 | 260 | 261 | 262 | 263 | 264 | 265 | 266 | 267 | 268 | 269 | 270 | 271 | 272 | 273 | 274 | 275 | 276 | 277 | 278 | 279 | 280 | 281 | 282 | 283 | 284 | 285 | 286 | 287 | 288 | 290 | 291 | 292 | 293 | 294 | 295 | 296 | 297 | 298 | 299 | 300 | 301 | 302 | 303 | 304 | 305 | 306 | 307 | 308 | 309 | 310 | 311 | 312 | 313 | 314 | 315 | 316 | 317 | 318 | 319 | 320 | 321 | 322 | 323 | 324 | 325 | 326 | 327 | 328 | 329 | 330 | 331 | 334 | 335 | 336 | 337 | 338 | 339 | 340 | 341 | 342 | 343 | 344 | 345 | 346 | 347 | 348 | 349 | 350 | 351 | 355 | 356 | 357 | 358 | 359 | 360 | 362 | 363 | 364 | 365 | 366 | 367 | 368 | 369 | 370 | 371 | 372 | 373 | 374 | 375 | 376 | 377 | 378 | 379 | 380 | 381 | 382 | 383 | 384 | 385 | 386 | 387 | 388 | 389 | 390 | 391 | 393 | 394 | 395 | 396 | 397 | 398 | 399 | 400 | 401 | 402 | 403 | 404 | 410 | 411 | 412 | 413 | 414 | 415 | 416 | 417 | 418 | 419 | 420 | 421 | 422 | 423 | 424 | 425 | 426 | 427 | 433 | 434 | 435 | 436 | 437 | 438 | 456 | 457 | 458 | 459 | 460 | 461 | 462 | 463 | 464 | 465 | 466 | 467 | 469 | 470 | 471 | 480 | 481 | 482 | 483 |
NameTypeDefaultDescription
absolutebooleanfalseSets absolute instead of fixed position to the popup. It will scroll with the rest of the content.
autoopenbooleanfalseShows the popup when initialized.
autozindexbooleanfalse

Sets highest z-index of all elements of the page to the popup.

backgroundbooleantrueEnables background cover.
289 | Default is false for tooltips.
blurbooleantrueCloses the popup if a user clicks anywhere outside the popup.
blurignorestring (CSS selector)trueSets elements which will be ignored in blur option, even if they are outside.
closeelementstring (CSS selector)'.{popup_id}_close'Enables you to define custom element which will close the popup on click. In our case it's set to .JPO_close.
closebuttonbooleannullDynamically creates a Close button during popup initialization by calling popup('addclosebutton') method. Use this if you don't want to hard-code Close elements in HTML template.
closebuttonmarkupobject
jQuery or DOM object
nullEnables you to define custom markup which will be used for a dynamically created button. Use with closebutton option.
colorstring (CSS color)'#000'Sets background color.
detachbooleanfalse 332 |

Removes popup element from the DOM. It will be appended to <body> when opened, and removed again when closed.

333 |
escapebooleantrueCloses the popup when Escape key is pressed.
focuselementboolean or 'closeelement' or string (CSS selector)'#{popup_id}'Enables you to specify the element which will be focused upon showing the popup. By default, the popup element (in our case #JPO) will recieve the initial focus. Setting to true will focus the popup even if keepfocus is false. A keyword 'closebutton' can be used to target a Close element.
focusdelaynumber (milliseconds)50 352 |

Delays the focusing of the focuselement.

353 |

Use this if you have slide-in animations for the popup, to make them run smoothly in Chrome on Android, as it tries to get the focused element in the viewport so it conflicts with the animation. The delay should be longer than transition-duration.

354 |
horizontal'center'
'left'
'right'
'leftedge'
'rightedge'
'center'

Sets horizontal position.

361 |

Options `leftedge` and `rightedge` can be used only for tooltips, and will align the tooltip to the left or right edge of the opening element (`openelement`).

keepfocusbooleantrueLock keyboard focus inside of popup. Recommended to be enabled.
offsettopnumber0

Sets top offset to tooltip.

offsetleftnumber0

Sets left offset to tooltip.

opacityfloat0.5Sets background opacity.
outlinebooleanfalse

Shows a default browser outline on popup element when focused.

392 |

Setting to false is equivalent to .popup_content {outline:none;}.

openelementstring (CSS selector)'.{popup_id}_open'Enables you to define custom element which will open the popup on click. In our case it's set to .JPO_open.
pagecontainerstring (CSS selector)null

Sets a page container to help the plugin do its work. Page container should be a direct child of <body>, a top level element that surrounds all content of the page (e.g. #page on this page).

405 |

It's recommended that you set the page container for better screen-reader experience.

406 |

Doing so, when the popup is visible, aria-hidden="true" will be set to the page container and aria-hidden="false" to the popup, and vice-versa when the popup closes. Some screen readers requires this in order to read the modal content properly.

407 |

iOS*: Setting `pagecontainer` will also enable blur:true option to work correctly on iOS if background:false option is set (tooltips have background:false by default). See Issue 90.

408 |

You can set `pagecontainer` once per website. For example:
$.fn.popup.defaults.pagecontainer = '#page';

409 |
setzindexbooleantrueSets default z-index to the popup (2001) and to the background (2000).
scrolllockbooleanfalseDisables scrolling of background content while the popup is visible.
transitionstring (CSS transition)null 428 |

Sets CSS transition when showing and hiding a popup.

429 |

Use this if you don't need separate transition for background, or different transition for opening and closing the popup, or if you need to transition only selected properties – otherwise set custom transitions directly in CSS.

430 |

Simple fade effect $('#JPO').popup({transition: 'all 0.3s'}) is equivalent to #JPO, #JPO_wrapper, #JPO_background {transition: all 0.3s;}

431 |

Setting fade effect for all popups on the site: $.fn.popup.defaults.transition = 'all 0.3s'; is equivalent to .popup_content, .popup_wrapper, .popup_background {transition: all 0.3s;}

432 |
tooltipanchorobject
jQuery or DOM object
null 439 |

Sets an element to be an anchor for tooltip position.

440 |

For example, for multiple opening links using the same tooltip on mouseover:

441 |
 442 | $('.JPO_open').on({
 443 |   mouseenter: function(event) {
 444 |     $('#JPO').popup({
 445 |       tooltipanchor: event.target,
 446 |       autoopen: true,
 447 |       type: 'tooltip'
 448 |     });
 449 |   },
 450 |   mouseleave: function() {
 451 |     $('#JPO').popup('hide');
 452 |   }
 453 | });
 454 | 
455 |
type'overlay'
'tooltip'
'overlay'Sets popup type to overlay or tooltip.
vertical'center'
'top'
'bottom'
'topedge'
'bottomedge'
'center'

Sets vertical position.

468 |

Options `topedge` and `bottomedge` can be used only for tooltips, and will align the tooltip to the top or bottom edge of the opening element (`openelement`).

472 |

Example:

473 |
 474 | $('#JPO').popup({
 475 |   opacity: 0.3,
 476 |   transition: 'all 0.3s'
 477 | });
 478 | 
479 |
484 |
485 | 486 | 487 | 488 |

Callback events

489 | 490 | 491 | 492 | 493 | 494 | 495 | 496 | 497 | 498 | 499 | 500 | 501 | 502 | 503 | 504 | 505 | 506 | 507 | 508 | 509 | 510 | 511 | 512 | 513 | 514 | 515 | 516 | 517 | 518 | 519 | 520 | 521 | 522 | 523 | 524 | 525 | 535 | 536 | 537 |
NameTypeDescription
beforeopenfunctionCallback function which will execute before the popup is opened.
onopenfunctionCallback function which will execute when the popup starts to open.
onclosefunctionCallback function which will execute when the popup starts to close.
opentransitionendfunctionCallback function which will execute after the opening CSS transition is over, only if transition actually occurs and if supported by the browser.
closetransitionendfunctionCallback function which will execute after the closing CSS transition is over, only if transition actually occurs and if supported by the browser.
526 |

Example:

527 |
 528 | $('#JPO').popup({
 529 |   onopen: function() {
 530 |     alert('Popup just opened!');
 531 |   }
 532 | });
 533 | 
534 |
538 | 539 |

Defaults

540 | 541 | 542 | 543 | 544 | 545 | 546 | 547 | 548 | 556 | 557 |

Default values for options and events can be modified.

549 |

Example:

550 | 551 |
 552 | $.fn.popup.defaults.transition = 'all 0.3s';
 553 | $.fn.popup.defaults.pagecontainer = '#page';
 554 | 
555 |
558 | 559 | 560 |

Methods

561 | 562 | 563 | 564 | 565 | 566 | 567 | 568 | 569 | 570 | 571 | 572 | 579 | 580 | 581 | 582 | 586 | 587 | 588 | 589 | 593 | 594 | 595 | 596 | 600 | 601 | 602 | 603 | 608 | 609 | 610 | 611 | 616 | 617 | 618 |
NameDescription
.popup(options)

Activates your content as a popup. Accepts an optional options object.

573 |
 574 | $('#JPO').popup({
 575 |   background: false
 576 | });
 577 | 
578 |
.popup('show') 583 |

Manually opens a popup.

584 |
$('#JPO').popup('show');
585 |
.popup('hide') 590 |

Manually hides a popup.

591 |
$('#JPO').popup('hide');
592 |
.popup('toggle') 597 |

Manually toggles a popup.

598 |
$('#JPO').popup('toggle');
599 |
.popup('addclosebutton') 604 |

Manually creates a Close button.

605 |
$('#JPO').popup('addclosebutton');
606 |

This method is triggered automatically on popup initialization if closebutton option is set to true.

607 |
.popup('reposition') 612 |

Manually re-positions a popup.

613 |
$('#JPO').popup('reposition');
614 |

This method is triggered automatically every time a tooltip or overlay is opened, and on window.resize event for tooltips.

615 |
619 | 620 |

Changelog

621 |

See the changelog on GitHub.

622 | 623 | 624 | 625 |
626 |
627 | 642 |
643 |
644 | 645 | 646 | 647 | 648 | 649 | 650 | 651 | 652 | 653 | 654 | 659 | 660 | 661 | 662 | 663 | 664 | 665 | 666 | 667 | 668 | 669 | 670 | 671 | 672 | 673 |
674 |

Basic

675 |
$('#basic').popup();
676 |

Try to change the width and height of browser window, or to rotate your device.

677 |

Also try to navigate with the Tab key

678 |

The dialog can be closed by pressing the Esc key, or by clicking on the background 679 |
outside the content area, or by clicking on the Close button.

680 | 681 | 682 |
683 | 684 | 689 | 690 | 691 | 692 | 693 | 694 | 695 |
696 |

Generated close button

697 |

closebutton:true option will append markup for the close button (at top right).

698 | 699 |
$('#closebutton').popup({
 700 |   closebutton: true
 701 | });
702 |

Additionally, custom markup can be provided via closebuttonmarkup option.

703 | 704 |
705 | 706 | 714 | 715 | 716 | 717 | 718 | 719 | 720 | 721 | 722 | 723 | 724 |
725 |

Fade

726 |

CSS transitions can be set via options:

727 |
 728 | $('#fade').popup({
 729 |   transition: 'all 0.3s'
 730 | });
 731 | 
732 |

Or you can set them directly in CSS:

733 |
$('#fade').popup();
734 |
#fade,
 735 | #fade_wrapper,
 736 | #fade_background {
 737 |   transition: all 0.3s;
 738 | }
 739 | 
 740 | 
741 | 742 |
743 | 744 | 754 | 755 | 756 | 757 | 758 | 759 | 760 | 761 | 762 | 763 |
764 |

Scrolllock

765 |

Background scrolling can be locked with scrollock option.*

766 |
 767 | $('#scrolllock').popup({
 768 |   scrolllock: true
 769 | });
 770 | 
771 |

772 |
773 | 774 | 785 | 786 | 787 | 788 | 789 | 790 | 791 |
792 |

Fade & Scale Arrest

793 |

escape:false prevents closing on Esc key.

794 |

blur:false prevents closing on click outside the popup.

795 |
 796 | $('#fadeandscale').popup({
 797 |   escape: false,
 798 |   blur: false,
 799 |   scrolllock: true,
 800 |   transition: 'all 0.3s'
 801 | });
 802 | 
803 |
 804 | #fadeandscale {
 805 |   transform: scale(0.8);
 806 | }
 807 | .popup_visible #fadeandscale {
 808 |   transform: scale(1);
 809 | }
 810 | 
811 | 812 |
813 | 814 | 827 | 828 | 842 | 843 | 844 | 845 | 846 | 847 | 848 | 849 | 850 | 851 | 852 | 853 |
854 |

Slide-in

855 |

If you are using slide-in or any animation that is getting the popup out of the viewport, use focusdelay that is longer than transition-duration, it will make animations more smooth in Chrome on Android which tries to get the focused element to the viewport and conflicts the animation.

856 |

outline controls the outline visibility on the popup. It is optional and added just for demonstration.

857 |
 858 | $('#slide').popup({
 859 |   focusdelay: 400, // for smoother slide-in animations on Android
 860 |   outline: true,
 861 |   vertical: 'top'
 862 | });
 863 | 
 864 | 
865 |
 866 | #slide_background {
 867 |   transition: all 0.3s 0.3s;
 868 | }
 869 | #slide,
 870 | #slide_wrapper {
 871 |   transition: all 0.3s ease-out;
 872 | }
 873 | #slide {
 874 |   transform: translateX(0) translateY(-40%);
 875 | }
 876 | .popup_visible #slide {
 877 |   transform: translateX(0) translateY(0);
 878 | }
 879 | 
 880 | 
881 | 882 |
883 | 884 | 894 | 895 | 920 | 921 | 922 | 923 | 924 | 925 | 926 | 927 | 928 | 929 | 930 | 931 |
932 |

Stand-alone

933 |
 934 | $('#standalone').popup({
 935 |   color: 'white',
 936 |   opacity: 1,
 937 |   transition: '0.3s',
 938 |   scrolllock: true
 939 | });
 940 | 
 941 | 
942 |
 943 | #standalone {
 944 |   transform: scale(0.8);
 945 | }
 946 | .popup_visible #standalone {
 947 |   transform: scale(1);
 948 | }
 949 | 
 950 | 
951 | 952 |
953 | 954 | 955 | 956 | 968 | 969 | 984 | 985 | 986 | 987 | 988 | 989 | 990 | 991 | 992 | 993 | 994 | 995 | 996 | 997 |
998 |

Active background

999 |

background:false will enable interaction with background content (hover, click, etc.), while the popup is visible, as the background div will not be added to DOM.

1000 |

horizontal and vertical will set the position.

1001 |

keepfocus:false will prevent locking tabbing inside of popup, and leave a focus on the opening element.

1002 |

autozindex will keep the popup on top of all other elements on the page.

1003 |
1004 | $('#active_background_fixed').popup({
1005 |   background: false,
1006 |   horizontal: 'right',
1007 |   vertical: 'bottom',
1008 |   keepfocus: false,
1009 |   autozindex: true,
1010 |   blur: false
1011 | });
1012 | 
1013 | 1014 |
1015 | 1016 | 1029 | 1030 | 1031 | 1032 | 1033 | 1034 | 1035 | 1036 | 1037 | 1038 |
1039 |

Active background absolute

1040 |

absolute:true keeps the popup in place when scrolling.

1041 |

focuselement:'closebutton' will focus the Close element even if keepfocus is false.

1042 |

1043 |
1044 | $('#active_background_absolute').popup({
1045 |   absolute: true,
1046 |   background: false,
1047 |   keepfocus: false,
1048 |   focuselement: 'closebutton'
1049 | });
1050 | 
1051 | 1052 |
1053 | 1054 | 1065 | 1066 | 1067 | 1068 | 1069 |
1070 |

Tooltip

1071 |

type:'tooltip' will use the opening link as an anchor for positioning. 1072 | An anchor can be explicitly set with tooltipanchor option.

1073 |

offsetleft and offsetleft will set the offset.

1074 | 1075 |
$('#tooltip').popup({
1076 |   type: 'tooltip',
1077 |   tooltipanchor: $('#tooltip_open'),
1078 |   offsetleft: 0,
1079 |   offsettop: '-15',
1080 |   vertical: 'top',
1081 |   horizontal: 'center'
1082 | });
1083 | 1084 |
1085 | 1086 | 1100 | 1101 | 1102 | 1103 | 1104 | 1105 | 1106 |
1107 |

Callback events

1108 |
1109 | $('#fall').popup({
1110 |         beforeopen: function () {
1111 |             alert('beforeopen');
1112 |         },
1113 |         onopen: function () {
1114 |             alert('onopen');
1115 |         },
1116 |         onclose: function () {
1117 |             alert('onclose');
1118 |         },
1119 |         opentransitionend: function () {
1120 |             alert('opentransitionend');
1121 |         },
1122 |         closetransitionend: function () {
1123 |             alert('closetransitionend');
1124 |         }
1125 |     });
1126 | 
1127 | 
1128 | 1129 | 1130 |
1131 | 1132 | 1156 | 1157 | 1190 | 1191 | 1192 | 1193 | 1194 | 1195 |
1196 |

Other examples

1197 |

See other examples on JSBin:

1198 | 1202 |
1203 | 1204 | 1209 | 1210 | 1211 | 1212 | 1213 | 1214 | 1215 | 1216 | 1217 | 1220 | 1221 | 1222 | 1223 | 1224 | -------------------------------------------------------------------------------- /index.js: -------------------------------------------------------------------------------- 1 | /* eslint-disable */ 2 | if (!jQuery) { 3 | console.log('jquery.popupoverlay - jQuery not defined.'); 4 | } 5 | require('./jquery.popupoverlay'); -------------------------------------------------------------------------------- /jquery.popupoverlay.js: -------------------------------------------------------------------------------- 1 | /*! 2 | * jQuery Popup Overlay 3 | * 4 | * @requires jQuery v1.7.1+ 5 | * @link https://vast-engineering.github.com/jquery-popup-overlay/ 6 | */ 7 | ;(function ($) { /* eslint-disable-line */ 8 | 9 | var $window = $(window); 10 | var options = {}; 11 | var zindexvalues = []; 12 | var lastclicked = []; 13 | var scrollbarwidth; 14 | var bodymarginright = null; 15 | var opensuffix = '_open'; 16 | var closesuffix = '_close'; 17 | var visiblePopupsArray = []; 18 | var transitionsupport = null; 19 | var opentimer; 20 | var iOS = /(iPad|iPhone|iPod)/.test(navigator.userAgent); 21 | var focusableElementsString = "a[href], area[href], input:not([disabled]), select:not([disabled]), textarea:not([disabled]), button:not([disabled]), iframe, object, embed, *[tabindex], *[contenteditable]"; 22 | 23 | var methods = { 24 | 25 | _init: function (el) { 26 | var $el = $(el); 27 | var options = $el.data('popupoptions'); 28 | lastclicked[el.id] = false; 29 | zindexvalues[el.id] = 0; 30 | 31 | if (!$el.data('popup-initialized')) { 32 | $el.attr('data-popup-initialized', 'true'); 33 | methods._initonce(el); 34 | } 35 | 36 | if (options.autoopen) { 37 | setTimeout(function() { 38 | methods.show(el, 0); 39 | }, 0); 40 | } 41 | }, 42 | 43 | _initonce: function (el) { 44 | var $el = $(el); 45 | var $body = $('body'); 46 | var $wrapper; 47 | var options = $el.data('popupoptions'); 48 | 49 | bodymarginright = parseInt($body.css('margin-right'), 10); 50 | transitionsupport = document.body.style.webkitTransition !== undefined || 51 | document.body.style.MozTransition !== undefined || 52 | document.body.style.msTransition !== undefined || 53 | document.body.style.OTransition !== undefined || 54 | document.body.style.transition !== undefined; 55 | 56 | if (options.scrolllock) { 57 | // Calculate the browser's scrollbar width dynamically 58 | var parent; 59 | var child; 60 | if (typeof scrollbarwidth === 'undefined') { 61 | parent = $('
').appendTo('body'); 62 | child = parent.children(); 63 | scrollbarwidth = child.innerWidth() - child.height(99).innerWidth(); 64 | parent.remove(); 65 | } 66 | } 67 | 68 | if (!$el.attr('id')) { 69 | $el.attr('id', 'j-popup-' + parseInt((Math.random() * 100000000), 10)); 70 | } 71 | 72 | $el.addClass('popup_content'); 73 | 74 | if ((options.background) && (!$('#' + el.id + '_background').length)) { 75 | 76 | $body.append(''); 77 | 78 | var $background = $('#' + el.id + '_background'); 79 | 80 | $background.css({ 81 | opacity: 0, 82 | visibility: 'hidden', 83 | backgroundColor: options.color, 84 | position: 'fixed', 85 | top: 0, 86 | right: 0, 87 | bottom: 0, 88 | left: 0 89 | }); 90 | 91 | if (options.setzindex && !options.autozindex) { 92 | $background.css('z-index', '100000'); 93 | } 94 | 95 | if (options.transition) { 96 | $background.css('transition', options.transition); 97 | } 98 | } 99 | 100 | $body.append(el); 101 | 102 | $el.wrap('