Project

General

Profile

1
// Native Javascript for Bootstrap 3 | Modal
2
// by dnp_theme
3

    
4
(function(factory){
5

    
6
  // CommonJS/RequireJS and "native" compatibility
7
  if(typeof module !== "undefined" && typeof exports == "object") {
8
    // A commonJS/RequireJS environment
9
    if(typeof window != "undefined") {
10
      // Window and document exist, so return the factory's return value.
11
      module.exports = factory();
12
    } else {
13
      // Let the user give the factory a Window and Document.
14
      module.exports = factory;
15
    }
16
  } else {
17
    // Assume a traditional browser.
18
    window.Modal = factory();
19
  }
20

    
21
})(function(){
22
  
23
  //MODAL DEFINITION
24
  var Modal = function(element, options) { // element is the trigger button / options.target is the modal
25
    options = options || {};
26
    this.isIE = (new RegExp("MSIE ([0-9]{1,}[\.0-9]{0,})").exec(navigator.userAgent) != null) ? parseFloat( RegExp.$1 ) : false; 
27
    this.modal = typeof element === 'object' ? element : document.querySelector(element);
28
    this.options = {};
29
    this.options.backdrop = options.backdrop === 'false' ? false : true;
30
    this.options.keyboard = options.keyboard === 'false' ? false : true;
31
    this.options.content = options.content;
32
    this.duration = options.duration || 300; // the default modal fade duration option
33
    this.options.duration = (this.isIE && this.isIE < 10) ? 0 : this.duration;
34

    
35
    this.scrollbarWidth    = 0;
36
    this.dialog = this.modal.querySelector('.modal-dialog');
37
    this.timer = 0;
38

    
39
    this.init();
40
  };
41
  
42
  var getWindowWidth = function() {
43
    var htmlRect = document.documentElement.getBoundingClientRect(), 
44
      fullWindowWidth = window.innerWidth || (htmlRect.right - Math.abs(htmlRect.left));
45
    return fullWindowWidth;
46
  };
47
  Modal.prototype = {
48
    
49
    init : function() {      
50
        
51
      this.actions();
52
      this.trigger();  
53
      if ( this.options.content && this.options.content !== undefined ) {        
54
        this.content( this.options.content );
55
      }
56
    },
57
    
58
    actions : function() {
59
      var self = this;
60
      this.open = function() {
61
        this._open();
62
      },
63
    
64
      this.close = function() {
65
        this._close();
66
      },
67
    
68
      this._open = function() {
69
        var currentOpen = document.querySelector('.modal.in');
70
        if (currentOpen){
71
            clearTimeout(currentOpen.getAttribute('data-timer'));
72
            this.removeClass(currentOpen,'in');
73
            setTimeout( function() {
74
              currentOpen.setAttribute('aria-hidden', true);
75
              currentOpen.style.display = '';
76
            }, self.options.duration/2);
77
        }
78
            
79
        if ( this.options.backdrop ) {
80
          this.createOverlay();
81
        } else { this.overlay = null }
82
        
83
        if ( this.overlay ) {
84
          setTimeout( function() {                                
85
            self.addClass(self.overlay,'in');
86
          }, 0);            
87
        }
88
                
89
        clearTimeout(self.modal.getAttribute('data-timer'));
90
        this.timer = setTimeout( function() {
91
          self.modal.style.display = 'block';
92
          
93
          self.checkScrollbar();
94
          self.adjustDialog();
95
          self.setScrollbar();
96
          
97
          self.resize();
98
          self.dismiss();
99
          self.keydown();      
100
          
101
          self.addClass(document.body,'modal-open');
102
          self.addClass(self.modal,'in');
103
          self.modal.setAttribute('aria-hidden', false);
104
        }, self.options.duration/2);
105
        this.modal.setAttribute('data-timer',self.timer);
106
      },
107
    
108
      this._close = function() {
109

    
110
        if ( this.overlay ) {          
111
          this.removeClass(this.overlay,'in');
112
        }      
113
        this.removeClass(this.modal,'in');
114
        this.modal.setAttribute('aria-hidden', true);
115
                
116
        clearTimeout(self.modal.getAttribute('data-timer'));
117
        this.timer = setTimeout( function() {
118
          self.removeClass(document.body,'modal-open');
119
          self.resize();
120
          self.resetAdjustments();
121
          self.resetScrollbar();
122
          
123
          self.dismiss();
124
          self.keydown();
125
          self.modal.style.display = '';
126
        }, self.options.duration/2);
127
        this.modal.setAttribute('data-timer',self.timer);
128
        
129
        setTimeout( function() {
130
          if (!document.querySelector('.modal.in')) {  self.removeOverlay(); }
131
        }, self.options.duration);
132
      },
133
    
134
      this.content = function( content ) {
135
        return this.modal.querySelector('.modal-content').innerHTML = content;
136
      },
137
    
138
      this.createOverlay = function() {
139
        var backdrop = document.createElement('div'), overlay = document.querySelector('.modal-backdrop');
140
        backdrop.setAttribute('class','modal-backdrop fade');
141
    
142
        if ( overlay ) {
143
          this.overlay = overlay;
144
        } else {
145
          this.overlay = backdrop;
146
          document.body.appendChild(backdrop);
147
        }
148
      },
149
    
150
      this.removeOverlay = function() {
151
        var overlay = document.querySelector('.modal-backdrop');
152
        if ( overlay !== null && overlay !== undefined ) {
153
          document.body.removeChild(overlay)
154
        }
155
      },
156
    
157
      this.keydown = function() {
158
        function keyHandler(e) {
159
          if (self.options.keyboard && e.which == 27) {
160
            self.close();
161
          }          
162
        }
163
        if (!/in/.test(this.modal.className)) {
164
          document.addEventListener('keydown', keyHandler, false);
165
        } else {
166
          document.removeEventListener('keydown', keyHandler, false);
167
        }  
168
      },
169
    
170
      this.trigger = function() {
171
        var triggers = document.querySelectorAll('[data-toggle="modal"]'), tgl = triggers.length, i = 0;
172
        for ( i;i<tgl;i++ ) {
173
          triggers[i].addEventListener('click', function(e) {
174
            var b = e.target,
175
            s = b.getAttribute('data-target') && b.getAttribute('data-target').replace('#','')
176
            || b.getAttribute('href') && b.getAttribute('href').replace('#','');
177
            if ( document.getElementById( s ) === self.modal ) {
178
              self.open()
179
            }
180
          })
181
        }
182
      },
183
    
184
      this._resize = function() {
185
        var overlay = this.overlay||document.querySelector('.modal-backdrop'),
186
          dim = { w: document.documentElement.clientWidth + 'px', h: document.documentElement.clientHeight + 'px' };
187
        // setTimeout(function() {
188
          if ( overlay !== null && /in/.test(overlay.className) ) {
189
            overlay.style.height = dim.h; overlay.style.width = dim.w;
190
          }
191
        // }, self.options.duration/2)
192
      },
193
      
194
      this.oneResize = function() {
195
        function oneResize() {
196
          self._resize();
197
          self.handleUpdate();
198
          window.removeEventListener('resize', oneResize, false);
199
        }
200
        window.addEventListener('resize', oneResize, false);      
201
      },
202
    
203
      this.resize = function() {
204
        function resizeHandler() {
205
          // setTimeout(function() {
206
            self._resize();
207
            self.handleUpdate();
208
            // console.log('offresize')
209
          // }, 100)
210
        }      
211

    
212
        if (!/in/.test(this.modal.className)) {
213
          window.addEventListener('resize', this.oneResize, false);
214
        } else {
215
          window.removeEventListener('resize', this.oneResize, false);
216
        }
217
          
218
      },
219
    
220
      this.dismiss = function() {
221
        function dismissHandler(e) {
222
          if ( e.target.parentNode.getAttribute('data-dismiss') === 'modal' || e.target.getAttribute('data-dismiss') === 'modal' || e.target === self.modal ) {
223
            e.preventDefault(); self.close()
224
          }
225
        }          
226
        if (!/in/.test(this.modal.className)) {
227
          this.modal.addEventListener('click', dismissHandler, false);
228
        } else {
229
          this.modal.removeEventListener('click', dismissHandler, false);
230
        }  
231
      },
232
    
233
      // these following methods are used to handle overflowing modals
234
      
235
      this.handleUpdate = function () {
236
        this.adjustDialog(); 
237
      },
238
      
239
      this.adjustDialog = function () {
240
        this.modal.style.paddingLeft = !this.bodyIsOverflowing && this.modalIsOverflowing ? this.scrollbarWidth + 'px' : '';
241
        this.modal.style.paddingRight = this.bodyIsOverflowing && !this.modalIsOverflowing ? this.scrollbarWidth + 'px' : '';
242
      },
243
      
244
      this.resetAdjustments = function () {
245
        this.modal.style.paddingLeft = '';
246
        this.modal.style.paddingRight = '';
247
      },
248
      
249
      this.checkScrollbar = function () {  
250
        this.bodyIsOverflowing = document.body.clientWidth < getWindowWidth();
251
        this.modalIsOverflowing = this.modal.scrollHeight > document.documentElement.clientHeight;
252
        this.scrollbarWidth = this.measureScrollbar();
253
      },
254
      
255
      this.setScrollbar = function () {
256
        var bodyStyle = window.getComputedStyle(document.body), bodyPad = parseInt((bodyStyle.paddingRight), 10);
257
        if (this.bodyIsOverflowing) { document.body.style.paddingRight = (bodyPad + this.scrollbarWidth) + 'px'; }
258
      },
259
      
260
      this.resetScrollbar = function () {
261
        document.body.style.paddingRight = '';
262
      },
263
      
264
      this.measureScrollbar = function () { // thx walsh
265
        var scrollDiv = document.createElement('div');
266
        scrollDiv.className = 'modal-scrollbar-measure';
267
        document.body.appendChild(scrollDiv);
268
        var scrollbarWidth = scrollDiv.offsetWidth - scrollDiv.clientWidth;
269
        document.body.removeChild(scrollDiv);
270
        return scrollbarWidth;
271
      },
272
      
273
      this.addClass = function(el,c) {  
274
        if (el.classList) { el.classList.add(c); } else { el.className += ' '+c; }
275
      },
276
      
277
      this.removeClass = function(el,c) {
278
        if (el.classList) { el.classList.remove(c); } else { el.className = el.className.replace(c,'').replace(/^\s+|\s+$/g,''); }
279
      }
280
    }
281
  };  
282
  
283
  // DATA API
284
  var Modals = document.querySelectorAll('.modal'), mdl = Modals.length, i = 0;
285
  for ( i;i<mdl;i++ ) {
286
    var modal = Modals[i], options = {};
287
    options.keyboard = modal.getAttribute('data-keyboard');
288
    options.backdrop = modal.getAttribute('data-backdrop');
289
    options.duration = modal.getAttribute('data-duration');
290
    new Modal(modal,options)
291
  }
292

    
293
  return Modal;
294

    
295
});
(9-9/17)