vendor: 9,586 bytes, lines 1-279
1// AMD support (Thanks to @FagnerMartinsBrack) 2;(function(factory) { 3 'use strict'; 4 5 if (typeof define === 'function' && define.amd) { 6 define(['jquery'], factory); 7 } else { 8 factory(jQuery); 9 } 10})(function($){ 11 'use strict'; 12 13 var instances = [], 14 matchers = [], 15 defaultOptions = { 16 precision: 100, // 0.1 seconds, used to update the DOM 17 elapse: false, 18 defer: false 19 }; 20 // Miliseconds 21 matchers.push(/^[0-9]*$/.source); 22 // Month/Day/Year [hours:minutes:seconds] 23 matchers.push(/([0-9]{1,2}\/){2}[0-9]{4}( [0-9]{1,2}(:[0-9]{2}){2})?/ 24 .source); 25 // Year/Day/Month [hours:minutes:seconds] and 26 // Year-Day-Month [hours:minutes:seconds] 27 matchers.push(/[0-9]{4}([\/\-][0-9]{1,2}){2}( [0-9]{1,2}(:[0-9]{2}){2})?/ 28 .source); 29 // Cast the matchers to a regular expression object 30 matchers = new RegExp(matchers.join('|')); 31 // Parse a Date formatted has String to a native object 32 function parseDateString(dateString) { 33 // Pass through when a native object is sent 34 if(dateString instanceof Date) { 35 return dateString; 36 } 37 // Caste string to date object 38 if(String(dateString).match(matchers)) { 39 // If looks like a milisecond value cast to number before 40 // final casting (Thanks to @msigley) 41 if(String(dateString).match(/^[0-9]*$/)) { 42 dateString = Number(dateString); 43 } 44 // Replace dashes to slashes 45 if(String(dateString).match(/\-/)) { 46 dateString = String(dateString).replace(/\-/g, '/'); 47 } 48 return new Date(dateString); 49 } else { 50 throw new Error('Couldn\'t cast `' + dateString + 51 '` to a date object.'); 52 } 53 } 54 // Map to convert from a directive to offset object property 55 var DIRECTIVE_KEY_MAP = { 56 'Y': 'years', 57 'm': 'months', 58 'n': 'daysToMonth', 59 'd': 'daysToWeek', 60 'w': 'weeks', 61 'W': 'weeksToMonth', 62 'H': 'hours', 63 'M': 'minutes', 64 'S': 'seconds', 65 'D': 'totalDays', 66 'I': 'totalHours', 67 'N': 'totalMinutes', 68 'T': 'totalSeconds' 69 }; 70 // Returns an escaped regexp from the string 71 function escapedRegExp(str) { 72 var sanitize = str.toString().replace(/([.?*+^$[\]\\(){}|-])/g, '\\$1'); 73 return new RegExp(sanitize); 74 } 75 // Time string formatter 76 function strftime(offsetObject) { 77 return function(format) { 78 var directives = format.match(/%(-|!)?[A-Z]{1}(:[^;]+;)?/gi); 79 if(directives) { 80 for(var i = 0, len = directives.length; i < len; ++i) { 81 var directive = directives[i] 82 .match(/%(-|!)?([a-zA-Z]{1})(:[^;]+;)?/), 83 regexp = escapedRegExp(directive[0]), 84 modifier = directive[1] || '', 85 plural = directive[3] || '', 86 value = null; 87 // Get the key 88 directive = directive[2]; 89 // Swap shot-versions directives 90 if(DIRECTIVE_KEY_MAP.hasOwnProperty(directive)) { 91 value = DIRECTIVE_KEY_MAP[directive]; 92 value = Number(offsetObject[value]); 93 } 94 if(value !== null) { 95 // Pluralize 96 if(modifier === '!') { 97 value = pluralize(plural, value); 98 } 99 // Add zero-padding 100 if(modifier === '') { 101 if(value < 10) { 102 value = '0' + value.toString(); 103 } 104 } 105 // Replace the directive 106 format = format.replace(regexp, value.toString()); 107 } 108 } 109 } 110 format = format.replace(/%%/, '%'); 111 return format; 112 }; 113 } 114 // Pluralize 115 function pluralize(format, count) { 116 var plural = 's', singular = ''; 117 if(format) { 118 format = format.replace(/(:|;|\s)/gi, '').split(/\,/); 119 if(format.length === 1) { 120 plural = format[0]; 121 } else { 122 singular = format[0]; 123 plural = format[1]; 124 } 125 } 126 // Fix #187 127 if(Math.abs(count) > 1) { 128 return plural; 129 } else { 130 return singular; 131 } 132 } 133 // The Final Countdown 134 var Countdown = function(el, finalDate, options) { 135 this.el = el; 136 this.$el = $(el); 137 this.interval = null; 138 this.offset = {}; 139 this.options = $.extend({}, defaultOptions); 140 // console.log(this.options); 141 // This helper variable is necessary to mimick the previous check for an 142 // event listener on this.$el. Because of the event loop there might not 143 // be a registered event listener during the first tick. In order to work 144 // as expected a second tick is necessary, so that the events can be fired 145 // and handled properly. 146 this.firstTick = true; 147 // Register this instance 148 this.instanceNumber = instances.length; 149 instances.push(this); 150 // Save the reference 151 this.$el.data('countdown-instance', this.instanceNumber); 152 // Handle options or callback 153 if (options) { 154 // Register the callbacks when supplied 155 if(typeof options === 'function') { 156 this.$el.on('update.countdown', options); 157 this.$el.on('stoped.countdown', options); 158 this.$el.on('finish.countdown', options); 159 } else { 160 this.options = $.extend({}, defaultOptions, options); 161 } 162 } 163 // Set the final date and start 164 this.setFinalDate(finalDate); 165 // Starts the countdown automatically unless it's defered, 166 // Issue #198 167 if (this.options.defer === false) { 168 this.start(); 169 } 170 }; 171 $.extend(Countdown.prototype, { 172 start: function() { 173 if(this.interval !== null) { 174 clearInterval(this.interval); 175 } 176 var self = this; 177 this.update(); 178 this.interval = setInterval(function() { 179 self.update.call(self); 180 }, this.options.precision); 181 }, 182 stop: function() { 183 clearInterval(this.interval); 184 this.interval = null; 185 this.dispatchEvent('stoped'); 186 }, 187 toggle: function() { 188 if (this.interval) { 189 this.stop(); 190 } else { 191 this.start(); 192 } 193 }, 194 pause: function() { 195 this.stop(); 196 }, 197 resume: function() { 198 this.start(); 199 }, 200 remove: function() { 201 this.stop.call(this); 202 instances[this.instanceNumber] = null; 203 // Reset the countdown instance under data attr (Thanks to @assiotis) 204 delete this.$el.data().countdownInstance; 205 }, 206 setFinalDate: function(value) { 207 this.finalDate = parseDateString(value); // Cast the given date 208 }, 209 update: function() { 210 // Stop if dom is not in the html (Thanks to @dleavitt) 211 if(this.$el.closest('html').length === 0) { 212 this.remove(); 213 return; 214 } 215 var now = new Date(), 216 newTotalSecsLeft; 217 // Create an offset date object 218 newTotalSecsLeft = this.finalDate.getTime() - now.getTime(); // Millisecs 219 // Calculate the remaining time 220 newTotalSecsLeft = Math.ceil(newTotalSecsLeft / 1000); // Secs 221 // If is not have to elapse set the finish 222 newTotalSecsLeft = !this.options.elapse && newTotalSecsLeft < 0 ? 0 : 223 Math.abs(newTotalSecsLeft); 224 // Do not proceed to calculation if the seconds have not changed or 225 // during the first tick 226 if (this.totalSecsLeft === newTotalSecsLeft || this.firstTick) { 227 this.firstTick = false; 228 return; 229 } else { 230 this.totalSecsLeft = newTotalSecsLeft; 231 } 232 // Check if the countdown has elapsed 233 this.elapsed = (now >= this.finalDate); 234 // Calculate the offsets 235 this.offset = { 236 seconds : this.totalSecsLeft % 60, 237 minutes : Math.floor(this.totalSecsLeft / 60) % 60, 238 hours : Math.floor(this.totalSecsLeft / 60 / 60) % 24, 239 days : Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, 240 daysToWeek : Math.floor(this.totalSecsLeft / 60 / 60 / 24) % 7, 241 daysToMonth : Math.floor(this.totalSecsLeft / 60 / 60 / 24 % 30.4368), 242 weeks : Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7), 243 weeksToMonth: Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 7) % 4, 244 months : Math.floor(this.totalSecsLeft / 60 / 60 / 24 / 30.4368), 245 years : Math.abs(this.finalDate.getFullYear()-now.getFullYear()), 246 totalDays : Math.floor(this.totalSecsLeft / 60 / 60 / 24), 247 totalHours : Math.floor(this.totalSecsLeft / 60 / 60), 248 totalMinutes: Math.floor(this.totalSecsLeft / 60), 249 totalSeconds: this.totalSecsLeft 250 }; 251 // Dispatch an event 252 if(!this.options.elapse && this.totalSecsLeft === 0) { 253 this.stop(); 254 this.dispatchEvent('finish'); 255 } else { 256 this.dispatchEvent('update'); 257 } 258 }, 259 dispatchEvent: function(eventName) { 260 var event = $.Event(eventName + '.countdown'); 261 event.finalDate = this.finalDate; 262 event.elapsed = this.elapsed; 263 event.offset = $.extend({}, this.offset); 264 event.strftime = strftime(this.offset); 265 this.$el.trigger(event); 266 } 267 }); 268 // Register the jQuery selector actions 269 $.fn.countdown = function() { 270 var argumentsArray = Array.prototype.slice.call(arguments, 0); 271 return this.each(function() { 272 // If no data was set, jQuery.data returns undefined 273 var instanceNumber = $(this).data('countdown-instance'); 274 // Verify if we already have a countdown for this node ... 275 // Fix issue #22 (Thanks to @romanbsd) 276 if (instanceNumber !== undefined) { 277 var instance = instances[instanceNumber], 278 method = argumentsArray[0]; 279 // If method exists in the prototype execute
280 if(Countdown.prototype.hasOwnProperty(method)) { 281 instance[method].apply(instance, argumentsArray.slice(1)); 282 // If method look like a date try to set a new final date 283 } else if(String(method).match(/^[$A-Z_][0-9A-Z_$]*$/i) === null) { 284 instance.setFinalDate.call(instance, method); 285 // Allow plugin to restart after finished 286 // Fix issue #38 (thanks to @yaoazhen) 287 instance.start(); 288 } else { 289 $.error('Method %s does not exist on jQuery.countdown' 290 .replace(/\%s/gi, method)); 291 } 292 } else { 293 // ... if not we create an instance 294 new Countdown(this, argumentsArray[0], argumentsArray[1]); 295 } 296 }); 297 }; 298});
Line numbers count LF bytes from the start of the resource, as the search results do. Vendor segments are library code the classifier recognised; they are stored but not indexed. Bytes are shown as Latin1 characters, one per byte.