dialog-polyfill-rails 0.4.5.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 237cb92f58f9c6f5851c6248329122fbbb96757b
4
+ data.tar.gz: 861985161565dd3b03828c644cac7a9021de9b6e
5
+ SHA512:
6
+ metadata.gz: 3f3e9b25bab51a9bdde256744abccc9a71378f6d6fc6b2d35e3b1d199964128adb9bce34de39dd19290518845ec8055d33d8f56fba22765b89d4b8cf42836971
7
+ data.tar.gz: 4643f1b7ea90709b6b6edc706dbd0e94b6408258bda445846a7461cb870b27c4b0f63aa2611ed88ab348229f24f11d62dfc00293f71c466a90c46cda2b360145
@@ -0,0 +1,10 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+ *.gem
@@ -0,0 +1,49 @@
1
+ # Contributor Code of Conduct
2
+
3
+ As contributors and maintainers of this project, and in the interest of
4
+ fostering an open and welcoming community, we pledge to respect all people who
5
+ contribute through reporting issues, posting feature requests, updating
6
+ documentation, submitting pull requests or patches, and other activities.
7
+
8
+ We are committed to making participation in this project a harassment-free
9
+ experience for everyone, regardless of level of experience, gender, gender
10
+ identity and expression, sexual orientation, disability, personal appearance,
11
+ body size, race, ethnicity, age, religion, or nationality.
12
+
13
+ Examples of unacceptable behavior by participants include:
14
+
15
+ * The use of sexualized language or imagery
16
+ * Personal attacks
17
+ * Trolling or insulting/derogatory comments
18
+ * Public or private harassment
19
+ * Publishing other's private information, such as physical or electronic
20
+ addresses, without explicit permission
21
+ * Other unethical or unprofessional conduct
22
+
23
+ Project maintainers have the right and responsibility to remove, edit, or
24
+ reject comments, commits, code, wiki edits, issues, and other contributions
25
+ that are not aligned to this Code of Conduct, or to ban temporarily or
26
+ permanently any contributor for other behaviors that they deem inappropriate,
27
+ threatening, offensive, or harmful.
28
+
29
+ By adopting this Code of Conduct, project maintainers commit themselves to
30
+ fairly and consistently applying these principles to every aspect of managing
31
+ this project. Project maintainers who do not follow or enforce the Code of
32
+ Conduct may be permanently removed from the project team.
33
+
34
+ This code of conduct applies both within project spaces and in public spaces
35
+ when an individual is representing the project or its community.
36
+
37
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
38
+ reported by contacting a project maintainer at mjmaix@gmail.com. All
39
+ complaints will be reviewed and investigated and will result in a response that
40
+ is deemed necessary and appropriate to the circumstances. Maintainers are
41
+ obligated to maintain confidentiality with regard to the reporter of an
42
+ incident.
43
+
44
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage],
45
+ version 1.3.0, available at
46
+ [http://contributor-covenant.org/version/1/3/0/][version]
47
+
48
+ [homepage]: http://contributor-covenant.org
49
+ [version]: http://contributor-covenant.org/version/1/3/0/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in dialog-polyfill-rails.gemspec
4
+ gemspec
@@ -0,0 +1,27 @@
1
+ // Copyright (c) 2013 The Chromium Authors. All rights reserved.
2
+ //
3
+ // Redistribution and use in source and binary forms, with or without
4
+ // modification, are permitted provided that the following conditions are
5
+ // met:
6
+ //
7
+ // * Redistributions of source code must retain the above copyright
8
+ // notice, this list of conditions and the following disclaimer.
9
+ // * Redistributions in binary form must reproduce the above
10
+ // copyright notice, this list of conditions and the following disclaimer
11
+ // in the documentation and/or other materials provided with the
12
+ // distribution.
13
+ // * Neither the name of Google Inc. nor the names of its
14
+ // contributors may be used to endorse or promote products derived from
15
+ // this software without specific prior written permission.
16
+ //
17
+ // THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
18
+ // "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
19
+ // LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
20
+ // A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
21
+ // OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
22
+ // SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
23
+ // LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24
+ // DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25
+ // THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26
+ // (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
27
+ // OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
@@ -0,0 +1,50 @@
1
+ # Dialog::Polyfill::Rails
2
+
3
+ Welcome to your new gem! In this directory, you'll find the files you need to be able to package up your Ruby library into a gem. Put your Ruby code in the file `lib/dialog/polyfill/rails`. To experiment with that code, run `bin/console` for an interactive prompt.
4
+
5
+ TODO: Delete this and the text above, and describe your gem
6
+
7
+ ## Installation
8
+
9
+ Add this line to your application's Gemfile:
10
+
11
+ ```ruby
12
+ gem 'dialog-polyfill-rails'
13
+ ```
14
+
15
+ Add this to your js manifest file
16
+
17
+ ```js
18
+ //= require dialog-polyfill
19
+ ```
20
+
21
+ Add this to your css manifest file
22
+
23
+ ```css
24
+ *= require dialog-polyfill
25
+ ```
26
+
27
+
28
+
29
+ And then execute:
30
+
31
+ $ bundle
32
+
33
+ Or install it yourself as:
34
+
35
+ $ gem install dialog-polyfill-rails
36
+
37
+ ## Usage
38
+
39
+ TODO: Write usage instructions here
40
+
41
+ ## Development
42
+
43
+ After checking out the repo, run `bin/setup` to install dependencies. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
44
+
45
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
46
+
47
+ ## Contributing
48
+
49
+ Bug reports and pull requests are welcome on GitHub at https://github.com/[USERNAME]/dialog-polyfill-rails. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](http://contributor-covenant.org) code of conduct.
50
+
@@ -0,0 +1,2 @@
1
+ require "bundler/gem_tasks"
2
+ task :default => :spec
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "dialog/polyfill/rails"
5
+
6
+ # You can add fixtures and/or initialization code here to make experimenting
7
+ # with your gem easier. You can also use a different console, if you like.
8
+
9
+ # (If you use this, don't forget to add pry to your Gemfile!)
10
+ # require "pry"
11
+ # Pry.start
12
+
13
+ require "irb"
14
+ IRB.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,31 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'dialog/polyfill/rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "dialog-polyfill-rails"
8
+ spec.version = Dialog::Polyfill::Rails::VERSION
9
+ spec.authors = ["MJ Abadilla"]
10
+ spec.email = ["mjmaix@gmail.com"]
11
+
12
+ spec.summary = %q{Gemified version of https://github.com/GoogleChrome/dialog-polyfill.}
13
+ spec.description = %q{Gemified version of https://github.com/GoogleChrome/dialog-polyfill.}
14
+ spec.homepage = "https://github.com/mjmaix/dialog-polyfill-rails"
15
+
16
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
17
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
18
+ if spec.respond_to?(:metadata)
19
+ spec.metadata['allowed_push_host'] = "https://rubygems.org"
20
+ else
21
+ raise "RubyGems 2.0 or newer is required to protect against public gem pushes."
22
+ end
23
+
24
+ spec.files = `git ls-files -z`.split("\x0").reject { |f| f.match(%r{^(test|spec|features)/}) }
25
+ spec.bindir = "exe"
26
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
27
+ spec.require_paths = ["lib"]
28
+
29
+ spec.add_development_dependency "bundler", "~> 1.13"
30
+ spec.add_development_dependency "rake", "~> 10.0"
31
+ end
@@ -0,0 +1,10 @@
1
+ require "dialog/polyfill/rails/version"
2
+
3
+ module Dialog
4
+ module Polyfill
5
+ module Rails
6
+ class Engine < ::Rails::Engine
7
+ end
8
+ end
9
+ end
10
+ end
@@ -0,0 +1,7 @@
1
+ module Dialog
2
+ module Polyfill
3
+ module Rails
4
+ VERSION = "0.4.5.1"
5
+ end
6
+ end
7
+ end
@@ -0,0 +1,523 @@
1
+ (function() {
2
+
3
+ var supportCustomEvent = window.CustomEvent;
4
+ if (!supportCustomEvent || typeof supportCustomEvent == 'object') {
5
+ supportCustomEvent = function CustomEvent(event, x) {
6
+ x = x || {};
7
+ var ev = document.createEvent('CustomEvent');
8
+ ev.initCustomEvent(event, !!x.bubbles, !!x.cancelable, x.detail || null);
9
+ return ev;
10
+ };
11
+ supportCustomEvent.prototype = window.Event.prototype;
12
+ }
13
+
14
+ /**
15
+ * Finds the nearest <dialog> from the passed element.
16
+ *
17
+ * @param {Element} el to search from
18
+ * @return {HTMLDialogElement} dialog found
19
+ */
20
+ function findNearestDialog(el) {
21
+ while (el) {
22
+ if (el.nodeName.toUpperCase() == 'DIALOG') {
23
+ return /** @type {HTMLDialogElement} */ (el);
24
+ }
25
+ el = el.parentElement;
26
+ }
27
+ return null;
28
+ }
29
+
30
+ /**
31
+ * Blur the specified element, as long as it's not the HTML body element.
32
+ * This works around an IE9/10 bug - blurring the body causes Windows to
33
+ * blur the whole application.
34
+ *
35
+ * @param {Element} el to blur
36
+ */
37
+ function safeBlur(el) {
38
+ if (el && el.blur && el != document.body) {
39
+ el.blur();
40
+ }
41
+ }
42
+
43
+ /**
44
+ * @param {!NodeList} nodeList to search
45
+ * @param {Node} node to find
46
+ * @return {boolean} whether node is inside nodeList
47
+ */
48
+ function inNodeList(nodeList, node) {
49
+ for (var i = 0; i < nodeList.length; ++i) {
50
+ if (nodeList[i] == node) {
51
+ return true;
52
+ }
53
+ }
54
+ return false;
55
+ }
56
+
57
+ /**
58
+ * @param {!HTMLDialogElement} dialog to upgrade
59
+ * @constructor
60
+ */
61
+ function dialogPolyfillInfo(dialog) {
62
+ this.dialog_ = dialog;
63
+ this.replacedStyleTop_ = false;
64
+ this.openAsModal_ = false;
65
+
66
+ // Set a11y role. Browsers that support dialog implicitly know this already.
67
+ if (!dialog.hasAttribute('role')) {
68
+ dialog.setAttribute('role', 'dialog');
69
+ }
70
+
71
+ dialog.show = this.show.bind(this);
72
+ dialog.showModal = this.showModal.bind(this);
73
+ dialog.close = this.close.bind(this);
74
+
75
+ if (!('returnValue' in dialog)) {
76
+ dialog.returnValue = '';
77
+ }
78
+
79
+ this.maybeHideModal = this.maybeHideModal.bind(this);
80
+ if ('MutationObserver' in window) {
81
+ // IE11+, most other browsers.
82
+ var mo = new MutationObserver(this.maybeHideModal);
83
+ mo.observe(dialog, { attributes: true, attributeFilter: ['open'] });
84
+ } else {
85
+ dialog.addEventListener('DOMAttrModified', this.maybeHideModal);
86
+ }
87
+ // Note that the DOM is observed inside DialogManager while any dialog
88
+ // is being displayed as a modal, to catch modal removal from the DOM.
89
+
90
+ Object.defineProperty(dialog, 'open', {
91
+ set: this.setOpen.bind(this),
92
+ get: dialog.hasAttribute.bind(dialog, 'open')
93
+ });
94
+
95
+ this.backdrop_ = document.createElement('div');
96
+ this.backdrop_.className = 'backdrop';
97
+ this.backdropClick_ = this.backdropClick_.bind(this);
98
+ }
99
+
100
+ dialogPolyfillInfo.prototype = {
101
+
102
+ get dialog() {
103
+ return this.dialog_;
104
+ },
105
+
106
+ /**
107
+ * Maybe remove this dialog from the modal top layer. This is called when
108
+ * a modal dialog may no longer be tenable, e.g., when the dialog is no
109
+ * longer open or is no longer part of the DOM.
110
+ */
111
+ maybeHideModal: function() {
112
+ if (!this.openAsModal_) { return; }
113
+ if (this.dialog_.hasAttribute('open') &&
114
+ document.body.contains(this.dialog_)) { return; }
115
+
116
+ this.openAsModal_ = false;
117
+ this.dialog_.style.zIndex = '';
118
+
119
+ // This won't match the native <dialog> exactly because if the user set
120
+ // top on a centered polyfill dialog, that top gets thrown away when the
121
+ // dialog is closed. Not sure it's possible to polyfill this perfectly.
122
+ if (this.replacedStyleTop_) {
123
+ this.dialog_.style.top = '';
124
+ this.replacedStyleTop_ = false;
125
+ }
126
+
127
+ // Optimistically clear the modal part of this <dialog>.
128
+ this.backdrop_.removeEventListener('click', this.backdropClick_);
129
+ if (this.backdrop_.parentElement) {
130
+ this.backdrop_.parentElement.removeChild(this.backdrop_);
131
+ }
132
+ dialogPolyfill.dm.removeDialog(this);
133
+ },
134
+
135
+ /**
136
+ * @param {boolean} value whether to open or close this dialog
137
+ */
138
+ setOpen: function(value) {
139
+ if (value) {
140
+ this.dialog_.hasAttribute('open') || this.dialog_.setAttribute('open', '');
141
+ } else {
142
+ this.dialog_.removeAttribute('open');
143
+ this.maybeHideModal(); // nb. redundant with MutationObserver
144
+ }
145
+ },
146
+
147
+ /**
148
+ * Handles clicks on the fake .backdrop element, redirecting them as if
149
+ * they were on the dialog itself.
150
+ *
151
+ * @param {!Event} e to redirect
152
+ */
153
+ backdropClick_: function(e) {
154
+ var redirectedEvent = document.createEvent('MouseEvents');
155
+ redirectedEvent.initMouseEvent(e.type, e.bubbles, e.cancelable, window,
156
+ e.detail, e.screenX, e.screenY, e.clientX, e.clientY, e.ctrlKey,
157
+ e.altKey, e.shiftKey, e.metaKey, e.button, e.relatedTarget);
158
+ this.dialog_.dispatchEvent(redirectedEvent);
159
+ e.stopPropagation();
160
+ },
161
+
162
+ /**
163
+ * Focuses on the first focusable element within the dialog. This will always blur the current
164
+ * focus, even if nothing within the dialog is found.
165
+ */
166
+ focus_: function() {
167
+ // Find element with `autofocus` attribute, or fall back to the first form/tabindex control.
168
+ var target = this.dialog_.querySelector('[autofocus]:not([disabled])');
169
+ if (!target) {
170
+ // Note that this is 'any focusable area'. This list is probably not exhaustive, but the
171
+ // alternative involves stepping through and trying to focus everything.
172
+ var opts = ['button', 'input', 'keygen', 'select', 'textarea'];
173
+ var query = opts.map(function(el) {
174
+ return el + ':not([disabled])';
175
+ });
176
+ // TODO(samthor): tabindex values that are not numeric are not focusable.
177
+ query.push('[tabindex]:not([disabled]):not([tabindex=""])'); // tabindex != "", not disabled
178
+ target = this.dialog_.querySelector(query.join(', '));
179
+ }
180
+ safeBlur(document.activeElement);
181
+ target && target.focus();
182
+ },
183
+
184
+ /**
185
+ * Sets the zIndex for the backdrop and dialog.
186
+ *
187
+ * @param {number} dialogZ
188
+ * @param {number} backdropZ
189
+ */
190
+ updateZIndex: function(dialogZ, backdropZ) {
191
+ if (dialogZ < backdropZ) {
192
+ throw new Error('dialogZ should never be < backdropZ');
193
+ }
194
+ this.dialog_.style.zIndex = dialogZ;
195
+ this.backdrop_.style.zIndex = backdropZ;
196
+ },
197
+
198
+ /**
199
+ * Shows the dialog. If the dialog is already open, this does nothing.
200
+ */
201
+ show: function() {
202
+ if (!this.dialog_.open) {
203
+ this.setOpen(true);
204
+ this.focus_();
205
+ }
206
+ },
207
+
208
+ /**
209
+ * Show this dialog modally.
210
+ */
211
+ showModal: function() {
212
+ if (this.dialog_.hasAttribute('open')) {
213
+ throw new Error('Failed to execute \'showModal\' on dialog: The element is already open, and therefore cannot be opened modally.');
214
+ }
215
+ if (!document.body.contains(this.dialog_)) {
216
+ throw new Error('Failed to execute \'showModal\' on dialog: The element is not in a Document.');
217
+ }
218
+ if (!dialogPolyfill.dm.pushDialog(this)) {
219
+ throw new Error('Failed to execute \'showModal\' on dialog: There are too many open modal dialogs.');
220
+ }
221
+ this.show();
222
+ this.openAsModal_ = true;
223
+
224
+ // Optionally center vertically, relative to the current viewport.
225
+ if (dialogPolyfill.needsCentering(this.dialog_)) {
226
+ dialogPolyfill.reposition(this.dialog_);
227
+ this.replacedStyleTop_ = true;
228
+ } else {
229
+ this.replacedStyleTop_ = false;
230
+ }
231
+
232
+ // Insert backdrop.
233
+ this.backdrop_.addEventListener('click', this.backdropClick_);
234
+ this.dialog_.parentNode.insertBefore(this.backdrop_,
235
+ this.dialog_.nextSibling);
236
+ },
237
+
238
+ /**
239
+ * Closes this HTMLDialogElement. This is optional vs clearing the open
240
+ * attribute, however this fires a 'close' event.
241
+ *
242
+ * @param {string=} opt_returnValue to use as the returnValue
243
+ */
244
+ close: function(opt_returnValue) {
245
+ if (!this.dialog_.hasAttribute('open')) {
246
+ throw new Error('Failed to execute \'close\' on dialog: The element does not have an \'open\' attribute, and therefore cannot be closed.');
247
+ }
248
+ this.setOpen(false);
249
+
250
+ // Leave returnValue untouched in case it was set directly on the element
251
+ if (opt_returnValue !== undefined) {
252
+ this.dialog_.returnValue = opt_returnValue;
253
+ }
254
+
255
+ // Triggering "close" event for any attached listeners on the <dialog>.
256
+ var closeEvent = new supportCustomEvent('close', {
257
+ bubbles: false,
258
+ cancelable: false
259
+ });
260
+ this.dialog_.dispatchEvent(closeEvent);
261
+ }
262
+
263
+ };
264
+
265
+ var dialogPolyfill = {};
266
+
267
+ dialogPolyfill.reposition = function(element) {
268
+ var scrollTop = document.body.scrollTop || document.documentElement.scrollTop;
269
+ var topValue = scrollTop + (window.innerHeight - element.offsetHeight) / 2;
270
+ element.style.top = Math.max(scrollTop, topValue) + 'px';
271
+ };
272
+
273
+ dialogPolyfill.isInlinePositionSetByStylesheet = function(element) {
274
+ for (var i = 0; i < document.styleSheets.length; ++i) {
275
+ var styleSheet = document.styleSheets[i];
276
+ var cssRules = null;
277
+ // Some browsers throw on cssRules.
278
+ try {
279
+ cssRules = styleSheet.cssRules;
280
+ } catch (e) {}
281
+ if (!cssRules) { continue; }
282
+ for (var j = 0; j < cssRules.length; ++j) {
283
+ var rule = cssRules[j];
284
+ var selectedNodes = null;
285
+ // Ignore errors on invalid selector texts.
286
+ try {
287
+ selectedNodes = document.querySelectorAll(rule.selectorText);
288
+ } catch(e) {}
289
+ if (!selectedNodes || !inNodeList(selectedNodes, element)) {
290
+ continue;
291
+ }
292
+ var cssTop = rule.style.getPropertyValue('top');
293
+ var cssBottom = rule.style.getPropertyValue('bottom');
294
+ if ((cssTop && cssTop != 'auto') || (cssBottom && cssBottom != 'auto')) {
295
+ return true;
296
+ }
297
+ }
298
+ }
299
+ return false;
300
+ };
301
+
302
+ dialogPolyfill.needsCentering = function(dialog) {
303
+ var computedStyle = window.getComputedStyle(dialog);
304
+ if (computedStyle.position != 'absolute') {
305
+ return false;
306
+ }
307
+
308
+ // We must determine whether the top/bottom specified value is non-auto. In
309
+ // WebKit/Blink, checking computedStyle.top == 'auto' is sufficient, but
310
+ // Firefox returns the used value. So we do this crazy thing instead: check
311
+ // the inline style and then go through CSS rules.
312
+ if ((dialog.style.top != 'auto' && dialog.style.top != '') ||
313
+ (dialog.style.bottom != 'auto' && dialog.style.bottom != ''))
314
+ return false;
315
+ return !dialogPolyfill.isInlinePositionSetByStylesheet(dialog);
316
+ };
317
+
318
+ /**
319
+ * @param {!Element} element to force upgrade
320
+ */
321
+ dialogPolyfill.forceRegisterDialog = function(element) {
322
+ if (element.showModal) {
323
+ console.warn('This browser already supports <dialog>, the polyfill ' +
324
+ 'may not work correctly', element);
325
+ }
326
+ if (element.nodeName.toUpperCase() != 'DIALOG') {
327
+ throw new Error('Failed to register dialog: The element is not a dialog.');
328
+ }
329
+ new dialogPolyfillInfo(/** @type {!HTMLDialogElement} */ (element));
330
+ };
331
+
332
+ /**
333
+ * @param {!Element} element to upgrade, if necessary
334
+ */
335
+ dialogPolyfill.registerDialog = function(element) {
336
+ if (!element.showModal) {
337
+ dialogPolyfill.forceRegisterDialog(element);
338
+ }
339
+ };
340
+
341
+ /**
342
+ * @constructor
343
+ */
344
+ dialogPolyfill.DialogManager = function() {
345
+ /** @type {!Array<!dialogPolyfillInfo>} */
346
+ this.pendingDialogStack = [];
347
+
348
+ // The overlay is used to simulate how a modal dialog blocks the document.
349
+ // The blocking dialog is positioned on top of the overlay, and the rest of
350
+ // the dialogs on the pending dialog stack are positioned below it. In the
351
+ // actual implementation, the modal dialog stacking is controlled by the
352
+ // top layer, where z-index has no effect.
353
+ this.overlay = document.createElement('div');
354
+ this.overlay.className = '_dialog_overlay';
355
+ this.overlay.addEventListener('click', function(e) {
356
+ e.stopPropagation();
357
+ this.checkDOM_(); // sanity-check DOM
358
+ }.bind(this));
359
+
360
+ this.handleKey_ = this.handleKey_.bind(this);
361
+ this.handleFocus_ = this.handleFocus_.bind(this);
362
+ this.handleRemove_ = this.handleRemove_.bind(this);
363
+
364
+ this.zIndexLow_ = 100000;
365
+ this.zIndexHigh_ = 100000 + 150;
366
+ };
367
+
368
+ /**
369
+ * @return {Element} the top HTML dialog element, if any
370
+ */
371
+ dialogPolyfill.DialogManager.prototype.topDialogElement = function() {
372
+ var dpi = this.pendingDialogStack[0];
373
+ return dpi ? dpi.dialog : null;
374
+ };
375
+
376
+ /**
377
+ * Called on the first modal dialog being shown. Adds the overlay and related
378
+ * handlers.
379
+ */
380
+ dialogPolyfill.DialogManager.prototype.blockDocument = function() {
381
+ document.body.appendChild(this.overlay);
382
+ document.body.addEventListener('focus', this.handleFocus_, true);
383
+ document.addEventListener('keydown', this.handleKey_);
384
+ document.addEventListener('DOMNodeRemoved', this.handleRemove_);
385
+ };
386
+
387
+ /**
388
+ * Called on the first modal dialog being removed, i.e., when no more modal
389
+ * dialogs are visible.
390
+ */
391
+ dialogPolyfill.DialogManager.prototype.unblockDocument = function() {
392
+ document.body.removeChild(this.overlay);
393
+ document.body.removeEventListener('focus', this.handleFocus_, true);
394
+ document.removeEventListener('keydown', this.handleKey_);
395
+ document.removeEventListener('DOMNodeRemoved', this.handleRemove_);
396
+ };
397
+
398
+ dialogPolyfill.DialogManager.prototype.updateStacking = function() {
399
+ var zIndex = this.zIndexHigh_;
400
+
401
+ for (var i = 0, dpi; dpi = this.pendingDialogStack[i]; ++i) {
402
+ dpi.updateZIndex(--zIndex, --zIndex);
403
+ if (i === 0) {
404
+ this.overlay.style.zIndex = --zIndex;
405
+ }
406
+ }
407
+ };
408
+
409
+ dialogPolyfill.DialogManager.prototype.handleFocus_ = function(event) {
410
+ var candidate = findNearestDialog(/** @type {Element} */ (event.target));
411
+ if (candidate != this.topDialogElement()) {
412
+ event.preventDefault();
413
+ event.stopPropagation();
414
+ safeBlur(/** @type {Element} */ (event.target));
415
+ // TODO: Focus on the browser chrome (aka document) or the dialog itself
416
+ // depending on the tab direction.
417
+ return false;
418
+ }
419
+ };
420
+
421
+ dialogPolyfill.DialogManager.prototype.handleKey_ = function(event) {
422
+ if (event.keyCode == 27) {
423
+ event.preventDefault();
424
+ event.stopPropagation();
425
+ var cancelEvent = new supportCustomEvent('cancel', {
426
+ bubbles: false,
427
+ cancelable: true
428
+ });
429
+ var dialog = this.topDialogElement();
430
+ if (dialog.dispatchEvent(cancelEvent)) {
431
+ dialog.close();
432
+ }
433
+ }
434
+ };
435
+
436
+ /**
437
+ * Finds and removes any modal dialogs that are no longer on the page.
438
+ */
439
+ dialogPolyfill.DialogManager.prototype.checkDOM_ = function() {
440
+ var clone = this.pendingDialogStack.slice();
441
+ clone.forEach(function(dpi) {
442
+ dpi.maybeHideModal();
443
+ });
444
+ };
445
+
446
+ dialogPolyfill.DialogManager.prototype.handleRemove_ = function(event) {
447
+ if (event.target.nodeName.toUpperCase() !== 'DIALOG') { return; }
448
+ this.checkDOM_();
449
+ };
450
+
451
+ /**
452
+ * @param {!dialogPolyfillInfo} dpi
453
+ * @return {boolean} whether the dialog was allowed
454
+ */
455
+ dialogPolyfill.DialogManager.prototype.pushDialog = function(dpi) {
456
+ var allowed = (this.zIndexHigh_ - this.zIndexLow_) / 2 - 1;
457
+ if (this.pendingDialogStack.length >= allowed) {
458
+ return false;
459
+ }
460
+ if (this.pendingDialogStack.unshift(dpi) === 1) {
461
+ this.blockDocument();
462
+ }
463
+ this.updateStacking();
464
+ return true;
465
+ };
466
+
467
+ /**
468
+ * @param {!dialogPolyfillInfo} dpi
469
+ */
470
+ dialogPolyfill.DialogManager.prototype.removeDialog = function(dpi) {
471
+ var index = this.pendingDialogStack.indexOf(dpi);
472
+ if (index == -1) { return; }
473
+
474
+ this.pendingDialogStack.splice(index, 1);
475
+ this.updateStacking();
476
+ if (this.pendingDialogStack.length === 0) {
477
+ this.unblockDocument();
478
+ }
479
+ };
480
+
481
+ dialogPolyfill.dm = new dialogPolyfill.DialogManager();
482
+
483
+ /**
484
+ * Global form 'dialog' method handler. Closes a dialog correctly on submit
485
+ * and possibly sets its return value.
486
+ */
487
+ document.addEventListener('submit', function(ev) {
488
+ var target = ev.target;
489
+ if (!target || !target.hasAttribute('method')) { return; }
490
+ if (target.getAttribute('method').toLowerCase() != 'dialog') { return; }
491
+ ev.preventDefault();
492
+
493
+ var dialog = findNearestDialog(/** @type {Element} */ (ev.target));
494
+ if (!dialog) { return; }
495
+
496
+ // FIXME: The original event doesn't contain the element used to submit the
497
+ // form (if any). Look in some possible places.
498
+ var returnValue;
499
+ var cands = [document.activeElement, ev.explicitOriginalTarget];
500
+ var els = ['BUTTON', 'INPUT'];
501
+ cands.some(function(cand) {
502
+ if (cand && cand.form == ev.target && els.indexOf(cand.nodeName.toUpperCase()) != -1) {
503
+ returnValue = cand.value;
504
+ return true;
505
+ }
506
+ });
507
+ dialog.close(returnValue);
508
+ }, true);
509
+
510
+ dialogPolyfill['forceRegisterDialog'] = dialogPolyfill.forceRegisterDialog;
511
+ dialogPolyfill['registerDialog'] = dialogPolyfill.registerDialog;
512
+
513
+ if (typeof define === 'function' && 'amd' in define) {
514
+ // AMD support
515
+ define(function() { return dialogPolyfill; });
516
+ } else if (typeof module === 'object' && typeof module['exports'] === 'object') {
517
+ // CommonJS support
518
+ module['exports'] = dialogPolyfill;
519
+ } else {
520
+ // all others
521
+ window['dialogPolyfill'] = dialogPolyfill;
522
+ }
523
+ })();
@@ -0,0 +1,46 @@
1
+ dialog {
2
+ position: absolute;
3
+ left: 0; right: 0;
4
+ width: -moz-fit-content;
5
+ width: -webkit-fit-content;
6
+ width: fit-content;
7
+ height: -moz-fit-content;
8
+ height: -webkit-fit-content;
9
+ height: fit-content;
10
+ margin: auto;
11
+ border: solid;
12
+ padding: 1em;
13
+ background: white;
14
+ color: black;
15
+ display: none;
16
+ }
17
+
18
+ dialog[open] {
19
+ display: block;
20
+ }
21
+
22
+ dialog + .backdrop {
23
+ position: fixed;
24
+ top: 0; right: 0; bottom: 0; left: 0;
25
+ background: rgba(0,0,0,0.1);
26
+ }
27
+
28
+ /* for small devices, modal dialogs go full-screen */
29
+ @media screen and (max-width: 540px) {
30
+ dialog[_polyfill_modal] { /* TODO: implement */
31
+ top: 0;
32
+ width: auto;
33
+ margin: 1em;
34
+ }
35
+ }
36
+
37
+ ._dialog_overlay {
38
+ position: fixed;
39
+ top: 0; right: 0; bottom: 0; left: 0;
40
+ }
41
+
42
+ dialog.fixed {
43
+ position: fixed;
44
+ top: 50%;
45
+ transform: translate(0, -50%);
46
+ }
metadata ADDED
@@ -0,0 +1,85 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: dialog-polyfill-rails
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.4.5.1
5
+ platform: ruby
6
+ authors:
7
+ - MJ Abadilla
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-01-02 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.13'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.13'
27
+ - !ruby/object:Gem::Dependency
28
+ name: rake
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '10.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '10.0'
41
+ description: Gemified version of https://github.com/GoogleChrome/dialog-polyfill.
42
+ email:
43
+ - mjmaix@gmail.com
44
+ executables: []
45
+ extensions: []
46
+ extra_rdoc_files: []
47
+ files:
48
+ - ".gitignore"
49
+ - CODE_OF_CONDUCT.md
50
+ - Gemfile
51
+ - LICENSE.txt
52
+ - README.md
53
+ - Rakefile
54
+ - bin/console
55
+ - bin/setup
56
+ - dialog-polyfill-rails.gemspec
57
+ - lib/dialog/polyfill/rails.rb
58
+ - lib/dialog/polyfill/rails/version.rb
59
+ - vendor/assets/javascripts/dialog-polyfill.js
60
+ - vendor/assets/stylesheets/dialog-polyfill.css
61
+ homepage: https://github.com/mjmaix/dialog-polyfill-rails
62
+ licenses: []
63
+ metadata:
64
+ allowed_push_host: https://rubygems.org
65
+ post_install_message:
66
+ rdoc_options: []
67
+ require_paths:
68
+ - lib
69
+ required_ruby_version: !ruby/object:Gem::Requirement
70
+ requirements:
71
+ - - ">="
72
+ - !ruby/object:Gem::Version
73
+ version: '0'
74
+ required_rubygems_version: !ruby/object:Gem::Requirement
75
+ requirements:
76
+ - - ">="
77
+ - !ruby/object:Gem::Version
78
+ version: '0'
79
+ requirements: []
80
+ rubyforge_project:
81
+ rubygems_version: 2.6.8
82
+ signing_key:
83
+ specification_version: 4
84
+ summary: Gemified version of https://github.com/GoogleChrome/dialog-polyfill.
85
+ test_files: []