remodal-rails 1.1.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: bdb8b9392effcc3fb66e88628887c90521c1da44
4
+ data.tar.gz: d4821f1e874ce47fafd779bc4eda9e3477cb77df
5
+ SHA512:
6
+ metadata.gz: b21ff5bc5731a6a6b172846ccd4179805fa8a6521466a582a9ce7d4e3f3f5d4c0fb879150c8c76a38cc8e8d70f2909d414c32632c30bba7571a1f0f93f2a0b62
7
+ data.tar.gz: c30cad3d35647dbbb8bbed86437168cd119ec1909bd62fa8fc613e2cdbff87056a0780e10b97128357fbf91bb710ef77c96f43554bdc622f93d69defe90a14a8
data/.gitignore ADDED
@@ -0,0 +1,9 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
data/.travis.yml ADDED
@@ -0,0 +1,5 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.3.1
5
+ before_install: gem install bundler -v 1.13.6
@@ -0,0 +1,74 @@
1
+ # Contributor Covenant Code of Conduct
2
+
3
+ ## Our Pledge
4
+
5
+ In the interest of fostering an open and welcoming environment, we as
6
+ contributors and maintainers pledge to making participation in our project and
7
+ our community a harassment-free experience for everyone, regardless of age, body
8
+ size, disability, ethnicity, gender identity and expression, level of experience,
9
+ nationality, personal appearance, race, religion, or sexual identity and
10
+ orientation.
11
+
12
+ ## Our Standards
13
+
14
+ Examples of behavior that contributes to creating a positive environment
15
+ include:
16
+
17
+ * Using welcoming and inclusive language
18
+ * Being respectful of differing viewpoints and experiences
19
+ * Gracefully accepting constructive criticism
20
+ * Focusing on what is best for the community
21
+ * Showing empathy towards other community members
22
+
23
+ Examples of unacceptable behavior by participants include:
24
+
25
+ * The use of sexualized language or imagery and unwelcome sexual attention or
26
+ advances
27
+ * Trolling, insulting/derogatory comments, and personal or political attacks
28
+ * Public or private harassment
29
+ * Publishing others' private information, such as a physical or electronic
30
+ address, without explicit permission
31
+ * Other conduct which could reasonably be considered inappropriate in a
32
+ professional setting
33
+
34
+ ## Our Responsibilities
35
+
36
+ Project maintainers are responsible for clarifying the standards of acceptable
37
+ behavior and are expected to take appropriate and fair corrective action in
38
+ response to any instances of unacceptable behavior.
39
+
40
+ Project maintainers have the right and responsibility to remove, edit, or
41
+ reject comments, commits, code, wiki edits, issues, and other contributions
42
+ that are not aligned to this Code of Conduct, or to ban temporarily or
43
+ permanently any contributor for other behaviors that they deem inappropriate,
44
+ threatening, offensive, or harmful.
45
+
46
+ ## Scope
47
+
48
+ This Code of Conduct applies both within project spaces and in public spaces
49
+ when an individual is representing the project or its community. Examples of
50
+ representing a project or community include using an official project e-mail
51
+ address, posting via an official social media account, or acting as an appointed
52
+ representative at an online or offline event. Representation of a project may be
53
+ further defined and clarified by project maintainers.
54
+
55
+ ## Enforcement
56
+
57
+ Instances of abusive, harassing, or otherwise unacceptable behavior may be
58
+ reported by contacting the project team at sadiqmmm@gmail.com. All
59
+ complaints will be reviewed and investigated and will result in a response that
60
+ is deemed necessary and appropriate to the circumstances. The project team is
61
+ obligated to maintain confidentiality with regard to the reporter of an incident.
62
+ Further details of specific enforcement policies may be posted separately.
63
+
64
+ Project maintainers who do not follow or enforce the Code of Conduct in good
65
+ faith may face temporary or permanent repercussions as determined by other
66
+ members of the project's leadership.
67
+
68
+ ## Attribution
69
+
70
+ This Code of Conduct is adapted from the [Contributor Covenant][homepage], version 1.4,
71
+ available at [http://contributor-covenant.org/version/1/4][version]
72
+
73
+ [homepage]: http://contributor-covenant.org
74
+ [version]: http://contributor-covenant.org/version/1/4/
data/Gemfile ADDED
@@ -0,0 +1,4 @@
1
+ source 'https://rubygems.org'
2
+
3
+ # Specify your gem's dependencies in remodal-rails.gemspec
4
+ gemspec
data/LICENSE.txt ADDED
@@ -0,0 +1,21 @@
1
+ The MIT License (MIT)
2
+
3
+ Copyright (c) 2016 Mohammed Sadiq
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
13
+ all 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
21
+ THE SOFTWARE.
data/README.md ADDED
@@ -0,0 +1,57 @@
1
+ # remodal-rails
2
+ [![Gem Version](https://badge.fury.io/rb/remodal-rails.svg)](http://badge.fury.io/rb/remodal-rails)
3
+
4
+ remodal-rails gem is the integration of remodal.js javascript library for your Rails 4 and Rails 5 application.
5
+
6
+ Responsive, lightweight, fast, synchronized with CSS animations, fully customizable modal window plugin with declarative configuration and hash tracking.
7
+ source: http://vodkabears.github.io/remodal/
8
+
9
+ Ruby gems url: https://rubygems.org/gems/remodal-rails
10
+
11
+ ## Installation
12
+
13
+ Add this line to your application's Gemfile:
14
+
15
+ ```ruby
16
+ gem 'remodal-rails'
17
+ ```
18
+
19
+ And then execute:
20
+
21
+ $ bundle
22
+
23
+ Or install it yourself as:
24
+
25
+ $ gem install remodal-rails
26
+
27
+ Now you need to edit your `app/assets/stylesheets/application.css` file and add the following lines:
28
+
29
+ ``` css
30
+ *= require remodal-default-theme
31
+ *= require remodal
32
+ ```
33
+
34
+ Now you need to edit your `app/assets/javascripts/application.js` file and add the following line:
35
+
36
+ ``` javascript
37
+ //= require remodal
38
+ ```
39
+
40
+ ## Full documentation
41
+
42
+ Read the remodal.js documentation here https://github.com/VodkaBears/Remodal
43
+
44
+ ## Development
45
+
46
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake false` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
47
+
48
+ 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).
49
+
50
+ ## Contributing
51
+
52
+ Bug reports and pull requests are welcome on GitHub at https://github.com/sadiqmmm/remodal-rails. This project is intended to be a safe, welcoming space for collaboration, and contributors are expected to adhere to the [Contributor Covenant](contributor-covenant.org) code of conduct.
53
+
54
+
55
+ ## License
56
+
57
+ The gem is available as open source under the terms of the [MIT License](http://opensource.org/licenses/MIT).
data/Rakefile ADDED
@@ -0,0 +1,10 @@
1
+ require "bundler/gem_tasks"
2
+ require "rake/testtask"
3
+
4
+ Rake::TestTask.new(:test) do |t|
5
+ t.libs << "test"
6
+ t.libs << "lib"
7
+ t.test_files = FileList['test/**/*_test.rb']
8
+ end
9
+
10
+ task :default => :test
data/bin/console ADDED
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require "bundler/setup"
4
+ require "remodal/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
data/bin/setup ADDED
@@ -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,7 @@
1
+ require "remodal/rails/version"
2
+
3
+ module Remodal
4
+ module Rails
5
+ class Engine < ::Rails::Engine; end
6
+ end
7
+ end
@@ -0,0 +1,5 @@
1
+ module Remodal
2
+ module Rails
3
+ VERSION = "1.1.0"
4
+ end
5
+ end
@@ -0,0 +1,37 @@
1
+ # coding: utf-8
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'remodal/rails/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = "remodal-rails"
8
+ spec.version = Remodal::Rails::VERSION
9
+ spec.authors = ["Mohammed Sadiq"]
10
+ spec.email = ["sadiqmmm@gmail.com"]
11
+
12
+ spec.summary = spec.description
13
+ spec.description = 'This gem provides the Remodal.js Javascript library for your Rails 4 and Rails 5 application.'
14
+ spec.homepage = 'https://github.com/sadiqmmm/remodal-rails'
15
+ spec.license = "MIT"
16
+
17
+ # Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
18
+ # to allow pushing to a single host or delete this section to allow pushing to any host.
19
+ #
20
+ # if spec.respond_to?(:metadata)
21
+ # spec.metadata['allowed_push_host'] = "TODO: Set to 'http://mygemserver.com'"
22
+ # else
23
+ # raise "RubyGems 2.0 or newer is required to protect against " \
24
+ # "public gem pushes."
25
+ # end
26
+
27
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
28
+ f.match(%r{^(test|spec|features)/})
29
+ end
30
+ spec.bindir = "exe"
31
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
32
+ spec.require_paths = ["lib"]
33
+
34
+ spec.add_development_dependency "bundler", "~> 1.13"
35
+ spec.add_development_dependency "rake", "~> 10.0"
36
+ spec.add_development_dependency "minitest", "~> 5.0"
37
+ end
@@ -0,0 +1,785 @@
1
+ /*
2
+ * Remodal - v1.1.0
3
+ * Responsive, lightweight, fast, synchronized with CSS animations, fully customizable modal window plugin with declarative configuration and hash tracking.
4
+ * http://vodkabears.github.io/remodal/
5
+ *
6
+ * Made by Ilya Makarov
7
+ * Under MIT License
8
+ */
9
+
10
+ !(function(root, factory) {
11
+ if (typeof define === 'function' && define.amd) {
12
+ define(['jquery'], function($) {
13
+ return factory(root, $);
14
+ });
15
+ } else if (typeof exports === 'object') {
16
+ factory(root, require('jquery'));
17
+ } else {
18
+ factory(root, root.jQuery || root.Zepto);
19
+ }
20
+ })(this, function(global, $) {
21
+
22
+ 'use strict';
23
+
24
+ /**
25
+ * Name of the plugin
26
+ * @private
27
+ * @const
28
+ * @type {String}
29
+ */
30
+ var PLUGIN_NAME = 'remodal';
31
+
32
+ /**
33
+ * Namespace for CSS and events
34
+ * @private
35
+ * @const
36
+ * @type {String}
37
+ */
38
+ var NAMESPACE = global.REMODAL_GLOBALS && global.REMODAL_GLOBALS.NAMESPACE || PLUGIN_NAME;
39
+
40
+ /**
41
+ * Animationstart event with vendor prefixes
42
+ * @private
43
+ * @const
44
+ * @type {String}
45
+ */
46
+ var ANIMATIONSTART_EVENTS = $.map(
47
+ ['animationstart', 'webkitAnimationStart', 'MSAnimationStart', 'oAnimationStart'],
48
+
49
+ function(eventName) {
50
+ return eventName + '.' + NAMESPACE;
51
+ }
52
+
53
+ ).join(' ');
54
+
55
+ /**
56
+ * Animationend event with vendor prefixes
57
+ * @private
58
+ * @const
59
+ * @type {String}
60
+ */
61
+ var ANIMATIONEND_EVENTS = $.map(
62
+ ['animationend', 'webkitAnimationEnd', 'MSAnimationEnd', 'oAnimationEnd'],
63
+
64
+ function(eventName) {
65
+ return eventName + '.' + NAMESPACE;
66
+ }
67
+
68
+ ).join(' ');
69
+
70
+ /**
71
+ * Default settings
72
+ * @private
73
+ * @const
74
+ * @type {Object}
75
+ */
76
+ var DEFAULTS = $.extend({
77
+ hashTracking: true,
78
+ closeOnConfirm: true,
79
+ closeOnCancel: true,
80
+ closeOnEscape: true,
81
+ closeOnOutsideClick: true,
82
+ modifier: '',
83
+ appendTo: null
84
+ }, global.REMODAL_GLOBALS && global.REMODAL_GLOBALS.DEFAULTS);
85
+
86
+ /**
87
+ * States of the Remodal
88
+ * @private
89
+ * @const
90
+ * @enum {String}
91
+ */
92
+ var STATES = {
93
+ CLOSING: 'closing',
94
+ CLOSED: 'closed',
95
+ OPENING: 'opening',
96
+ OPENED: 'opened'
97
+ };
98
+
99
+ /**
100
+ * Reasons of the state change.
101
+ * @private
102
+ * @const
103
+ * @enum {String}
104
+ */
105
+ var STATE_CHANGE_REASONS = {
106
+ CONFIRMATION: 'confirmation',
107
+ CANCELLATION: 'cancellation'
108
+ };
109
+
110
+ /**
111
+ * Is animation supported?
112
+ * @private
113
+ * @const
114
+ * @type {Boolean}
115
+ */
116
+ var IS_ANIMATION = (function() {
117
+ var style = document.createElement('div').style;
118
+
119
+ return style.animationName !== undefined ||
120
+ style.WebkitAnimationName !== undefined ||
121
+ style.MozAnimationName !== undefined ||
122
+ style.msAnimationName !== undefined ||
123
+ style.OAnimationName !== undefined;
124
+ })();
125
+
126
+ /**
127
+ * Is iOS?
128
+ * @private
129
+ * @const
130
+ * @type {Boolean}
131
+ */
132
+ var IS_IOS = /iPad|iPhone|iPod/.test(navigator.platform);
133
+
134
+ /**
135
+ * Current modal
136
+ * @private
137
+ * @type {Remodal}
138
+ */
139
+ var current;
140
+
141
+ /**
142
+ * Scrollbar position
143
+ * @private
144
+ * @type {Number}
145
+ */
146
+ var scrollTop;
147
+
148
+ /**
149
+ * Returns an animation duration
150
+ * @private
151
+ * @param {jQuery} $elem
152
+ * @returns {Number}
153
+ */
154
+ function getAnimationDuration($elem) {
155
+ if (
156
+ IS_ANIMATION &&
157
+ $elem.css('animation-name') === 'none' &&
158
+ $elem.css('-webkit-animation-name') === 'none' &&
159
+ $elem.css('-moz-animation-name') === 'none' &&
160
+ $elem.css('-o-animation-name') === 'none' &&
161
+ $elem.css('-ms-animation-name') === 'none'
162
+ ) {
163
+ return 0;
164
+ }
165
+
166
+ var duration = $elem.css('animation-duration') ||
167
+ $elem.css('-webkit-animation-duration') ||
168
+ $elem.css('-moz-animation-duration') ||
169
+ $elem.css('-o-animation-duration') ||
170
+ $elem.css('-ms-animation-duration') ||
171
+ '0s';
172
+
173
+ var delay = $elem.css('animation-delay') ||
174
+ $elem.css('-webkit-animation-delay') ||
175
+ $elem.css('-moz-animation-delay') ||
176
+ $elem.css('-o-animation-delay') ||
177
+ $elem.css('-ms-animation-delay') ||
178
+ '0s';
179
+
180
+ var iterationCount = $elem.css('animation-iteration-count') ||
181
+ $elem.css('-webkit-animation-iteration-count') ||
182
+ $elem.css('-moz-animation-iteration-count') ||
183
+ $elem.css('-o-animation-iteration-count') ||
184
+ $elem.css('-ms-animation-iteration-count') ||
185
+ '1';
186
+
187
+ var max;
188
+ var len;
189
+ var num;
190
+ var i;
191
+
192
+ duration = duration.split(', ');
193
+ delay = delay.split(', ');
194
+ iterationCount = iterationCount.split(', ');
195
+
196
+ // The 'duration' size is the same as the 'delay' size
197
+ for (i = 0, len = duration.length, max = Number.NEGATIVE_INFINITY; i < len; i++) {
198
+ num = parseFloat(duration[i]) * parseInt(iterationCount[i], 10) + parseFloat(delay[i]);
199
+
200
+ if (num > max) {
201
+ max = num;
202
+ }
203
+ }
204
+
205
+ return max;
206
+ }
207
+
208
+ /**
209
+ * Returns a scrollbar width
210
+ * @private
211
+ * @returns {Number}
212
+ */
213
+ function getScrollbarWidth() {
214
+ if ($(document.body).height() <= $(window).height()) {
215
+ return 0;
216
+ }
217
+
218
+ var outer = document.createElement('div');
219
+ var inner = document.createElement('div');
220
+ var widthNoScroll;
221
+ var widthWithScroll;
222
+
223
+ outer.style.visibility = 'hidden';
224
+ outer.style.width = '100px';
225
+ document.body.appendChild(outer);
226
+
227
+ widthNoScroll = outer.offsetWidth;
228
+
229
+ // Force scrollbars
230
+ outer.style.overflow = 'scroll';
231
+
232
+ // Add inner div
233
+ inner.style.width = '100%';
234
+ outer.appendChild(inner);
235
+
236
+ widthWithScroll = inner.offsetWidth;
237
+
238
+ // Remove divs
239
+ outer.parentNode.removeChild(outer);
240
+
241
+ return widthNoScroll - widthWithScroll;
242
+ }
243
+
244
+ /**
245
+ * Locks the screen
246
+ * @private
247
+ */
248
+ function lockScreen() {
249
+ if (IS_IOS) {
250
+ return;
251
+ }
252
+
253
+ var $html = $('html');
254
+ var lockedClass = namespacify('is-locked');
255
+ var paddingRight;
256
+ var $body;
257
+
258
+ if (!$html.hasClass(lockedClass)) {
259
+ $body = $(document.body);
260
+
261
+ // Zepto does not support '-=', '+=' in the `css` method
262
+ paddingRight = parseInt($body.css('padding-right'), 10) + getScrollbarWidth();
263
+
264
+ $body.css('padding-right', paddingRight + 'px');
265
+ $html.addClass(lockedClass);
266
+ }
267
+ }
268
+
269
+ /**
270
+ * Unlocks the screen
271
+ * @private
272
+ */
273
+ function unlockScreen() {
274
+ if (IS_IOS) {
275
+ return;
276
+ }
277
+
278
+ var $html = $('html');
279
+ var lockedClass = namespacify('is-locked');
280
+ var paddingRight;
281
+ var $body;
282
+
283
+ if ($html.hasClass(lockedClass)) {
284
+ $body = $(document.body);
285
+
286
+ // Zepto does not support '-=', '+=' in the `css` method
287
+ paddingRight = parseInt($body.css('padding-right'), 10) - getScrollbarWidth();
288
+
289
+ $body.css('padding-right', paddingRight + 'px');
290
+ $html.removeClass(lockedClass);
291
+ }
292
+ }
293
+
294
+ /**
295
+ * Sets a state for an instance
296
+ * @private
297
+ * @param {Remodal} instance
298
+ * @param {STATES} state
299
+ * @param {Boolean} isSilent If true, Remodal does not trigger events
300
+ * @param {String} Reason of a state change.
301
+ */
302
+ function setState(instance, state, isSilent, reason) {
303
+
304
+ var newState = namespacify('is', state);
305
+ var allStates = [namespacify('is', STATES.CLOSING),
306
+ namespacify('is', STATES.OPENING),
307
+ namespacify('is', STATES.CLOSED),
308
+ namespacify('is', STATES.OPENED)].join(' ');
309
+
310
+ instance.$bg
311
+ .removeClass(allStates)
312
+ .addClass(newState);
313
+
314
+ instance.$overlay
315
+ .removeClass(allStates)
316
+ .addClass(newState);
317
+
318
+ instance.$wrapper
319
+ .removeClass(allStates)
320
+ .addClass(newState);
321
+
322
+ instance.$modal
323
+ .removeClass(allStates)
324
+ .addClass(newState);
325
+
326
+ instance.state = state;
327
+ !isSilent && instance.$modal.trigger({
328
+ type: state,
329
+ reason: reason
330
+ }, [{ reason: reason }]);
331
+ }
332
+
333
+ /**
334
+ * Synchronizes with the animation
335
+ * @param {Function} doBeforeAnimation
336
+ * @param {Function} doAfterAnimation
337
+ * @param {Remodal} instance
338
+ */
339
+ function syncWithAnimation(doBeforeAnimation, doAfterAnimation, instance) {
340
+ var runningAnimationsCount = 0;
341
+
342
+ var handleAnimationStart = function(e) {
343
+ if (e.target !== this) {
344
+ return;
345
+ }
346
+
347
+ runningAnimationsCount++;
348
+ };
349
+
350
+ var handleAnimationEnd = function(e) {
351
+ if (e.target !== this) {
352
+ return;
353
+ }
354
+
355
+ if (--runningAnimationsCount === 0) {
356
+
357
+ // Remove event listeners
358
+ $.each(['$bg', '$overlay', '$wrapper', '$modal'], function(index, elemName) {
359
+ instance[elemName].off(ANIMATIONSTART_EVENTS + ' ' + ANIMATIONEND_EVENTS);
360
+ });
361
+
362
+ doAfterAnimation();
363
+ }
364
+ };
365
+
366
+ $.each(['$bg', '$overlay', '$wrapper', '$modal'], function(index, elemName) {
367
+ instance[elemName]
368
+ .on(ANIMATIONSTART_EVENTS, handleAnimationStart)
369
+ .on(ANIMATIONEND_EVENTS, handleAnimationEnd);
370
+ });
371
+
372
+ doBeforeAnimation();
373
+
374
+ // If the animation is not supported by a browser or its duration is 0
375
+ if (
376
+ getAnimationDuration(instance.$bg) === 0 &&
377
+ getAnimationDuration(instance.$overlay) === 0 &&
378
+ getAnimationDuration(instance.$wrapper) === 0 &&
379
+ getAnimationDuration(instance.$modal) === 0
380
+ ) {
381
+
382
+ // Remove event listeners
383
+ $.each(['$bg', '$overlay', '$wrapper', '$modal'], function(index, elemName) {
384
+ instance[elemName].off(ANIMATIONSTART_EVENTS + ' ' + ANIMATIONEND_EVENTS);
385
+ });
386
+
387
+ doAfterAnimation();
388
+ }
389
+ }
390
+
391
+ /**
392
+ * Closes immediately
393
+ * @private
394
+ * @param {Remodal} instance
395
+ */
396
+ function halt(instance) {
397
+ if (instance.state === STATES.CLOSED) {
398
+ return;
399
+ }
400
+
401
+ $.each(['$bg', '$overlay', '$wrapper', '$modal'], function(index, elemName) {
402
+ instance[elemName].off(ANIMATIONSTART_EVENTS + ' ' + ANIMATIONEND_EVENTS);
403
+ });
404
+
405
+ instance.$bg.removeClass(instance.settings.modifier);
406
+ instance.$overlay.removeClass(instance.settings.modifier).hide();
407
+ instance.$wrapper.hide();
408
+ unlockScreen();
409
+ setState(instance, STATES.CLOSED, true);
410
+ }
411
+
412
+ /**
413
+ * Parses a string with options
414
+ * @private
415
+ * @param str
416
+ * @returns {Object}
417
+ */
418
+ function parseOptions(str) {
419
+ var obj = {};
420
+ var arr;
421
+ var len;
422
+ var val;
423
+ var i;
424
+
425
+ // Remove spaces before and after delimiters
426
+ str = str.replace(/\s*:\s*/g, ':').replace(/\s*,\s*/g, ',');
427
+
428
+ // Parse a string
429
+ arr = str.split(',');
430
+ for (i = 0, len = arr.length; i < len; i++) {
431
+ arr[i] = arr[i].split(':');
432
+ val = arr[i][1];
433
+
434
+ // Convert a string value if it is like a boolean
435
+ if (typeof val === 'string' || val instanceof String) {
436
+ val = val === 'true' || (val === 'false' ? false : val);
437
+ }
438
+
439
+ // Convert a string value if it is like a number
440
+ if (typeof val === 'string' || val instanceof String) {
441
+ val = !isNaN(val) ? +val : val;
442
+ }
443
+
444
+ obj[arr[i][0]] = val;
445
+ }
446
+
447
+ return obj;
448
+ }
449
+
450
+ /**
451
+ * Generates a string separated by dashes and prefixed with NAMESPACE
452
+ * @private
453
+ * @param {...String}
454
+ * @returns {String}
455
+ */
456
+ function namespacify() {
457
+ var result = NAMESPACE;
458
+
459
+ for (var i = 0; i < arguments.length; ++i) {
460
+ result += '-' + arguments[i];
461
+ }
462
+
463
+ return result;
464
+ }
465
+
466
+ /**
467
+ * Handles the hashchange event
468
+ * @private
469
+ * @listens hashchange
470
+ */
471
+ function handleHashChangeEvent() {
472
+ var id = location.hash.replace('#', '');
473
+ var instance;
474
+ var $elem;
475
+
476
+ if (!id) {
477
+
478
+ // Check if we have currently opened modal and animation was completed
479
+ if (current && current.state === STATES.OPENED && current.settings.hashTracking) {
480
+ current.close();
481
+ }
482
+ } else {
483
+
484
+ // Catch syntax error if your hash is bad
485
+ try {
486
+ $elem = $(
487
+ '[data-' + PLUGIN_NAME + '-id="' + id + '"]'
488
+ );
489
+ } catch (err) {}
490
+
491
+ if ($elem && $elem.length) {
492
+ instance = $[PLUGIN_NAME].lookup[$elem.data(PLUGIN_NAME)];
493
+
494
+ if (instance && instance.settings.hashTracking) {
495
+ instance.open();
496
+ }
497
+ }
498
+
499
+ }
500
+ }
501
+
502
+ /**
503
+ * Remodal constructor
504
+ * @constructor
505
+ * @param {jQuery} $modal
506
+ * @param {Object} options
507
+ */
508
+ function Remodal($modal, options) {
509
+ var $body = $(document.body);
510
+ var $appendTo = $body;
511
+ var remodal = this;
512
+
513
+ remodal.settings = $.extend({}, DEFAULTS, options);
514
+ remodal.index = $[PLUGIN_NAME].lookup.push(remodal) - 1;
515
+ remodal.state = STATES.CLOSED;
516
+
517
+ remodal.$overlay = $('.' + namespacify('overlay'));
518
+
519
+ if (remodal.settings.appendTo !== null && remodal.settings.appendTo.length) {
520
+ $appendTo = $(remodal.settings.appendTo);
521
+ }
522
+
523
+ if (!remodal.$overlay.length) {
524
+ remodal.$overlay = $('<div>').addClass(namespacify('overlay') + ' ' + namespacify('is', STATES.CLOSED)).hide();
525
+ $appendTo.append(remodal.$overlay);
526
+ }
527
+
528
+ remodal.$bg = $('.' + namespacify('bg')).addClass(namespacify('is', STATES.CLOSED));
529
+
530
+ remodal.$modal = $modal
531
+ .addClass(
532
+ NAMESPACE + ' ' +
533
+ namespacify('is-initialized') + ' ' +
534
+ remodal.settings.modifier + ' ' +
535
+ namespacify('is', STATES.CLOSED))
536
+ .attr('tabindex', '-1');
537
+
538
+ remodal.$wrapper = $('<div>')
539
+ .addClass(
540
+ namespacify('wrapper') + ' ' +
541
+ remodal.settings.modifier + ' ' +
542
+ namespacify('is', STATES.CLOSED))
543
+ .hide()
544
+ .append(remodal.$modal);
545
+ $appendTo.append(remodal.$wrapper);
546
+
547
+ // Add the event listener for the close button
548
+ remodal.$wrapper.on('click.' + NAMESPACE, '[data-' + PLUGIN_NAME + '-action="close"]', function(e) {
549
+ e.preventDefault();
550
+
551
+ remodal.close();
552
+ });
553
+
554
+ // Add the event listener for the cancel button
555
+ remodal.$wrapper.on('click.' + NAMESPACE, '[data-' + PLUGIN_NAME + '-action="cancel"]', function(e) {
556
+ e.preventDefault();
557
+
558
+ remodal.$modal.trigger(STATE_CHANGE_REASONS.CANCELLATION);
559
+
560
+ if (remodal.settings.closeOnCancel) {
561
+ remodal.close(STATE_CHANGE_REASONS.CANCELLATION);
562
+ }
563
+ });
564
+
565
+ // Add the event listener for the confirm button
566
+ remodal.$wrapper.on('click.' + NAMESPACE, '[data-' + PLUGIN_NAME + '-action="confirm"]', function(e) {
567
+ e.preventDefault();
568
+
569
+ remodal.$modal.trigger(STATE_CHANGE_REASONS.CONFIRMATION);
570
+
571
+ if (remodal.settings.closeOnConfirm) {
572
+ remodal.close(STATE_CHANGE_REASONS.CONFIRMATION);
573
+ }
574
+ });
575
+
576
+ // Add the event listener for the overlay
577
+ remodal.$wrapper.on('click.' + NAMESPACE, function(e) {
578
+ var $target = $(e.target);
579
+
580
+ if (!$target.hasClass(namespacify('wrapper'))) {
581
+ return;
582
+ }
583
+
584
+ if (remodal.settings.closeOnOutsideClick) {
585
+ remodal.close();
586
+ }
587
+ });
588
+ }
589
+
590
+ /**
591
+ * Opens a modal window
592
+ * @public
593
+ */
594
+ Remodal.prototype.open = function() {
595
+ var remodal = this;
596
+ var id;
597
+
598
+ // Check if the animation was completed
599
+ if (remodal.state === STATES.OPENING || remodal.state === STATES.CLOSING) {
600
+ return;
601
+ }
602
+
603
+ id = remodal.$modal.attr('data-' + PLUGIN_NAME + '-id');
604
+
605
+ if (id && remodal.settings.hashTracking) {
606
+ scrollTop = $(window).scrollTop();
607
+ location.hash = id;
608
+ }
609
+
610
+ if (current && current !== remodal) {
611
+ halt(current);
612
+ }
613
+
614
+ current = remodal;
615
+ lockScreen();
616
+ remodal.$bg.addClass(remodal.settings.modifier);
617
+ remodal.$overlay.addClass(remodal.settings.modifier).show();
618
+ remodal.$wrapper.show().scrollTop(0);
619
+ remodal.$modal.focus();
620
+
621
+ syncWithAnimation(
622
+ function() {
623
+ setState(remodal, STATES.OPENING);
624
+ },
625
+
626
+ function() {
627
+ setState(remodal, STATES.OPENED);
628
+ },
629
+
630
+ remodal);
631
+ };
632
+
633
+ /**
634
+ * Closes a modal window
635
+ * @public
636
+ * @param {String} reason
637
+ */
638
+ Remodal.prototype.close = function(reason) {
639
+ var remodal = this;
640
+
641
+ // Check if the animation was completed
642
+ if (remodal.state === STATES.OPENING || remodal.state === STATES.CLOSING) {
643
+ return;
644
+ }
645
+
646
+ if (
647
+ remodal.settings.hashTracking &&
648
+ remodal.$modal.attr('data-' + PLUGIN_NAME + '-id') === location.hash.substr(1)
649
+ ) {
650
+ location.hash = '';
651
+ $(window).scrollTop(scrollTop);
652
+ }
653
+
654
+ syncWithAnimation(
655
+ function() {
656
+ setState(remodal, STATES.CLOSING, false, reason);
657
+ },
658
+
659
+ function() {
660
+ remodal.$bg.removeClass(remodal.settings.modifier);
661
+ remodal.$overlay.removeClass(remodal.settings.modifier).hide();
662
+ remodal.$wrapper.hide();
663
+ unlockScreen();
664
+
665
+ setState(remodal, STATES.CLOSED, false, reason);
666
+ },
667
+
668
+ remodal);
669
+ };
670
+
671
+ /**
672
+ * Returns a current state of a modal
673
+ * @public
674
+ * @returns {STATES}
675
+ */
676
+ Remodal.prototype.getState = function() {
677
+ return this.state;
678
+ };
679
+
680
+ /**
681
+ * Destroys a modal
682
+ * @public
683
+ */
684
+ Remodal.prototype.destroy = function() {
685
+ var lookup = $[PLUGIN_NAME].lookup;
686
+ var instanceCount;
687
+
688
+ halt(this);
689
+ this.$wrapper.remove();
690
+
691
+ delete lookup[this.index];
692
+ instanceCount = $.grep(lookup, function(instance) {
693
+ return !!instance;
694
+ }).length;
695
+
696
+ if (instanceCount === 0) {
697
+ this.$overlay.remove();
698
+ this.$bg.removeClass(
699
+ namespacify('is', STATES.CLOSING) + ' ' +
700
+ namespacify('is', STATES.OPENING) + ' ' +
701
+ namespacify('is', STATES.CLOSED) + ' ' +
702
+ namespacify('is', STATES.OPENED));
703
+ }
704
+ };
705
+
706
+ /**
707
+ * Special plugin object for instances
708
+ * @public
709
+ * @type {Object}
710
+ */
711
+ $[PLUGIN_NAME] = {
712
+ lookup: []
713
+ };
714
+
715
+ /**
716
+ * Plugin constructor
717
+ * @constructor
718
+ * @param {Object} options
719
+ * @returns {JQuery}
720
+ */
721
+ $.fn[PLUGIN_NAME] = function(opts) {
722
+ var instance;
723
+ var $elem;
724
+
725
+ this.each(function(index, elem) {
726
+ $elem = $(elem);
727
+
728
+ if ($elem.data(PLUGIN_NAME) == null) {
729
+ instance = new Remodal($elem, opts);
730
+ $elem.data(PLUGIN_NAME, instance.index);
731
+
732
+ if (
733
+ instance.settings.hashTracking &&
734
+ $elem.attr('data-' + PLUGIN_NAME + '-id') === location.hash.substr(1)
735
+ ) {
736
+ instance.open();
737
+ }
738
+ } else {
739
+ instance = $[PLUGIN_NAME].lookup[$elem.data(PLUGIN_NAME)];
740
+ }
741
+ });
742
+
743
+ return instance;
744
+ };
745
+
746
+ $(document).ready(function() {
747
+
748
+ // data-remodal-target opens a modal window with the special Id
749
+ $(document).on('click', '[data-' + PLUGIN_NAME + '-target]', function(e) {
750
+ e.preventDefault();
751
+
752
+ var elem = e.currentTarget;
753
+ var id = elem.getAttribute('data-' + PLUGIN_NAME + '-target');
754
+ var $target = $('[data-' + PLUGIN_NAME + '-id="' + id + '"]');
755
+
756
+ $[PLUGIN_NAME].lookup[$target.data(PLUGIN_NAME)].open();
757
+ });
758
+
759
+ // Auto initialization of modal windows
760
+ // They should have the 'remodal' class attribute
761
+ // Also you can write the `data-remodal-options` attribute to pass params into the modal
762
+ $(document).find('.' + NAMESPACE).each(function(i, container) {
763
+ var $container = $(container);
764
+ var options = $container.data(PLUGIN_NAME + '-options');
765
+
766
+ if (!options) {
767
+ options = {};
768
+ } else if (typeof options === 'string' || options instanceof String) {
769
+ options = parseOptions(options);
770
+ }
771
+
772
+ $container[PLUGIN_NAME](options);
773
+ });
774
+
775
+ // Handles the keydown event
776
+ $(document).on('keydown.' + NAMESPACE, function(e) {
777
+ if (current && current.settings.closeOnEscape && current.state === STATES.OPENED && e.keyCode === 27) {
778
+ current.close();
779
+ }
780
+ });
781
+
782
+ // Handles the hashchange event
783
+ $(window).on('hashchange.' + NAMESPACE, handleHashChangeEvent);
784
+ });
785
+ });