Shortcodes by Angie Makes - Version 1.11

Version Description

Download this release

Release Info

Developer cbaldelomar
Plugin Icon wp plugin Shortcodes by Angie Makes
Version 1.11
Comparing to
See all releases

Code changes from version 1.10 to 1.11

README.md CHANGED
@@ -44,6 +44,13 @@ Use the shortcode manager in the TinyMCE text editor
44
 
45
  ## Changelog ##
46
 
 
 
 
 
 
 
 
47
  ### Version 1.10
48
 
49
  * Fixed style bug for testimonials
44
 
45
  ## Changelog ##
46
 
47
+ ### Version 1.11
48
+
49
+ * added countdown shortcode
50
+ * added link to testimonial author
51
+ * added support for buttons to be positioned left, right, or centered
52
+ * added type attribute to pricing box
53
+
54
  ### Version 1.10
55
 
56
  * Fixed style bug for testimonials
includes/css/style.css CHANGED
@@ -380,6 +380,29 @@
380
 
381
  .wc-shortcodes-button:active {}
382
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
383
  /* Secondary */
384
  .wc-shortcodes-button.wc-shortcodes-button-secondary:visited,
385
  .wc-shortcodes-button.wc-shortcodes-button-secondary {
@@ -950,3 +973,71 @@ pre.pre-wrap {
950
  .widget_wc_shortcodes_social_icons .wc-shortcodes-social-icons.wc-shortcodes-columns-1 li {
951
  width: 100%;
952
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
380
 
381
  .wc-shortcodes-button:active {}
382
 
383
+ .wc-shortcodes-button-left {
384
+ text-align: left;
385
+ margin-right: 0px;
386
+ margin-left: 0px;
387
+ }
388
+ .wc-shortcodes-button-center {
389
+ text-align: center;
390
+ margin-right: 0px;
391
+ margin-left: 0px;
392
+ }
393
+ .wc-shortcodes-button-center .wc-shortcodes-button {
394
+ margin-right: 0px;
395
+ margin-left: 0px;
396
+ }
397
+
398
+ .wc-shortcodes-button-right {
399
+ text-align: right;
400
+ }
401
+ .wc-shortcodes-button-right .wc-shortcodes-button {
402
+ margin-right: 0px;
403
+ margin-left: 10px;
404
+ }
405
+
406
  /* Secondary */
407
  .wc-shortcodes-button.wc-shortcodes-button-secondary:visited,
408
  .wc-shortcodes-button.wc-shortcodes-button-secondary {
973
  .widget_wc_shortcodes_social_icons .wc-shortcodes-social-icons.wc-shortcodes-columns-1 li {
974
  width: 100%;
975
  }
976
+
977
+
978
+ /**
979
+ * jQuery Countdown styles 1.6.3.
980
+ * ----------------------------------------------------------------------------
981
+ */
982
+ .wc-shortcodes-countdown.hasCountdown {
983
+ border: 1px solid #ccc;
984
+ background-color: #eee;
985
+ text-align: center;
986
+ margin-bottom: 20px;
987
+ padding-top: 10px;
988
+ padding-bottom: 10px;
989
+ }
990
+ .wc-shortcodes-countdown.countdown_rtl {
991
+ direction: rtl;
992
+ }
993
+ .wc-shortcodes-countdown.countdown_holding div {
994
+ color: #888;
995
+ }
996
+ .wc-shortcodes-countdown .countdown_row {
997
+ clear: both;
998
+ width: 100%;
999
+ padding: 0px 2px;
1000
+ text-align: center;
1001
+ }
1002
+ .wc-shortcodes-countdown .countdown_show1 .countdown_section {
1003
+ width: 98%;
1004
+ }
1005
+ .wc-shortcodes-countdown .countdown_show2 .countdown_section {
1006
+ width: 48%;
1007
+ }
1008
+ .wc-shortcodes-countdown .countdown_show3 .countdown_section {
1009
+ width: 32.5%;
1010
+ }
1011
+ .wc-shortcodes-countdown .countdown_show4 .countdown_section {
1012
+ width: 24.5%;
1013
+ }
1014
+ .wc-shortcodes-countdown .countdown_show5 .countdown_section {
1015
+ width: 19.5%;
1016
+ }
1017
+ .wc-shortcodes-countdown .countdown_show6 .countdown_section {
1018
+ width: 16.25%;
1019
+ }
1020
+ .wc-shortcodes-countdown .countdown_show7 .countdown_section {
1021
+ width: 14%;
1022
+ }
1023
+ .wc-shortcodes-countdown .countdown_section {
1024
+ display: inline-block;
1025
+ font-size: 80%;
1026
+ text-align: center;
1027
+ border-right: 1px solid #cccccc;
1028
+ border-left: 1px solid #eeeeee;
1029
+ }
1030
+ .wc-shortcodes-countdown .countdown_row *:last-child,
1031
+ .wc-shortcodes-countdown .countdown_row .countdown_section:last-child {
1032
+ border-right: 1px solid #eeeeee;
1033
+ }
1034
+ .wc-shortcodes-countdown .countdown_amount {
1035
+ font-size: 200%;
1036
+ }
1037
+ .wc-shortcodes-countdown .countdown_descr {
1038
+ display: block;
1039
+ width: 100%;
1040
+ }
1041
+ .wc-shortcodes-countdown .countdown_expired_message {
1042
+ font-size: 200%;
1043
+ }
includes/js/countdown.js ADDED
@@ -0,0 +1,27 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ ( function( $ ) {
2
+ "use strict";
3
+
4
+ $(document).ready(function() {
5
+
6
+ $('.wc-shortcodes-countdown').each( function() {
7
+ var $this, date, until, message, format;
8
+
9
+ $this = $(this);
10
+ date = $this.data('date');
11
+ message = $this.data('message');
12
+ format = $this.data('format');
13
+ date = new Date( date );
14
+
15
+ $this.countdown({
16
+ until: date,
17
+ format: format,
18
+ alwaysExpire: true,
19
+ onExpiry: function() {
20
+ var $this = $(this);
21
+ $this.html("<span class='countdown_expired_message'>"+message+"</span>");
22
+ }
23
+ });
24
+ });
25
+
26
+ });
27
+ } )( jQuery );
includes/js/jquery.countdown.js ADDED
@@ -0,0 +1,810 @@
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
+ /* http://keith-wood.name/countdown.html
2
+ Countdown for jQuery v1.6.3.
3
+ Written by Keith Wood (kbwood{at}iinet.com.au) January 2008.
4
+ Available under the MIT (https://github.com/jquery/jquery/blob/master/MIT-LICENSE.txt) license.
5
+ Please attribute the author if you use it. */
6
+
7
+ /* Display a countdown timer.
8
+ Attach it with options like:
9
+ $('div selector').countdown(
10
+ {until: new Date(2009, 1 - 1, 1, 0, 0, 0), onExpiry: happyNewYear}); */
11
+
12
+ (function($) { // Hide scope, no $ conflict
13
+
14
+ /* Countdown manager. */
15
+ function Countdown() {
16
+ this.regional = []; // Available regional settings, indexed by language code
17
+ this.regional[''] = { // Default regional settings
18
+ // The display texts for the counters
19
+ labels: ['Years', 'Months', 'Weeks', 'Days', 'Hours', 'Minutes', 'Seconds'],
20
+ // The display texts for the counters if only one
21
+ labels1: ['Year', 'Month', 'Week', 'Day', 'Hour', 'Minute', 'Second'],
22
+ compactLabels: ['y', 'm', 'w', 'd'], // The compact texts for the counters
23
+ whichLabels: null, // Function to determine which labels to use
24
+ digits: ['0', '1', '2', '3', '4', '5', '6', '7', '8', '9'], // The digits to display
25
+ timeSeparator: ':', // Separator for time periods
26
+ isRTL: false // True for right-to-left languages, false for left-to-right
27
+ };
28
+ this._defaults = {
29
+ until: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count down to
30
+ // or numeric for seconds offset, or string for unit offset(s):
31
+ // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
32
+ since: null, // new Date(year, mth - 1, day, hr, min, sec) - date/time to count up from
33
+ // or numeric for seconds offset, or string for unit offset(s):
34
+ // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
35
+ timezone: null, // The timezone (hours or minutes from GMT) for the target times,
36
+ // or null for client local
37
+ serverSync: null, // A function to retrieve the current server time for synchronisation
38
+ format: 'dHMS', // Format for display - upper case for always, lower case only if non-zero,
39
+ // 'Y' years, 'O' months, 'W' weeks, 'D' days, 'H' hours, 'M' minutes, 'S' seconds
40
+ layout: '', // Build your own layout for the countdown
41
+ compact: false, // True to display in a compact format, false for an expanded one
42
+ significant: 0, // The number of periods with values to show, zero for all
43
+ description: '', // The description displayed for the countdown
44
+ expiryUrl: '', // A URL to load upon expiry, replacing the current page
45
+ expiryText: '', // Text to display upon expiry, replacing the countdown
46
+ alwaysExpire: false, // True to trigger onExpiry even if never counted down
47
+ onExpiry: null, // Callback when the countdown expires -
48
+ // receives no parameters and 'this' is the containing division
49
+ onTick: null, // Callback when the countdown is updated -
50
+ // receives int[7] being the breakdown by period (based on format)
51
+ // and 'this' is the containing division
52
+ tickInterval: 1 // Interval (seconds) between onTick callbacks
53
+ };
54
+ $.extend(this._defaults, this.regional['']);
55
+ this._serverSyncs = [];
56
+ var now = (typeof Date.now == 'function' ? Date.now :
57
+ function() { return new Date().getTime(); });
58
+ var perfAvail = (window.performance && typeof window.performance.now == 'function');
59
+ // Shared timer for all countdowns
60
+ function timerCallBack(timestamp) {
61
+ var drawStart = (timestamp < 1e12 ? // New HTML5 high resolution timer
62
+ (perfAvail ? (performance.now() + performance.timing.navigationStart) : now()) :
63
+ // Integer milliseconds since unix epoch
64
+ timestamp || now());
65
+ if (drawStart - animationStartTime >= 1000) {
66
+ plugin._updateTargets();
67
+ animationStartTime = drawStart;
68
+ }
69
+ requestAnimationFrame(timerCallBack);
70
+ }
71
+ var requestAnimationFrame = window.requestAnimationFrame ||
72
+ window.webkitRequestAnimationFrame || window.mozRequestAnimationFrame ||
73
+ window.oRequestAnimationFrame || window.msRequestAnimationFrame || null;
74
+ // This is when we expect a fall-back to setInterval as it's much more fluid
75
+ var animationStartTime = 0;
76
+ if (!requestAnimationFrame || $.noRequestAnimationFrame) {
77
+ $.noRequestAnimationFrame = null;
78
+ setInterval(function() { plugin._updateTargets(); }, 980); // Fall back to good old setInterval
79
+ }
80
+ else {
81
+ animationStartTime = window.animationStartTime ||
82
+ window.webkitAnimationStartTime || window.mozAnimationStartTime ||
83
+ window.oAnimationStartTime || window.msAnimationStartTime || now();
84
+ requestAnimationFrame(timerCallBack);
85
+ }
86
+ }
87
+
88
+ var Y = 0; // Years
89
+ var O = 1; // Months
90
+ var W = 2; // Weeks
91
+ var D = 3; // Days
92
+ var H = 4; // Hours
93
+ var M = 5; // Minutes
94
+ var S = 6; // Seconds
95
+
96
+ $.extend(Countdown.prototype, {
97
+ /* Class name added to elements to indicate already configured with countdown. */
98
+ markerClassName: 'hasCountdown',
99
+ /* Name of the data property for instance settings. */
100
+ propertyName: 'countdown',
101
+
102
+ /* Class name for the right-to-left marker. */
103
+ _rtlClass: 'countdown_rtl',
104
+ /* Class name for the countdown section marker. */
105
+ _sectionClass: 'countdown_section',
106
+ /* Class name for the period amount marker. */
107
+ _amountClass: 'countdown_amount',
108
+ /* Class name for the countdown row marker. */
109
+ _rowClass: 'countdown_row',
110
+ /* Class name for the holding countdown marker. */
111
+ _holdingClass: 'countdown_holding',
112
+ /* Class name for the showing countdown marker. */
113
+ _showClass: 'countdown_show',
114
+ /* Class name for the description marker. */
115
+ _descrClass: 'countdown_descr',
116
+
117
+ /* List of currently active countdown targets. */
118
+ _timerTargets: [],
119
+
120
+ /* Override the default settings for all instances of the countdown widget.
121
+ @param options (object) the new settings to use as defaults */
122
+ setDefaults: function(options) {
123
+ this._resetExtraLabels(this._defaults, options);
124
+ $.extend(this._defaults, options || {});
125
+ },
126
+
127
+ /* Convert a date/time to UTC.
128
+ @param tz (number) the hour or minute offset from GMT, e.g. +9, -360
129
+ @param year (Date) the date/time in that timezone or
130
+ (number) the year in that timezone
131
+ @param month (number, optional) the month (0 - 11) (omit if year is a Date)
132
+ @param day (number, optional) the day (omit if year is a Date)
133
+ @param hours (number, optional) the hour (omit if year is a Date)
134
+ @param mins (number, optional) the minute (omit if year is a Date)
135
+ @param secs (number, optional) the second (omit if year is a Date)
136
+ @param ms (number, optional) the millisecond (omit if year is a Date)
137
+ @return (Date) the equivalent UTC date/time */
138
+ UTCDate: function(tz, year, month, day, hours, mins, secs, ms) {
139
+ if (typeof year == 'object' && year.constructor == Date) {
140
+ ms = year.getMilliseconds();
141
+ secs = year.getSeconds();
142
+ mins = year.getMinutes();
143
+ hours = year.getHours();
144
+ day = year.getDate();
145
+ month = year.getMonth();
146
+ year = year.getFullYear();
147
+ }
148
+ var d = new Date();
149
+ d.setUTCFullYear(year);
150
+ d.setUTCDate(1);
151
+ d.setUTCMonth(month || 0);
152
+ d.setUTCDate(day || 1);
153
+ d.setUTCHours(hours || 0);
154
+ d.setUTCMinutes((mins || 0) - (Math.abs(tz) < 30 ? tz * 60 : tz));
155
+ d.setUTCSeconds(secs || 0);
156
+ d.setUTCMilliseconds(ms || 0);
157
+ return d;
158
+ },
159
+
160
+ /* Convert a set of periods into seconds.
161
+ Averaged for months and years.
162
+ @param periods (number[7]) the periods per year/month/week/day/hour/minute/second
163
+ @return (number) the corresponding number of seconds */
164
+ periodsToSeconds: function(periods) {
165
+ return periods[0] * 31557600 + periods[1] * 2629800 + periods[2] * 604800 +
166
+ periods[3] * 86400 + periods[4] * 3600 + periods[5] * 60 + periods[6];
167
+ },
168
+
169
+ /* Attach the countdown widget to a div.
170
+ @param target (element) the containing division
171
+ @param options (object) the initial settings for the countdown */
172
+ _attachPlugin: function(target, options) {
173
+ target = $(target);
174
+ if (target.hasClass(this.markerClassName)) {
175
+ return;
176
+ }
177
+ var inst = {options: $.extend({}, this._defaults), _periods: [0, 0, 0, 0, 0, 0, 0]};
178
+ target.addClass(this.markerClassName).data(this.propertyName, inst);
179
+ this._optionPlugin(target, options);
180
+ },
181
+
182
+ /* Add a target to the list of active ones.
183
+ @param target (element) the countdown target */
184
+ _addTarget: function(target) {
185
+ if (!this._hasTarget(target)) {
186
+ this._timerTargets.push(target);
187
+ }
188
+ },
189
+
190
+ /* See if a target is in the list of active ones.
191
+ @param target (element) the countdown target
192
+ @return (boolean) true if present, false if not */
193
+ _hasTarget: function(target) {
194
+ return ($.inArray(target, this._timerTargets) > -1);
195
+ },
196
+
197
+ /* Remove a target from the list of active ones.
198
+ @param target (element) the countdown target */
199
+ _removeTarget: function(target) {
200
+ this._timerTargets = $.map(this._timerTargets,
201
+ function(value) { return (value == target ? null : value); }); // delete entry
202
+ },
203
+
204
+ /* Update each active timer target. */
205
+ _updateTargets: function() {
206
+ for (var i = this._timerTargets.length - 1; i >= 0; i--) {
207
+ this._updateCountdown(this._timerTargets[i]);
208
+ }
209
+ },
210
+
211
+ /* Reconfigure the settings for a countdown div.
212
+ @param target (element) the control to affect
213
+ @param options (object) the new options for this instance or
214
+ (string) an individual property name
215
+ @param value (any) the individual property value (omit if options
216
+ is an object or to retrieve the value of a setting)
217
+ @return (any) if retrieving a value */
218
+ _optionPlugin: function(target, options, value) {
219
+ target = $(target);
220
+ var inst = target.data(this.propertyName);
221
+ if (!options || (typeof options == 'string' && value == null)) { // Get option
222
+ var name = options;
223
+ options = (inst || {}).options;
224
+ return (options && name ? options[name] : options);
225
+ }
226
+
227
+ if (!target.hasClass(this.markerClassName)) {
228
+ return;
229
+ }
230
+ options = options || {};
231
+ if (typeof options == 'string') {
232
+ var name = options;
233
+ options = {};
234
+ options[name] = value;
235
+ }
236
+ if (options.layout) {
237
+ options.layout = options.layout.replace(/&lt;/g, '<').replace(/&gt;/g, '>');
238
+ }
239
+ this._resetExtraLabels(inst.options, options);
240
+ var timezoneChanged = (inst.options.timezone != options.timezone);
241
+ $.extend(inst.options, options);
242
+ this._adjustSettings(target, inst,
243
+ options.until != null || options.since != null || timezoneChanged);
244
+ var now = new Date();
245
+ if ((inst._since && inst._since < now) || (inst._until && inst._until > now)) {
246
+ this._addTarget(target[0]);
247
+ }
248
+ this._updateCountdown(target, inst);
249
+ },
250
+
251
+ /* Redisplay the countdown with an updated display.
252
+ @param target (jQuery) the containing division
253
+ @param inst (object) the current settings for this instance */
254
+ _updateCountdown: function(target, inst) {
255
+ var $target = $(target);
256
+ inst = inst || $target.data(this.propertyName);
257
+ if (!inst) {
258
+ return;
259
+ }
260
+ $target.html(this._generateHTML(inst)).toggleClass(this._rtlClass, inst.options.isRTL);
261
+ if ($.isFunction(inst.options.onTick)) {
262
+ var periods = inst._hold != 'lap' ? inst._periods :
263
+ this._calculatePeriods(inst, inst._show, inst.options.significant, new Date());
264
+ if (inst.options.tickInterval == 1 ||
265
+ this.periodsToSeconds(periods) % inst.options.tickInterval == 0) {
266
+ inst.options.onTick.apply(target, [periods]);
267
+ }
268
+ }
269
+ var expired = inst._hold != 'pause' &&
270
+ (inst._since ? inst._now.getTime() < inst._since.getTime() :
271
+ inst._now.getTime() >= inst._until.getTime());
272
+ if (expired && !inst._expiring) {
273
+ inst._expiring = true;
274
+ if (this._hasTarget(target) || inst.options.alwaysExpire) {
275
+ this._removeTarget(target);
276
+ if ($.isFunction(inst.options.onExpiry)) {
277
+ inst.options.onExpiry.apply(target, []);
278
+ }
279
+ if (inst.options.expiryText) {
280
+ var layout = inst.options.layout;
281
+ inst.options.layout = inst.options.expiryText;
282
+ this._updateCountdown(target, inst);
283
+ inst.options.layout = layout;
284
+ }
285
+ if (inst.options.expiryUrl) {
286
+ window.location = inst.options.expiryUrl;
287
+ }
288
+ }
289
+ inst._expiring = false;
290
+ }
291
+ else if (inst._hold == 'pause') {
292
+ this._removeTarget(target);
293
+ }
294
+ $target.data(this.propertyName, inst);
295
+ },
296
+
297
+ /* Reset any extra labelsn and compactLabelsn entries if changing labels.
298
+ @param base (object) the options to be updated
299
+ @param options (object) the new option values */
300
+ _resetExtraLabels: function(base, options) {
301
+ var changingLabels = false;
302
+ for (var n in options) {
303
+ if (n != 'whichLabels' && n.match(/[Ll]abels/)) {
304
+ changingLabels = true;
305
+ break;
306
+ }
307
+ }
308
+ if (changingLabels) {
309
+ for (var n in base) { // Remove custom numbered labels
310
+ if (n.match(/[Ll]abels[02-9]|compactLabels1/)) {
311
+ base[n] = null;
312
+ }
313
+ }
314
+ }
315
+ },
316
+
317
+ /* Calculate interal settings for an instance.
318
+ @param target (element) the containing division
319
+ @param inst (object) the current settings for this instance
320
+ @param recalc (boolean) true if until or since are set */
321
+ _adjustSettings: function(target, inst, recalc) {
322
+ var now;
323
+ var serverOffset = 0;
324
+ var serverEntry = null;
325
+ for (var i = 0; i < this._serverSyncs.length; i++) {
326
+ if (this._serverSyncs[i][0] == inst.options.serverSync) {
327
+ serverEntry = this._serverSyncs[i][1];
328
+ break;
329
+ }
330
+ }
331
+ if (serverEntry != null) {
332
+ serverOffset = (inst.options.serverSync ? serverEntry : 0);
333
+ now = new Date();
334
+ }
335
+ else {
336
+ var serverResult = ($.isFunction(inst.options.serverSync) ?
337
+ inst.options.serverSync.apply(target, []) : null);
338
+ now = new Date();
339
+ serverOffset = (serverResult ? now.getTime() - serverResult.getTime() : 0);
340
+ this._serverSyncs.push([inst.options.serverSync, serverOffset]);
341
+ }
342
+ var timezone = inst.options.timezone;
343
+ timezone = (timezone == null ? -now.getTimezoneOffset() : timezone);
344
+ if (recalc || (!recalc && inst._until == null && inst._since == null)) {
345
+ inst._since = inst.options.since;
346
+ if (inst._since != null) {
347
+ inst._since = this.UTCDate(timezone, this._determineTime(inst._since, null));
348
+ if (inst._since && serverOffset) {
349
+ inst._since.setMilliseconds(inst._since.getMilliseconds() + serverOffset);
350
+ }
351
+ }
352
+ inst._until = this.UTCDate(timezone, this._determineTime(inst.options.until, now));
353
+ if (serverOffset) {
354
+ inst._until.setMilliseconds(inst._until.getMilliseconds() + serverOffset);
355
+ }
356
+ }
357
+ inst._show = this._determineShow(inst);
358
+ },
359
+
360
+ /* Remove the countdown widget from a div.
361
+ @param target (element) the containing division */
362
+ _destroyPlugin: function(target) {
363
+ target = $(target);
364
+ if (!target.hasClass(this.markerClassName)) {
365
+ return;
366
+ }
367
+ this._removeTarget(target[0]);
368
+ target.removeClass(this.markerClassName).empty().removeData(this.propertyName);
369
+ },
370
+
371
+ /* Pause a countdown widget at the current time.
372
+ Stop it running but remember and display the current time.
373
+ @param target (element) the containing division */
374
+ _pausePlugin: function(target) {
375
+ this._hold(target, 'pause');
376
+ },
377
+
378
+ /* Pause a countdown widget at the current time.
379
+ Stop the display but keep the countdown running.
380
+ @param target (element) the containing division */
381
+ _lapPlugin: function(target) {
382
+ this._hold(target, 'lap');
383
+ },
384
+
385
+ /* Resume a paused countdown widget.
386
+ @param target (element) the containing division */
387
+ _resumePlugin: function(target) {
388
+ this._hold(target, null);
389
+ },
390
+
391
+ /* Pause or resume a countdown widget.
392
+ @param target (element) the containing division
393
+ @param hold (string) the new hold setting */
394
+ _hold: function(target, hold) {
395
+ var inst = $.data(target, this.propertyName);
396
+ if (inst) {
397
+ if (inst._hold == 'pause' && !hold) {
398
+ inst._periods = inst._savePeriods;
399
+ var sign = (inst._since ? '-' : '+');
400
+ inst[inst._since ? '_since' : '_until'] =
401
+ this._determineTime(sign + inst._periods[0] + 'y' +
402
+ sign + inst._periods[1] + 'o' + sign + inst._periods[2] + 'w' +
403
+ sign + inst._periods[3] + 'd' + sign + inst._periods[4] + 'h' +
404
+ sign + inst._periods[5] + 'm' + sign + inst._periods[6] + 's');
405
+ this._addTarget(target);
406
+ }
407
+ inst._hold = hold;
408
+ inst._savePeriods = (hold == 'pause' ? inst._periods : null);
409
+ $.data(target, this.propertyName, inst);
410
+ this._updateCountdown(target, inst);
411
+ }
412
+ },
413
+
414
+ /* Return the current time periods.
415
+ @param target (element) the containing division
416
+ @return (number[7]) the current periods for the countdown */
417
+ _getTimesPlugin: function(target) {
418
+ var inst = $.data(target, this.propertyName);
419
+ return (!inst ? null : (inst._hold == 'pause' ? inst._savePeriods : (!inst._hold ? inst._periods :
420
+ this._calculatePeriods(inst, inst._show, inst.options.significant, new Date()))));
421
+ },
422
+
423
+ /* A time may be specified as an exact value or a relative one.
424
+ @param setting (string or number or Date) - the date/time value
425
+ as a relative or absolute value
426
+ @param defaultTime (Date) the date/time to use if no other is supplied
427
+ @return (Date) the corresponding date/time */
428
+ _determineTime: function(setting, defaultTime) {
429
+ var offsetNumeric = function(offset) { // e.g. +300, -2
430
+ var time = new Date();
431
+ time.setTime(time.getTime() + offset * 1000);
432
+ return time;
433
+ };
434
+ var offsetString = function(offset) { // e.g. '+2d', '-4w', '+3h +30m'
435
+ offset = offset.toLowerCase();
436
+ var time = new Date();
437
+ var year = time.getFullYear();
438
+ var month = time.getMonth();
439
+ var day = time.getDate();
440
+ var hour = time.getHours();
441
+ var minute = time.getMinutes();
442
+ var second = time.getSeconds();
443
+ var pattern = /([+-]?[0-9]+)\s*(s|m|h|d|w|o|y)?/g;
444
+ var matches = pattern.exec(offset);
445
+ while (matches) {
446
+ switch (matches[2] || 's') {
447
+ case 's': second += parseInt(matches[1], 10); break;
448
+ case 'm': minute += parseInt(matches[1], 10); break;
449
+ case 'h': hour += parseInt(matches[1], 10); break;
450
+ case 'd': day += parseInt(matches[1], 10); break;
451
+ case 'w': day += parseInt(matches[1], 10) * 7; break;
452
+ case 'o':
453
+ month += parseInt(matches[1], 10);
454
+ day = Math.min(day, plugin._getDaysInMonth(year, month));
455
+ break;
456
+ case 'y':
457
+ year += parseInt(matches[1], 10);
458
+ day = Math.min(day, plugin._getDaysInMonth(year, month));
459
+ break;
460
+ }
461
+ matches = pattern.exec(offset);
462
+ }
463
+ return new Date(year, month, day, hour, minute, second, 0);
464
+ };
465
+ var time = (setting == null ? defaultTime :
466
+ (typeof setting == 'string' ? offsetString(setting) :
467
+ (typeof setting == 'number' ? offsetNumeric(setting) : setting)));
468
+ if (time) time.setMilliseconds(0);
469
+ return time;
470
+ },
471
+
472
+ /* Determine the number of days in a month.
473
+ @param year (number) the year
474
+ @param month (number) the month
475
+ @return (number) the days in that month */
476
+ _getDaysInMonth: function(year, month) {
477
+ return 32 - new Date(year, month, 32).getDate();
478
+ },
479
+
480
+ /* Determine which set of labels should be used for an amount.
481
+ @param num (number) the amount to be displayed
482
+ @return (number) the set of labels to be used for this amount */
483
+ _normalLabels: function(num) {
484
+ return num;
485
+ },
486
+
487
+ /* Generate the HTML to display the countdown widget.
488
+ @param inst (object) the current settings for this instance
489
+ @return (string) the new HTML for the countdown display */
490
+ _generateHTML: function(inst) {
491
+ var self = this;
492
+ // Determine what to show
493
+ inst._periods = (inst._hold ? inst._periods :
494
+ this._calculatePeriods(inst, inst._show, inst.options.significant, new Date()));
495
+ // Show all 'asNeeded' after first non-zero value
496
+ var shownNonZero = false;
497
+ var showCount = 0;
498
+ var sigCount = inst.options.significant;
499
+ var show = $.extend({}, inst._show);
500
+ for (var period = Y; period <= S; period++) {
501
+ shownNonZero |= (inst._show[period] == '?' && inst._periods[period] > 0);
502
+ show[period] = (inst._show[period] == '?' && !shownNonZero ? null : inst._show[period]);
503
+ showCount += (show[period] ? 1 : 0);
504
+ sigCount -= (inst._periods[period] > 0 ? 1 : 0);
505
+ }
506
+ var showSignificant = [false, false, false, false, false, false, false];
507
+ for (var period = S; period >= Y; period--) { // Determine significant periods
508
+ if (inst._show[period]) {
509
+ if (inst._periods[period]) {
510
+ showSignificant[period] = true;
511
+ }
512
+ else {
513
+ showSignificant[period] = sigCount > 0;
514
+ sigCount--;
515
+ }
516
+ }
517
+ }
518
+ var labels = (inst.options.compact ? inst.options.compactLabels : inst.options.labels);
519
+ var whichLabels = inst.options.whichLabels || this._normalLabels;
520
+ var showCompact = function(period) {
521
+ var labelsNum = inst.options['compactLabels' + whichLabels(inst._periods[period])];
522
+ return (show[period] ? self._translateDigits(inst, inst._periods[period]) +
523
+ (labelsNum ? labelsNum[period] : labels[period]) + ' ' : '');
524
+ };
525
+ var showFull = function(period) {
526
+ var labelsNum = inst.options['labels' + whichLabels(inst._periods[period])];
527
+ return ((!inst.options.significant && show[period]) ||
528
+ (inst.options.significant && showSignificant[period]) ?
529
+ '<div class="' + plugin._sectionClass + '">' +
530
+ '<div class="' + plugin._amountClass + '">' +
531
+ self._translateDigits(inst, inst._periods[period]) + '</div>' +
532
+ (labelsNum ? labelsNum[period] : labels[period]) + '</div>' : '');
533
+ };
534
+ return (inst.options.layout ? this._buildLayout(inst, show, inst.options.layout,
535
+ inst.options.compact, inst.options.significant, showSignificant) :
536
+ ((inst.options.compact ? // Compact version
537
+ '<div class="' + this._rowClass + ' ' + this._amountClass +
538
+ (inst._hold ? ' ' + this._holdingClass : '') + '">' +
539
+ showCompact(Y) + showCompact(O) + showCompact(W) + showCompact(D) +
540
+ (show[H] ? this._minDigits(inst, inst._periods[H], 2) : '') +
541
+ (show[M] ? (show[H] ? inst.options.timeSeparator : '') +
542
+ this._minDigits(inst, inst._periods[M], 2) : '') +
543
+ (show[S] ? (show[H] || show[M] ? inst.options.timeSeparator : '') +
544
+ this._minDigits(inst, inst._periods[S], 2) : '') :
545
+ // Full version
546
+ '<div class="' + this._rowClass + ' ' + this._showClass + (inst.options.significant || showCount) +
547
+ (inst._hold ? ' ' + this._holdingClass : '') + '">' +
548
+ showFull(Y) + showFull(O) + showFull(W) + showFull(D) +
549
+ showFull(H) + showFull(M) + showFull(S)) + '</div>' +
550
+ (inst.options.description ? '<div class="' + this._rowClass + ' ' + this._descrClass + '">' +
551
+ inst.options.description + '</div>' : '')));
552
+ },
553
+
554
+ /* Construct a custom layout.
555
+ @param inst (object) the current settings for this instance
556
+ @param show (string[7]) flags indicating which periods are requested
557
+ @param layout (string) the customised layout
558
+ @param compact (boolean) true if using compact labels
559
+ @param significant (number) the number of periods with values to show, zero for all
560
+ @param showSignificant (boolean[7]) other periods to show for significance
561
+ @return (string) the custom HTML */
562
+ _buildLayout: function(inst, show, layout, compact, significant, showSignificant) {
563
+ var labels = inst.options[compact ? 'compactLabels' : 'labels'];
564
+ var whichLabels = inst.options.whichLabels || this._normalLabels;
565
+ var labelFor = function(index) {
566
+ return (inst.options[(compact ? 'compactLabels' : 'labels') +
567
+ whichLabels(inst._periods[index])] || labels)[index];
568
+ };
569
+ var digit = function(value, position) {
570
+ return inst.options.digits[Math.floor(value / position) % 10];
571
+ };
572
+ var subs = {desc: inst.options.description, sep: inst.options.timeSeparator,
573
+ yl: labelFor(Y), yn: this._minDigits(inst, inst._periods[Y], 1),
574
+ ynn: this._minDigits(inst, inst._periods[Y], 2),
575
+ ynnn: this._minDigits(inst, inst._periods[Y], 3), y1: digit(inst._periods[Y], 1),
576
+ y10: digit(inst._periods[Y], 10), y100: digit(inst._periods[Y], 100),
577
+ y1000: digit(inst._periods[Y], 1000),
578
+ ol: labelFor(O), on: this._minDigits(inst, inst._periods[O], 1),
579
+ onn: this._minDigits(inst, inst._periods[O], 2),
580
+ onnn: this._minDigits(inst, inst._periods[O], 3), o1: digit(inst._periods[O], 1),
581
+ o10: digit(inst._periods[O], 10), o100: digit(inst._periods[O], 100),
582
+ o1000: digit(inst._periods[O], 1000),
583
+ wl: labelFor(W), wn: this._minDigits(inst, inst._periods[W], 1),
584
+ wnn: this._minDigits(inst, inst._periods[W], 2),
585
+ wnnn: this._minDigits(inst, inst._periods[W], 3), w1: digit(inst._periods[W], 1),
586
+ w10: digit(inst._periods[W], 10), w100: digit(inst._periods[W], 100),
587
+ w1000: digit(inst._periods[W], 1000),
588
+ dl: labelFor(D), dn: this._minDigits(inst, inst._periods[D], 1),
589
+ dnn: this._minDigits(inst, inst._periods[D], 2),
590
+ dnnn: this._minDigits(inst, inst._periods[D], 3), d1: digit(inst._periods[D], 1),
591
+ d10: digit(inst._periods[D], 10), d100: digit(inst._periods[D], 100),
592
+ d1000: digit(inst._periods[D], 1000),
593
+ hl: labelFor(H), hn: this._minDigits(inst, inst._periods[H], 1),
594
+ hnn: this._minDigits(inst, inst._periods[H], 2),
595
+ hnnn: this._minDigits(inst, inst._periods[H], 3), h1: digit(inst._periods[H], 1),
596
+ h10: digit(inst._periods[H], 10), h100: digit(inst._periods[H], 100),
597
+ h1000: digit(inst._periods[H], 1000),
598
+ ml: labelFor(M), mn: this._minDigits(inst, inst._periods[M], 1),
599
+ mnn: this._minDigits(inst, inst._periods[M], 2),
600
+ mnnn: this._minDigits(inst, inst._periods[M], 3), m1: digit(inst._periods[M], 1),
601
+ m10: digit(inst._periods[M], 10), m100: digit(inst._periods[M], 100),
602
+ m1000: digit(inst._periods[M], 1000),
603
+ sl: labelFor(S), sn: this._minDigits(inst, inst._periods[S], 1),
604
+ snn: this._minDigits(inst, inst._periods[S], 2),
605
+ snnn: this._minDigits(inst, inst._periods[S], 3), s1: digit(inst._periods[S], 1),
606
+ s10: digit(inst._periods[S], 10), s100: digit(inst._periods[S], 100),
607
+ s1000: digit(inst._periods[S], 1000)};
608
+ var html = layout;
609
+ // Replace period containers: {p<}...{p>}
610
+ for (var i = Y; i <= S; i++) {
611
+ var period = 'yowdhms'.charAt(i);
612
+ var re = new RegExp('\\{' + period + '<\\}([\\s\\S]*)\\{' + period + '>\\}', 'g');
613
+ html = html.replace(re, ((!significant && show[i]) ||
614
+ (significant && showSignificant[i]) ? '$1' : ''));
615
+ }
616
+ // Replace period values: {pn}
617
+ $.each(subs, function(n, v) {
618
+ var re = new RegExp('\\{' + n + '\\}', 'g');
619
+ html = html.replace(re, v);
620
+ });
621
+ return html;
622
+ },
623
+
624
+ /* Ensure a numeric value has at least n digits for display.
625
+ @param inst (object) the current settings for this instance
626
+ @param value (number) the value to display
627
+ @param len (number) the minimum length
628
+ @return (string) the display text */
629
+ _minDigits: function(inst, value, len) {
630
+ value = '' + value;
631
+ if (value.length >= len) {
632
+ return this._translateDigits(inst, value);
633
+ }
634
+ value = '0000000000' + value;
635
+ return this._translateDigits(inst, value.substr(value.length - len));
636
+ },
637
+
638
+ /* Translate digits into other representations.
639
+ @param inst (object) the current settings for this instance
640
+ @param value (string) the text to translate
641
+ @return (string) the translated text */
642
+ _translateDigits: function(inst, value) {
643
+ return ('' + value).replace(/[0-9]/g, function(digit) {
644
+ return inst.options.digits[digit];
645
+ });
646
+ },
647
+
648
+ /* Translate the format into flags for each period.
649
+ @param inst (object) the current settings for this instance
650
+ @return (string[7]) flags indicating which periods are requested (?) or
651
+ required (!) by year, month, week, day, hour, minute, second */
652
+ _determineShow: function(inst) {
653
+ var format = inst.options.format;
654
+ var show = [];
655
+ show[Y] = (format.match('y') ? '?' : (format.match('Y') ? '!' : null));
656
+ show[O] = (format.match('o') ? '?' : (format.match('O') ? '!' : null));
657
+ show[W] = (format.match('w') ? '?' : (format.match('W') ? '!' : null));
658
+ show[D] = (format.match('d') ? '?' : (format.match('D') ? '!' : null));
659
+ show[H] = (format.match('h') ? '?' : (format.match('H') ? '!' : null));
660
+ show[M] = (format.match('m') ? '?' : (format.match('M') ? '!' : null));
661
+ show[S] = (format.match('s') ? '?' : (format.match('S') ? '!' : null));
662
+ return show;
663
+ },
664
+
665
+ /* Calculate the requested periods between now and the target time.
666
+ @param inst (object) the current settings for this instance
667
+ @param show (string[7]) flags indicating which periods are requested/required
668
+ @param significant (number) the number of periods with values to show, zero for all
669
+ @param now (Date) the current date and time
670
+ @return (number[7]) the current time periods (always positive)
671
+ by year, month, week, day, hour, minute, second */
672
+ _calculatePeriods: function(inst, show, significant, now) {
673
+ // Find endpoints
674
+ inst._now = now;
675
+ inst._now.setMilliseconds(0);
676
+ var until = new Date(inst._now.getTime());
677
+ if (inst._since) {
678
+ if (now.getTime() < inst._since.getTime()) {
679
+ inst._now = now = until;
680
+ }
681
+ else {
682
+ now = inst._since;
683
+ }
684
+ }
685
+ else {
686
+ until.setTime(inst._until.getTime());
687
+ if (now.getTime() > inst._until.getTime()) {
688
+ inst._now = now = until;
689
+ }
690
+ }
691
+ // Calculate differences by period
692
+ var periods = [0, 0, 0, 0, 0, 0, 0];
693
+ if (show[Y] || show[O]) {
694
+ // Treat end of months as the same
695
+ var lastNow = plugin._getDaysInMonth(now.getFullYear(), now.getMonth());
696
+ var lastUntil = plugin._getDaysInMonth(until.getFullYear(), until.getMonth());
697
+ var sameDay = (until.getDate() == now.getDate() ||
698
+ (until.getDate() >= Math.min(lastNow, lastUntil) &&
699
+ now.getDate() >= Math.min(lastNow, lastUntil)));
700
+ var getSecs = function(date) {
701
+ return (date.getHours() * 60 + date.getMinutes()) * 60 + date.getSeconds();
702
+ };
703
+ var months = Math.max(0,
704
+ (until.getFullYear() - now.getFullYear()) * 12 + until.getMonth() - now.getMonth() +
705
+ ((until.getDate() < now.getDate() && !sameDay) ||
706
+ (sameDay && getSecs(until) < getSecs(now)) ? -1 : 0));
707
+ periods[Y] = (show[Y] ? Math.floor(months / 12) : 0);
708
+ periods[O] = (show[O] ? months - periods[Y] * 12 : 0);
709
+ // Adjust for months difference and end of month if necessary
710
+ now = new Date(now.getTime());
711
+ var wasLastDay = (now.getDate() == lastNow);
712
+ var lastDay = plugin._getDaysInMonth(now.getFullYear() + periods[Y],
713
+ now.getMonth() + periods[O]);
714
+ if (now.getDate() > lastDay) {
715
+ now.setDate(lastDay);
716
+ }
717
+ now.setFullYear(now.getFullYear() + periods[Y]);
718
+ now.setMonth(now.getMonth() + periods[O]);
719
+ if (wasLastDay) {
720
+ now.setDate(lastDay);
721
+ }
722
+ }
723
+ var diff = Math.floor((until.getTime() - now.getTime()) / 1000);
724
+ var extractPeriod = function(period, numSecs) {
725
+ periods[period] = (show[period] ? Math.floor(diff / numSecs) : 0);
726
+ diff -= periods[period] * numSecs;
727
+ };
728
+ extractPeriod(W, 604800);
729
+ extractPeriod(D, 86400);
730
+ extractPeriod(H, 3600);
731
+ extractPeriod(M, 60);
732
+ extractPeriod(S, 1);
733
+ if (diff > 0 && !inst._since) { // Round up if left overs
734
+ var multiplier = [1, 12, 4.3482, 7, 24, 60, 60];
735
+ var lastShown = S;
736
+ var max = 1;
737
+ for (var period = S; period >= Y; period--) {
738
+ if (show[period]) {
739
+ if (periods[lastShown] >= max) {
740
+ periods[lastShown] = 0;
741
+ diff = 1;
742
+ }
743
+ if (diff > 0) {
744
+ periods[period]++;
745
+ diff = 0;
746
+ lastShown = period;
747
+ max = 1;
748
+ }
749
+ }
750
+ max *= multiplier[period];
751
+ }
752
+ }
753
+ if (significant) { // Zero out insignificant periods
754
+ for (var period = Y; period <= S; period++) {
755
+ if (significant && periods[period]) {
756
+ significant--;
757
+ }
758
+ else if (!significant) {
759
+ periods[period] = 0;
760
+ }
761
+ }
762
+ }
763
+ return periods;
764
+ }
765
+ });
766
+
767
+ // The list of commands that return values and don't permit chaining
768
+ var getters = ['getTimes'];
769
+
770
+ /* Determine whether a command is a getter and doesn't permit chaining.
771
+ @param command (string, optional) the command to run
772
+ @param otherArgs ([], optional) any other arguments for the command
773
+ @return true if the command is a getter, false if not */
774
+ function isNotChained(command, otherArgs) {
775
+ if (command == 'option' && (otherArgs.length == 0 ||
776
+ (otherArgs.length == 1 && typeof otherArgs[0] == 'string'))) {
777
+ return true;
778
+ }
779
+ return $.inArray(command, getters) > -1;
780
+ }
781
+
782
+ /* Process the countdown functionality for a jQuery selection.
783
+ @param options (object) the new settings to use for these instances (optional) or
784
+ (string) the command to run (optional)
785
+ @return (jQuery) for chaining further calls or
786
+ (any) getter value */
787
+ $.fn.countdown = function(options) {
788
+ var otherArgs = Array.prototype.slice.call(arguments, 1);
789
+ if (isNotChained(options, otherArgs)) {
790
+ return plugin['_' + options + 'Plugin'].
791
+ apply(plugin, [this[0]].concat(otherArgs));
792
+ }
793
+ return this.each(function() {
794
+ if (typeof options == 'string') {
795
+ if (!plugin['_' + options + 'Plugin']) {
796
+ throw 'Unknown command: ' + options;
797
+ }
798
+ plugin['_' + options + 'Plugin'].
799
+ apply(plugin, [this].concat(otherArgs));
800
+ }
801
+ else {
802
+ plugin._attachPlugin(this, options || {});
803
+ }
804
+ });
805
+ };
806
+
807
+ /* Initialise the countdown functionality. */
808
+ var plugin = $.countdown = new Countdown(); // Singleton instance
809
+
810
+ })(jQuery);
includes/mce/js/shortcodes_tinymce.js CHANGED
@@ -49,6 +49,7 @@
49
  a.render( c, "Skillbar", "skillbar" );
50
  a.render( c, "Social Icon", "social" );
51
  a.render( c, "Testimonial", "testimonial" );
 
52
  a.render( c, "HTML", "html" );
53
 
54
  b.addSeparator();
@@ -172,7 +173,7 @@
172
 
173
  // Button
174
  if(id === "button") {
175
- tinyMCE.activeEditor.selection.setContent('[wc_button type="primary" url="http://www.wordpresscanvas.com" title="Visit Site" target="self"]' + wcDummyContent + '[/wc_button]');
176
  }
177
 
178
 
@@ -280,7 +281,7 @@
280
 
281
  // Pricing
282
  if(id === "pricing") {
283
- tinyMCE.activeEditor.selection.setContent('[wc_pricing featured="yes" plan="Basic" cost="$19.99" per="per month" button_url="#" button_text="Sign Up" button_target="self" button_rel="nofollow"]<ul><li>30GB Storage</li><li>512MB Ram</li><li>10 databases</li><li>1,000 Emails</li><li>25GB Bandwidth</li></ul>[/wc_pricing]');
284
  }
285
 
286
 
@@ -319,7 +320,16 @@
319
 
320
  //Testimonial
321
  if(id === "testimonial") {
322
- tinyMCE.activeEditor.selection.setContent('[wc_testimonial by="Wordpress Canvas" position="left"]' + wcDummyContent + '[/wc_testimonial]');
 
 
 
 
 
 
 
 
 
323
  }
324
 
325
 
49
  a.render( c, "Skillbar", "skillbar" );
50
  a.render( c, "Social Icon", "social" );
51
  a.render( c, "Testimonial", "testimonial" );
52
+ a.render( c, "Countdown", "countdown" );
53
  a.render( c, "HTML", "html" );
54
 
55
  b.addSeparator();
173
 
174
  // Button
175
  if(id === "button") {
176
+ tinyMCE.activeEditor.selection.setContent('[wc_button type="primary" url="http://www.wordpresscanvas.com" title="Visit Site" target="self" position="float"]' + wcDummyContent + '[/wc_button]');
177
  }
178
 
179
 
281
 
282
  // Pricing
283
  if(id === "pricing") {
284
+ tinyMCE.activeEditor.selection.setContent('[wc_pricing type="primary" featured="yes" plan="Basic" cost="$19.99" per="per month" button_url="#" button_text="Sign Up" button_target="self" button_rel="nofollow"]<ul><li>30GB Storage</li><li>512MB Ram</li><li>10 databases</li><li>1,000 Emails</li><li>25GB Bandwidth</li></ul>[/wc_pricing]');
285
  }
286
 
287
 
320
 
321
  //Testimonial
322
  if(id === "testimonial") {
323
+ tinyMCE.activeEditor.selection.setContent('[wc_testimonial by="Wordpress Canvas" url="" position="left"]' + wcDummyContent + '[/wc_testimonial]');
324
+ }
325
+
326
+
327
+
328
+ //Countdown
329
+ if(id === "countdown") {
330
+ var d = new Date();
331
+ var year = d.getFullYear() + 1;
332
+ tinyMCE.activeEditor.selection.setContent('[wc_countdown date="July 23, '+year+', 6:00:00 PM" format="wdHMs" message="Happy New Year!"]');
333
  }
334
 
335
 
includes/scripts.php CHANGED
@@ -12,9 +12,11 @@
12
  if( !function_exists ('wc_shortcodes_scripts') ) :
13
  function wc_shortcodes_scripts() {
14
  $ver = WC_SHORTCODES_VERSION;
 
15
 
16
- if ( get_option( WC_SHORTCODES_PREFIX . 'enable_shortcode_css', true ) )
17
  wp_enqueue_style( 'wc_shortcodes_style', plugin_dir_url( __FILE__ ) . 'css/style.css', array( ), $ver );
 
18
 
19
  wp_enqueue_script('jquery');
20
  wp_register_script( 'wc_shortcodes_tabs', plugin_dir_url( __FILE__ ) . 'js/tabs.js', array ( 'jquery', 'jquery-ui-tabs'), $ver, true );
@@ -26,6 +28,10 @@ if( !function_exists ('wc_shortcodes_scripts') ) :
26
  wp_register_script( 'wc_shortcodes_googlemap_api', 'https://maps.googleapis.com/maps/api/js?sensor=false', array('jquery'), $ver, true);
27
  wp_register_script( 'wc_shortcodes_skillbar', plugin_dir_url( __FILE__ ) . 'js/skillbar.js', array ( 'jquery' ), $ver, true );
28
  wp_register_script( 'wc_shortcodes_fullwidth', plugin_dir_url( __FILE__ ) . 'js/fullwidth.js', array ( 'jquery' ), $ver, true );
 
 
 
 
29
  }
30
  add_action('wp_enqueue_scripts', 'wc_shortcodes_scripts');
31
  endif;
12
  if( !function_exists ('wc_shortcodes_scripts') ) :
13
  function wc_shortcodes_scripts() {
14
  $ver = WC_SHORTCODES_VERSION;
15
+ $fc_ver = '0.3.2'; //flickclock version
16
 
17
+ if ( get_option( WC_SHORTCODES_PREFIX . 'enable_shortcode_css', true ) ) {
18
  wp_enqueue_style( 'wc_shortcodes_style', plugin_dir_url( __FILE__ ) . 'css/style.css', array( ), $ver );
19
+ }
20
 
21
  wp_enqueue_script('jquery');
22
  wp_register_script( 'wc_shortcodes_tabs', plugin_dir_url( __FILE__ ) . 'js/tabs.js', array ( 'jquery', 'jquery-ui-tabs'), $ver, true );
28
  wp_register_script( 'wc_shortcodes_googlemap_api', 'https://maps.googleapis.com/maps/api/js?sensor=false', array('jquery'), $ver, true);
29
  wp_register_script( 'wc_shortcodes_skillbar', plugin_dir_url( __FILE__ ) . 'js/skillbar.js', array ( 'jquery' ), $ver, true );
30
  wp_register_script( 'wc_shortcodes_fullwidth', plugin_dir_url( __FILE__ ) . 'js/fullwidth.js', array ( 'jquery' ), $ver, true );
31
+
32
+ // countdown
33
+ wp_register_script( 'wc_shortcodes_jquery_countdown_js', plugin_dir_url( __FILE__ ) . 'js/jquery.countdown.js', array ( 'jquery' ), $fc_ver, true );
34
+ wp_register_script( 'wc_shortcodes_countdown', plugin_dir_url( __FILE__ ) . 'js/countdown.js', array ( 'wc_shortcodes_jquery_countdown_js' ), $ver, true );
35
  }
36
  add_action('wp_enqueue_scripts', 'wc_shortcodes_scripts');
37
  endif;
includes/shortcode-functions.php CHANGED
@@ -402,24 +402,35 @@ if( !function_exists('wc_shortcodes_button') ) {
402
  'target' => 'self',
403
  'rel' => '',
404
  'border_radius' => '',
405
- 'class' => '',
406
  'icon_left' => '',
407
- 'icon_right' => ''
 
408
  ), $atts ) );
409
-
 
410
 
411
  // $border_radius_style = ( $border_radius ) ? 'style="border-radius:'. $border_radius .'"' : NULL;
412
  $rel = ( $rel ) ? 'rel="'.$rel.'"' : NULL;
413
  $type = 'wc-shortcodes-button-' . $type;
414
 
 
 
 
 
 
415
  $button = NULL;
416
- $button .= '<a href="' . $url . '" class="wc-shortcodes-button ' . $type . ' '. $class .'" target="_'.$target.'" title="'. $title .'" '. $rel .'>';
417
  $button .= '<span class="wc-shortcodes-button-inner">';
418
  if ( $icon_left ) $button .= '<span class="wc-shortcodes-button-icon-left icon-'. $icon_left .'"></span>';
419
  $button .= $content;
420
  if ( $icon_right ) $button .= '<span class="wc-shortcodes-button-icon-right icon-'. $icon_right .'"></span>';
421
  $button .= '</span>';
422
  $button .= '</a>';
 
 
 
 
 
423
  return $button;
424
  }
425
  add_shortcode( 'wc_button', 'wc_shortcodes_button' );
@@ -467,10 +478,17 @@ if( !function_exists('wc_shortcodes_box') ) {
467
  if( !function_exists('wc_shortcodes_testimonial') ) {
468
  function wc_shortcodes_testimonial( $atts, $content = null ) {
469
  extract( shortcode_atts( array(
470
- 'by' => '',
471
- 'position' => 'left',
 
472
  'class' => '',
473
- ), $atts ) );
 
 
 
 
 
 
474
  $testimonial_content = '';
475
  $testimonial_content .= '<div class="wc-shortcodes-testimonial wc-shortcodes-clearfix wc-shortcodes-testimonial-'.$position.' '. $class .'"><div class="wc-shortcodes-testimonial-content">';
476
  $testimonial_content .= $content;
@@ -846,3 +864,33 @@ if( !function_exists('wc_shortcodes_divider') ) {
846
  }
847
  add_shortcode( 'wc_divider', 'wc_shortcodes_divider' );
848
  }
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
402
  'target' => 'self',
403
  'rel' => '',
404
  'border_radius' => '',
 
405
  'icon_left' => '',
406
+ 'icon_right' => '',
407
+ 'position' => 'float',
408
  ), $atts ) );
