dialog-polyfill-rails 0.4.5.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -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: []