409
+
410
+ $whitelist = array( 'center', 'left', 'right' );
411
 
412
  // $border_radius_style = ( $border_radius ) ? 'style="border-radius:'. $border_radius .'"' : NULL;
413
  $rel = ( $rel ) ? 'rel="'.$rel.'"' : NULL;
414
  $type = 'wc-shortcodes-button-' . $type;
415
 
416
+ $class = array();
417
+ $class[] = 'wc-shortcodes-button';
418
+ $class[] = $type;
419
+ $class[] = 'wc-shortcodes-button-position-' . $position;
420
+
421
  $button = NULL;
422
+ $button .= '<a href="' . $url . '" class="'.implode( ' ', $class ).'" target="_'.$target.'" title="'. $title .'" '. $rel .'>';
423
  $button .= '<span class="wc-shortcodes-button-inner">';
424
  if ( $icon_left ) $button .= '<span class="wc-shortcodes-button-icon-left icon-'. $icon_left .'"></span>';
425
  $button .= $content;
426
  if ( $icon_right ) $button .= '<span class="wc-shortcodes-button-icon-right icon-'. $icon_right .'"></span>';
427
  $button .= '</span>';
428
  $button .= '</a>';
429
+
430
+ if ( in_array( $position, $whitelist ) ) {
431
+ $button = '<div class="wc-shortcodes-button-'.$position.'">'. $button .'</div>';
432
+ }
433
+
434
  return $button;
435
  }
436
  add_shortcode( 'wc_button', 'wc_shortcodes_button' );
478
  if( !function_exists('wc_shortcodes_testimonial') ) {
479
  function wc_shortcodes_testimonial( $atts, $content = null ) {
480
  extract( shortcode_atts( array(
481
+ 'by' => '',
482
+ 'url' => '',
483
+ 'position' => 'left',
484
  'class' => '',
485
+ ), $atts ) );
486
+
487
+ if ( ! empty( $url ) ) {
488
+ $url = esc_url( $url );
489
+ $by = '<a href="' . $url . '">' . $by . '</a>';
490
+ }
491
+
492
  $testimonial_content = '';
493
  $testimonial_content .= '<div class="wc-shortcodes-testimonial wc-shortcodes-clearfix wc-shortcodes-testimonial-'.$position.' '. $class .'"><div class="wc-shortcodes-testimonial-content">';
494
  $testimonial_content .= $content;
864
  }
865
  add_shortcode( 'wc_divider', 'wc_shortcodes_divider' );
866
  }
867
+
868
+
869
+ /*
870
+ * Countdown
871
+ * @since v1.10
872
+ */
873
+ if( !function_exists('wc_shortcodes_countdown') ) {
874
+ function wc_shortcodes_countdown( $atts ) {
875
+ extract( shortcode_atts( array(
876
+ 'date' => '',
877
+ 'format' => 'wdHMs',
878
+ 'message' => 'Happy New Year!',
879
+ ), $atts ) );
880
+
881
+ if ( empty( $date ) ) {
882
+ return '<p>*Please enter a date for your countdown*</p>';
883
+ }
884
+
885
+ wp_enqueue_script('wc_shortcodes_countdown');
886
+
887
+ $html = '<div class="wc-shortcodes-countdown" data-date="'.esc_attr( $date ).'" data-format="'.esc_attr( $format ).'" data-message="'.esc_attr( $message ).'"></div>';
888
+ $html = '<div class="wc-shortcodes-countdown-bg1">'.$html.'</div>';
889
+ $html = '<div class="wc-shortcodes-countdown-bg2">'.$html.'</div>';
890
+ $html = '<div class="wc-shortcodes-countdown-bg3">'.$html.'</div>';
891
+ $html = '<div class="wc-shortcodes-countdown-bg4">'.$html.'</div>';
892
+
893
+ return $html;
894
+ }
895
+ add_shortcode( 'wc_countdown', 'wc_shortcodes_countdown' );
896
+ }
readme.txt CHANGED
@@ -44,6 +44,13 @@ Use the shortcode manager in the TinyMCE text editor
44
 
45
  == Changelog ==
46
 
 
 
 
 
 
 
 
47
  ### Version 1.10
48
 
49
  * Fixed style bug for testimonials
44
 
45
  == Changelog ==
46
 
47
+ ### Version 1.11
48
+
49
+ * added countdown shortcode
50
+ * added link to testimonial author
51
+ * added support for buttons to be positioned left, right, or centered
52
+ * added type attribute to pricing box
53
+
54
  ### Version 1.10
55
 
56
  * Fixed style bug for testimonials
wc-shortcodes.php CHANGED
@@ -5,11 +5,11 @@ Plugin URI: http://wordpresscanvas.com/features/shortcodes/
5
  Description: A family of shortcodes to enhance site functionality.
6
  Author: Chris Baldelomar
7
  Author URI: http://webplantmedia.com/
8
- Version: 1.10
9
  License: GPLv2 or later
10
  */
11
 
12
- define( 'WC_SHORTCODES_VERSION', '1.10' );
13
  define( 'WC_SHORTCODES_PREFIX', 'wc_shortcodes_' );
14
  define( 'WC_SHORTCODES_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
15
 
5
  Description: A family of shortcodes to enhance site functionality.
6
  Author: Chris Baldelomar
7
  Author URI: http://webplantmedia.com/
8
+ Version: 1.11
9
  License: GPLv2 or later
10
  */
11
 
12
+ define( 'WC_SHORTCODES_VERSION', '1.11' );
13
  define( 'WC_SHORTCODES_PREFIX', 'wc_shortcodes_' );
14
  define( 'WC_SHORTCODES_PLUGIN_URL', plugin_dir_url( __FILE__ ) );
15