showoff 0.12.0 → 0.12.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +4 -4
- data/bin/showoff +28 -9
- data/lib/keymap.rb +145 -1
- data/lib/showoff.rb +184 -63
- data/lib/showoff/version.rb +1 -1
- data/lib/showoff_utils.rb +76 -39
- data/public/css/TimeCircles.css +42 -0
- data/public/css/presenter.css +161 -45
- data/public/css/showoff.css +185 -75
- data/public/favicon.ico +0 -0
- data/public/js/TimeCircles.js +984 -0
- data/public/js/presenter.js +147 -64
- data/public/js/showoff.js +224 -85
- data/views/download.erb +21 -24
- data/views/header.erb +5 -2
- data/views/index.erb +20 -10
- data/views/presenter.erb +19 -11
- data/views/stats.erb +47 -49
- metadata +28 -16
- data/public/css/close.png +0 -0
- data/public/css/run_code-dim.png +0 -0
- data/public/css/run_code.png +0 -0
- data/public/js/keyDictionary.json +0 -139
data/public/css/showoff.css
CHANGED
@@ -44,6 +44,7 @@ pre code {
|
|
44
44
|
body {
|
45
45
|
margin:0;
|
46
46
|
padding:0;
|
47
|
+
overflow: hidden;
|
47
48
|
}
|
48
49
|
|
49
50
|
#preso,
|
@@ -96,6 +97,9 @@ pre code {
|
|
96
97
|
z-index: 2147483647; /* max, see http://www.puidokas.com/max-z-index/ */
|
97
98
|
text-align: center;
|
98
99
|
}
|
100
|
+
#buttonNav {
|
101
|
+
display: none;
|
102
|
+
}
|
99
103
|
|
100
104
|
/* prevent large images from getting too out of hand */
|
101
105
|
.content img {
|
@@ -213,7 +217,7 @@ pre code {
|
|
213
217
|
white-space: pre;
|
214
218
|
}
|
215
219
|
|
216
|
-
|
220
|
+
#notes, .notes-section, .instructor, .solguide { display: none }
|
217
221
|
|
218
222
|
.offscreen { position:absolute; top:0; left:-9999px; overflow:hidden; }
|
219
223
|
|
@@ -229,6 +233,7 @@ pre code {
|
|
229
233
|
|
230
234
|
img#disconnected {
|
231
235
|
float: right;
|
236
|
+
margin: 5px;
|
232
237
|
display: none;
|
233
238
|
}
|
234
239
|
|
@@ -298,35 +303,6 @@ img#disconnected {
|
|
298
303
|
margin: 0.25em;
|
299
304
|
}
|
300
305
|
|
301
|
-
#presenterPopup {
|
302
|
-
display: none;
|
303
|
-
position: absolute;
|
304
|
-
z-index: 2147483647;
|
305
|
-
top: 24px;
|
306
|
-
left: 25%;
|
307
|
-
max-height: 80%;
|
308
|
-
width: 50%;
|
309
|
-
border-radius: 0 0 .5em .5em;
|
310
|
-
border-bottom: 8px solid #222222;
|
311
|
-
background-color: #222222;
|
312
|
-
overflow: auto;
|
313
|
-
}
|
314
|
-
|
315
|
-
#presenterPopup h1,
|
316
|
-
#presenterPopup h3 {
|
317
|
-
color: #ffffff;
|
318
|
-
}
|
319
|
-
|
320
|
-
#presenterPopup a {
|
321
|
-
margin-left: 12px;
|
322
|
-
color: #ffffff;
|
323
|
-
}
|
324
|
-
|
325
|
-
#presenterPopup ul#downloads {
|
326
|
-
margin-left: 0;
|
327
|
-
list-style-type: none;
|
328
|
-
}
|
329
|
-
|
330
306
|
/**********************************
|
331
307
|
*** Table styling ***
|
332
308
|
**********************************/
|
@@ -372,7 +348,8 @@ img#disconnected {
|
|
372
348
|
float: left;
|
373
349
|
}
|
374
350
|
|
375
|
-
#hamburger:hover
|
351
|
+
#hamburger:hover,
|
352
|
+
#hamburger.highlight {
|
376
353
|
opacity: 1;
|
377
354
|
background-color: #337ab7;
|
378
355
|
color: #ffffff;
|
@@ -433,6 +410,18 @@ img#disconnected {
|
|
433
410
|
cursor: pointer;
|
434
411
|
}
|
435
412
|
|
413
|
+
.buttonWrapper.disabled {
|
414
|
+
opacity: 0.25;
|
415
|
+
filter: grayscale(100%);
|
416
|
+
-webkit-filter: grayscale(100%);
|
417
|
+
background-color: initial !important;
|
418
|
+
color: initial !important;
|
419
|
+
}
|
420
|
+
.buttonWrapper.disabled:hover {
|
421
|
+
background-color: initial !important;
|
422
|
+
color: initial !important;
|
423
|
+
}
|
424
|
+
|
436
425
|
.buttonWrapper.split {
|
437
426
|
float: left;
|
438
427
|
width: 50%;
|
@@ -490,8 +479,49 @@ img#disconnected {
|
|
490
479
|
padding: .5em 1.5em;
|
491
480
|
}
|
492
481
|
|
482
|
+
#askedQuestions {
|
483
|
+
margin: 0;
|
484
|
+
}
|
485
|
+
#askedQuestions li {
|
486
|
+
cursor: default;
|
487
|
+
}
|
488
|
+
#askedQuestions li:hover {
|
489
|
+
background-color: #dedede;
|
490
|
+
}
|
491
|
+
#askedQuestions li:hover:after {
|
492
|
+
font-family: FontAwesome;
|
493
|
+
font-style: normal;
|
494
|
+
font-weight: normal;
|
495
|
+
text-decoration: inherit;
|
496
|
+
padding: 0 8px;
|
497
|
+
float: right;
|
498
|
+
content: "\f057"; /* fa-times-circle */
|
499
|
+
}
|
500
|
+
#askedQuestions li.closed {
|
501
|
+
text-decoration: line-through;
|
502
|
+
color: #ccc;
|
503
|
+
}
|
504
|
+
|
493
505
|
/* End Sidebar styling */
|
494
506
|
|
507
|
+
/* questions HUD indicator */
|
508
|
+
#questionsIndicator {
|
509
|
+
position: absolute;
|
510
|
+
top: 12px;
|
511
|
+
right: 12px;
|
512
|
+
width: 1em;
|
513
|
+
height: 1em;
|
514
|
+
font-size: 2em;
|
515
|
+
background-color: #fb8d8d;
|
516
|
+
border: 1px solid #900e0e;
|
517
|
+
border-radius: 5px;
|
518
|
+
padding: 0 0 0.25em 0.25em;
|
519
|
+
opacity: 0.5;
|
520
|
+
z-index: 999999999;
|
521
|
+
display: none;
|
522
|
+
}
|
523
|
+
/* end questions HUD indicator */
|
524
|
+
|
495
525
|
.results {
|
496
526
|
background-color:#002200;
|
497
527
|
color:#00AA00;
|
@@ -510,34 +540,41 @@ img#disconnected {
|
|
510
540
|
}
|
511
541
|
|
512
542
|
/* Add a Shell "code highlighting" style to resemble the look of a terminal window. */
|
513
|
-
.
|
543
|
+
.highlight .language-shell {
|
514
544
|
display: block;
|
515
|
-
background-color: #
|
545
|
+
background-color: #222;
|
516
546
|
color: #00ff40;
|
517
547
|
border: 2px solid #ddd;
|
518
548
|
padding: 0.5em;
|
519
549
|
overflow: hidden;
|
520
550
|
}
|
521
551
|
|
522
|
-
|
523
|
-
code
|
524
|
-
|
525
|
-
|
526
|
-
|
527
|
-
|
528
|
-
display: block;
|
529
|
-
min-height: 42px;
|
552
|
+
/**********************************
|
553
|
+
*** code execution ***
|
554
|
+
**********************************/
|
555
|
+
.execute {
|
556
|
+
position: relative;
|
557
|
+
cursor: pointer;
|
530
558
|
}
|
531
559
|
|
532
|
-
|
533
|
-
|
534
|
-
|
560
|
+
.execute:after {
|
561
|
+
font-family: FontAwesome;
|
562
|
+
content: "\F144";
|
563
|
+
position: absolute;
|
564
|
+
right: .5em;
|
535
565
|
}
|
536
566
|
|
537
|
-
|
538
|
-
|
567
|
+
.executing:after {
|
568
|
+
content: "\f1ce";
|
569
|
+
color: #e74c3c;
|
570
|
+
-webkit-animation: spin 1.5s linear infinite;
|
571
|
+
animation: spin 1.5s linear infinite;
|
539
572
|
}
|
540
573
|
|
574
|
+
.executing:hover { cursor: wait; }
|
575
|
+
/* End code execution */
|
576
|
+
|
577
|
+
|
541
578
|
#tips, #preshow_timer {
|
542
579
|
display:inline;
|
543
580
|
background-color:#000;
|
@@ -627,32 +664,36 @@ form .element {
|
|
627
664
|
.rendered {
|
628
665
|
border: 1px solid #ccc;
|
629
666
|
border-radius: 0.5em;
|
630
|
-
|
631
|
-
padding: 0.25em 0.25em 0.25em .5em;
|
667
|
+
padding: .5em;
|
632
668
|
min-height: 3em;
|
633
669
|
}
|
634
670
|
|
635
671
|
.rendered label {
|
636
672
|
border-bottom: 1px solid #999;
|
637
673
|
}
|
638
|
-
.
|
674
|
+
.item {
|
675
|
+
width: 100%;
|
676
|
+
position: relative;
|
677
|
+
}
|
678
|
+
|
679
|
+
.answer {
|
680
|
+
position: absolute;
|
681
|
+
left: 0;
|
682
|
+
}
|
683
|
+
.bar {
|
639
684
|
height: 1.25em;
|
640
|
-
|
641
|
-
background-color: #f2dede;
|
685
|
+
background-color: #e74c3c;
|
642
686
|
border: 1px solid #f45f5f;
|
643
687
|
border-left: none;
|
644
688
|
border-radius: 0 0.4em 0.4em 0;
|
645
689
|
}
|
646
|
-
.
|
690
|
+
.correct .bar {
|
647
691
|
background-color: #dff0d8;
|
648
692
|
border: 1px solid #00AA00;
|
649
693
|
border-left: none;
|
650
694
|
}
|
651
|
-
.count {
|
652
|
-
display: none;
|
653
|
-
}
|
654
695
|
|
655
|
-
|
696
|
+
.count {
|
656
697
|
display: none;
|
657
698
|
}
|
658
699
|
|
@@ -678,12 +719,13 @@ form .element {
|
|
678
719
|
.supplemental ul { list-style: disc; margin-left: 1.25em !important; padding-left: inherit !important; }
|
679
720
|
|
680
721
|
/* downloads page */
|
681
|
-
|
682
|
-
|
683
|
-
|
722
|
+
#download {
|
723
|
+
max-width: 90%;
|
724
|
+
margin: 0 auto;
|
684
725
|
}
|
685
|
-
|
686
|
-
|
726
|
+
|
727
|
+
#download h4 {
|
728
|
+
margin-left: .5em;
|
687
729
|
}
|
688
730
|
|
689
731
|
/**********************
|
@@ -696,6 +738,7 @@ body#download ul#downloads li {
|
|
696
738
|
margin: 0.25em 1em;
|
697
739
|
padding: 0.1em;
|
698
740
|
background-color: #dfdfdf;
|
741
|
+
color: #222;
|
699
742
|
-moz-border-radius: 5px;
|
700
743
|
-webkit-border-radius: 5px;
|
701
744
|
-khtml-border-radius: 5px;
|
@@ -778,8 +821,8 @@ body#download ul#downloads li {
|
|
778
821
|
**********************/
|
779
822
|
|
780
823
|
.callout {
|
781
|
-
padding: 12px
|
782
|
-
|
824
|
+
padding: 12px;
|
825
|
+
line-height: 1.6em;
|
783
826
|
border: 1px solid #222;
|
784
827
|
border-radius: 4px;
|
785
828
|
background-color: transparent; /* because there's a warning class with a red background */
|
@@ -791,7 +834,7 @@ body#download ul#downloads li {
|
|
791
834
|
font-weight: normal;
|
792
835
|
font-size: 2em;
|
793
836
|
text-decoration: inherit;
|
794
|
-
padding: 0 8px;
|
837
|
+
padding: 0 8px 100% 8px;
|
795
838
|
float: left;
|
796
839
|
}
|
797
840
|
|
@@ -806,8 +849,7 @@ body#download ul#downloads li {
|
|
806
849
|
**********************/
|
807
850
|
|
808
851
|
|
809
|
-
/*
|
810
|
-
/* Portrait */
|
852
|
+
/* Tiny mobile devices. Larger devices scale automatically. */
|
811
853
|
@media screen and (max-width: 320px)
|
812
854
|
{
|
813
855
|
html,body,#footer {
|
@@ -826,7 +868,40 @@ body#download ul#downloads li {
|
|
826
868
|
margin: 0;
|
827
869
|
padding: 0;
|
828
870
|
}
|
871
|
+
}
|
872
|
+
/* show notes, etc. when in portrait mode with plenty of room for it. */
|
873
|
+
@media screen and (max-width: 1024px) and (orientation:portrait) {
|
874
|
+
body { overflow: auto; }
|
829
875
|
|
876
|
+
/* Styling to make the handout notes appear in the printed output. */
|
877
|
+
#notes {
|
878
|
+
display: block;
|
879
|
+
clear: both;
|
880
|
+
margin: 1em 1em 4em 1em;
|
881
|
+
font-size: 9pt;
|
882
|
+
border-top: 2px dashed #999;
|
883
|
+
}
|
884
|
+
}
|
885
|
+
|
886
|
+
/* Show button navigation on touch screen devices. */
|
887
|
+
@media screen and (pointer: coarse) {
|
888
|
+
#buttonNav {
|
889
|
+
display: block;
|
890
|
+
position: fixed;
|
891
|
+
bottom: 0;
|
892
|
+
width: 100%;
|
893
|
+
}
|
894
|
+
|
895
|
+
#buttonNav div {
|
896
|
+
display: inline-block;
|
897
|
+
width: 50%;
|
898
|
+
line-height: 3em;
|
899
|
+
background-color: #337ab7;
|
900
|
+
color: #fff;
|
901
|
+
font-weight: bold;
|
902
|
+
text-align: center;
|
903
|
+
vertical-align: middle;
|
904
|
+
}
|
830
905
|
}
|
831
906
|
|
832
907
|
/** Print **/
|
@@ -867,19 +942,27 @@ body#download ul#downloads li {
|
|
867
942
|
}
|
868
943
|
|
869
944
|
/* Styling to make the handout notes appear in the printed output. */
|
870
|
-
.
|
945
|
+
.notes-section {
|
871
946
|
display: block;
|
872
947
|
clear: both;
|
873
|
-
|
948
|
+
margin-top: 1em;
|
949
|
+
border-top: 2px dashed #999;
|
874
950
|
}
|
875
951
|
|
876
|
-
|
877
|
-
|
878
|
-
|
879
|
-
|
880
|
-
|
881
|
-
|
882
|
-
|
952
|
+
.notes-section.notes .personal {
|
953
|
+
float: right;
|
954
|
+
border-left: 2px solid #999;
|
955
|
+
border-bottom: 2px solid #999;
|
956
|
+
border-radius: 0 0 0 0.5em;
|
957
|
+
padding: 0.1em 0 0.25em 0.25em;
|
958
|
+
margin: 0 0 1em 1em;
|
959
|
+
max-width: 35%;
|
960
|
+
}
|
961
|
+
|
962
|
+
.notes-section.notes .personal h1 {
|
963
|
+
margin-top: 0;
|
964
|
+
border-bottom: 1px solid #ccc;
|
965
|
+
font-size: 1.5em;
|
883
966
|
}
|
884
967
|
|
885
968
|
/* page break styling */
|
@@ -892,3 +975,30 @@ body#download ul#downloads li {
|
|
892
975
|
}
|
893
976
|
|
894
977
|
}
|
978
|
+
|
979
|
+
/***********************
|
980
|
+
*** Animations ***
|
981
|
+
***********************/
|
982
|
+
|
983
|
+
@-webkit-keyframes spin {
|
984
|
+
from {
|
985
|
+
-webkit-transform: rotate(0deg); /* Chrome, Opera 15+, Safari 3.1+ */
|
986
|
+
transform: rotate(0deg); /* Firefox 16+, IE 10+, Opera */
|
987
|
+
}
|
988
|
+
to {
|
989
|
+
-webkit-transform: rotate(360deg); /* Chrome, Opera 15+, Safari 3.1+ */
|
990
|
+
transform: rotate(360deg); /* Firefox 16+, IE 10+, Opera */
|
991
|
+
}
|
992
|
+
}
|
993
|
+
@keyframes spin {
|
994
|
+
from {
|
995
|
+
-webkit-transform: rotate(0deg); /* Chrome, Opera 15+, Safari 3.1+ */
|
996
|
+
transform: rotate(0deg); /* Firefox 16+, IE 10+, Opera */
|
997
|
+
}
|
998
|
+
to {
|
999
|
+
-webkit-transform: rotate(360deg); /* Chrome, Opera 15+, Safari 3.1+ */
|
1000
|
+
transform: rotate(360deg); /* Firefox 16+, IE 10+, Opera */
|
1001
|
+
}
|
1002
|
+
}
|
1003
|
+
|
1004
|
+
/* end animations */
|
data/public/favicon.ico
CHANGED
Binary file
|
@@ -0,0 +1,984 @@
|
|
1
|
+
/**
|
2
|
+
* Basic structure: TC_Class is the public class that is returned upon being called
|
3
|
+
*
|
4
|
+
* So, if you do
|
5
|
+
* var tc = $(".timer").TimeCircles();
|
6
|
+
*
|
7
|
+
* tc will contain an instance of the public TimeCircles class. It is important to
|
8
|
+
* note that TimeCircles is not chained in the conventional way, check the
|
9
|
+
* documentation for more info on how TimeCircles can be chained.
|
10
|
+
*
|
11
|
+
* After being called/created, the public TimerCircles class will then- for each element
|
12
|
+
* within it's collection, either fetch or create an instance of the private class.
|
13
|
+
* Each function called upon the public class will be forwarded to each instance
|
14
|
+
* of the private classes within the relevant element collection
|
15
|
+
**/
|
16
|
+
(function($) {
|
17
|
+
|
18
|
+
var useWindow = window;
|
19
|
+
|
20
|
+
// From https://developer.mozilla.org/en-US/docs/Web/JavaScript/Reference/Global_Objects/Object/keys
|
21
|
+
if (!Object.keys) {
|
22
|
+
Object.keys = (function() {
|
23
|
+
'use strict';
|
24
|
+
var hasOwnProperty = Object.prototype.hasOwnProperty,
|
25
|
+
hasDontEnumBug = !({toString: null}).propertyIsEnumerable('toString'),
|
26
|
+
dontEnums = [
|
27
|
+
'toString',
|
28
|
+
'toLocaleString',
|
29
|
+
'valueOf',
|
30
|
+
'hasOwnProperty',
|
31
|
+
'isPrototypeOf',
|
32
|
+
'propertyIsEnumerable',
|
33
|
+
'constructor'
|
34
|
+
],
|
35
|
+
dontEnumsLength = dontEnums.length;
|
36
|
+
|
37
|
+
return function(obj) {
|
38
|
+
if (typeof obj !== 'object' && (typeof obj !== 'function' || obj === null)) {
|
39
|
+
throw new TypeError('Object.keys called on non-object');
|
40
|
+
}
|
41
|
+
|
42
|
+
var result = [], prop, i;
|
43
|
+
|
44
|
+
for (prop in obj) {
|
45
|
+
if (hasOwnProperty.call(obj, prop)) {
|
46
|
+
result.push(prop);
|
47
|
+
}
|
48
|
+
}
|
49
|
+
|
50
|
+
if (hasDontEnumBug) {
|
51
|
+
for (i = 0; i < dontEnumsLength; i++) {
|
52
|
+
if (hasOwnProperty.call(obj, dontEnums[i])) {
|
53
|
+
result.push(dontEnums[i]);
|
54
|
+
}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
return result;
|
58
|
+
};
|
59
|
+
}());
|
60
|
+
}
|
61
|
+
|
62
|
+
// Used to disable some features on IE8
|
63
|
+
var limited_mode = false;
|
64
|
+
var tick_duration = 200; // in ms
|
65
|
+
|
66
|
+
var debug = (location.hash === "#debug");
|
67
|
+
function debug_log(msg) {
|
68
|
+
if (debug) {
|
69
|
+
console.log(msg);
|
70
|
+
}
|
71
|
+
}
|
72
|
+
|
73
|
+
var allUnits = ["Days", "Hours", "Minutes", "Seconds"];
|
74
|
+
var nextUnits = {
|
75
|
+
Seconds: "Minutes",
|
76
|
+
Minutes: "Hours",
|
77
|
+
Hours: "Days",
|
78
|
+
Days: "Years"
|
79
|
+
};
|
80
|
+
var secondsIn = {
|
81
|
+
Seconds: 1,
|
82
|
+
Minutes: 60,
|
83
|
+
Hours: 3600,
|
84
|
+
Days: 86400,
|
85
|
+
Months: 2678400,
|
86
|
+
Years: 31536000
|
87
|
+
};
|
88
|
+
|
89
|
+
/**
|
90
|
+
* Converts hex color code into object containing integer values for the r,g,b use
|
91
|
+
* This function (hexToRgb) originates from:
|
92
|
+
* http://stackoverflow.com/questions/5623838/rgb-to-hex-and-hex-to-rgb
|
93
|
+
* @param {string} hex color code
|
94
|
+
*/
|
95
|
+
function hexToRgb(hex) {
|
96
|
+
|
97
|
+
// Verify already RGB (e.g. "rgb(0,0,0)") or RGBA (e.g. "rgba(0,0,0,0.5)")
|
98
|
+
var rgba = /^rgba?\(([\d]+),([\d]+),([\d]+)(,([\d\.]+))?\)$/;
|
99
|
+
if(rgba.test(hex)) {
|
100
|
+
var result = rgba.exec(hex);
|
101
|
+
return {
|
102
|
+
r: parseInt(result[1]),
|
103
|
+
g: parseInt(result[2]),
|
104
|
+
b: parseInt(result[3]),
|
105
|
+
a: parseInt(result[5] ? result[5] : 1)
|
106
|
+
};
|
107
|
+
}
|
108
|
+
|
109
|
+
// Expand shorthand form (e.g. "03F") to full form (e.g. "0033FF")
|
110
|
+
var shorthandRegex = /^#?([a-f\d])([a-f\d])([a-f\d])$/i;
|
111
|
+
hex = hex.replace(shorthandRegex, function(m, r, g, b) {
|
112
|
+
return r + r + g + g + b + b;
|
113
|
+
});
|
114
|
+
|
115
|
+
var result = /^#?([a-f\d]{2})([a-f\d]{2})([a-f\d]{2})$/i.exec(hex);
|
116
|
+
return result ? {
|
117
|
+
r: parseInt(result[1], 16),
|
118
|
+
g: parseInt(result[2], 16),
|
119
|
+
b: parseInt(result[3], 16)
|
120
|
+
} : null;
|
121
|
+
}
|
122
|
+
|
123
|
+
function isCanvasSupported() {
|
124
|
+
var elem = document.createElement('canvas');
|
125
|
+
return !!(elem.getContext && elem.getContext('2d'));
|
126
|
+
}
|
127
|
+
|
128
|
+
/**
|
129
|
+
* Function s4() and guid() originate from:
|
130
|
+
* http://stackoverflow.com/questions/105034/how-to-create-a-guid-uuid-in-javascript
|
131
|
+
*/
|
132
|
+
function s4() {
|
133
|
+
return Math.floor((1 + Math.random()) * 0x10000)
|
134
|
+
.toString(16)
|
135
|
+
.substring(1);
|
136
|
+
}
|
137
|
+
|
138
|
+
/**
|
139
|
+
* Creates a unique id
|
140
|
+
* @returns {String}
|
141
|
+
*/
|
142
|
+
function guid() {
|
143
|
+
return s4() + s4() + '-' + s4() + '-' + s4() + '-' +
|
144
|
+
s4() + '-' + s4() + s4() + s4();
|
145
|
+
}
|
146
|
+
|
147
|
+
/**
|
148
|
+
* Array.prototype.indexOf fallback for IE8
|
149
|
+
* @param {Mixed} mixed
|
150
|
+
* @returns {Number}
|
151
|
+
*/
|
152
|
+
if (!Array.prototype.indexOf) {
|
153
|
+
Array.prototype.indexOf = function(elt /*, from*/)
|
154
|
+
{
|
155
|
+
var len = this.length >>> 0;
|
156
|
+
|
157
|
+
var from = Number(arguments[1]) || 0;
|
158
|
+
from = (from < 0)
|
159
|
+
? Math.ceil(from)
|
160
|
+
: Math.floor(from);
|
161
|
+
if (from < 0)
|
162
|
+
from += len;
|
163
|
+
|
164
|
+
for (; from < len; from++)
|
165
|
+
{
|
166
|
+
if (from in this &&
|
167
|
+
this[from] === elt)
|
168
|
+
return from;
|
169
|
+
}
|
170
|
+
return -1;
|
171
|
+
};
|
172
|
+
}
|
173
|
+
|
174
|
+
function parse_date(str) {
|
175
|
+
var match = str.match(/^[0-9]{4}-[0-9]{2}-[0-9]{2}\s[0-9]{1,2}:[0-9]{2}:[0-9]{2}$/);
|
176
|
+
if (match !== null && match.length > 0) {
|
177
|
+
var parts = str.split(" ");
|
178
|
+
var date = parts[0].split("-");
|
179
|
+
var time = parts[1].split(":");
|
180
|
+
return new Date(date[0], date[1] - 1, date[2], time[0], time[1], time[2]);
|
181
|
+
}
|
182
|
+
// Fallback for different date formats
|
183
|
+
var d = Date.parse(str);
|
184
|
+
if (!isNaN(d))
|
185
|
+
return d;
|
186
|
+
d = Date.parse(str.replace(/-/g, '/').replace('T', ' '));
|
187
|
+
if (!isNaN(d))
|
188
|
+
return d;
|
189
|
+
// Cant find anything
|
190
|
+
return new Date();
|
191
|
+
}
|
192
|
+
|
193
|
+
function parse_times(diff, old_diff, total_duration, units, floor) {
|
194
|
+
var raw_time = {};
|
195
|
+
var raw_old_time = {};
|
196
|
+
var time = {};
|
197
|
+
var pct = {};
|
198
|
+
var old_pct = {};
|
199
|
+
var old_time = {};
|
200
|
+
|
201
|
+
var greater_unit = null;
|
202
|
+
var unit;
|
203
|
+
var maxUnits;
|
204
|
+
var curUnits;
|
205
|
+
var oldUnits;
|
206
|
+
|
207
|
+
for(var i = 0; i < units.length; i++) {
|
208
|
+
unit = units[i];
|
209
|
+
maxUnits;
|
210
|
+
|
211
|
+
if (greater_unit === null) {
|
212
|
+
maxUnits = total_duration / secondsIn[unit];
|
213
|
+
}
|
214
|
+
else {
|
215
|
+
maxUnits = secondsIn[greater_unit] / secondsIn[unit];
|
216
|
+
}
|
217
|
+
|
218
|
+
curUnits = (diff / secondsIn[unit]);
|
219
|
+
oldUnits = (old_diff / secondsIn[unit]);
|
220
|
+
|
221
|
+
if(floor) {
|
222
|
+
if(curUnits > 0) curUnits = Math.floor(curUnits);
|
223
|
+
else curUnits = Math.ceil(curUnits);
|
224
|
+
if(oldUnits > 0) oldUnits = Math.floor(oldUnits);
|
225
|
+
else oldUnits = Math.ceil(oldUnits);
|
226
|
+
}
|
227
|
+
|
228
|
+
if (unit !== "Days") {
|
229
|
+
curUnits = curUnits % maxUnits;
|
230
|
+
oldUnits = oldUnits % maxUnits;
|
231
|
+
}
|
232
|
+
|
233
|
+
raw_time[unit] = curUnits;
|
234
|
+
time[unit] = Math.abs(curUnits);
|
235
|
+
raw_old_time[unit] = oldUnits;
|
236
|
+
old_time[unit] = Math.abs(oldUnits);
|
237
|
+
pct[unit] = Math.abs(curUnits) / maxUnits;
|
238
|
+
old_pct[unit] = Math.abs(oldUnits) / maxUnits;
|
239
|
+
|
240
|
+
greater_unit = unit;
|
241
|
+
}
|
242
|
+
|
243
|
+
return {
|
244
|
+
raw_time: raw_time,
|
245
|
+
raw_old_time: raw_old_time,
|
246
|
+
time: time,
|
247
|
+
old_time: old_time,
|
248
|
+
pct: pct,
|
249
|
+
old_pct: old_pct
|
250
|
+
};
|
251
|
+
}
|
252
|
+
|
253
|
+
var TC_Instance_List = {};
|
254
|
+
function updateUsedWindow() {
|
255
|
+
if(typeof useWindow.TC_Instance_List !== "undefined") {
|
256
|
+
TC_Instance_List = useWindow.TC_Instance_List;
|
257
|
+
}
|
258
|
+
else {
|
259
|
+
useWindow.TC_Instance_List = TC_Instance_List;
|
260
|
+
}
|
261
|
+
initializeAnimationFrameHandler(useWindow);
|
262
|
+
};
|
263
|
+
|
264
|
+
function initializeAnimationFrameHandler(w) {
|
265
|
+
var vendors = ['webkit', 'moz'];
|
266
|
+
for (var x = 0; x < vendors.length && !w.requestAnimationFrame; ++x) {
|
267
|
+
w.requestAnimationFrame = w[vendors[x] + 'RequestAnimationFrame'];
|
268
|
+
w.cancelAnimationFrame = w[vendors[x] + 'CancelAnimationFrame'];
|
269
|
+
}
|
270
|
+
|
271
|
+
if (!w.requestAnimationFrame || !w.cancelAnimationFrame) {
|
272
|
+
w.requestAnimationFrame = function(callback, element, instance) {
|
273
|
+
if (typeof instance === "undefined")
|
274
|
+
instance = {data: {last_frame: 0}};
|
275
|
+
var currTime = new Date().getTime();
|
276
|
+
var timeToCall = Math.max(0, 16 - (currTime - instance.data.last_frame));
|
277
|
+
var id = w.setTimeout(function() {
|
278
|
+
callback(currTime + timeToCall);
|
279
|
+
}, timeToCall);
|
280
|
+
instance.data.last_frame = currTime + timeToCall;
|
281
|
+
return id;
|
282
|
+
};
|
283
|
+
w.cancelAnimationFrame = function(id) {
|
284
|
+
clearTimeout(id);
|
285
|
+
};
|
286
|
+
}
|
287
|
+
};
|
288
|
+
|
289
|
+
|
290
|
+
var TC_Instance = function(element, options) {
|
291
|
+
this.element = element;
|
292
|
+
this.container;
|
293
|
+
this.listeners = null;
|
294
|
+
this.data = {
|
295
|
+
paused: false,
|
296
|
+
last_frame: 0,
|
297
|
+
animation_frame: null,
|
298
|
+
interval_fallback: null,
|
299
|
+
timer: false,
|
300
|
+
total_duration: null,
|
301
|
+
prev_time: null,
|
302
|
+
drawn_units: [],
|
303
|
+
text_elements: {
|
304
|
+
Days: null,
|
305
|
+
Hours: null,
|
306
|
+
Minutes: null,
|
307
|
+
Seconds: null
|
308
|
+
},
|
309
|
+
attributes: {
|
310
|
+
canvas: null,
|
311
|
+
context: null,
|
312
|
+
item_size: null,
|
313
|
+
line_width: null,
|
314
|
+
radius: null,
|
315
|
+
outer_radius: null
|
316
|
+
},
|
317
|
+
state: {
|
318
|
+
fading: {
|
319
|
+
Days: false,
|
320
|
+
Hours: false,
|
321
|
+
Minutes: false,
|
322
|
+
Seconds: false
|
323
|
+
}
|
324
|
+
}
|
325
|
+
};
|
326
|
+
|
327
|
+
this.config = null;
|
328
|
+
this.setOptions(options);
|
329
|
+
this.initialize();
|
330
|
+
};
|
331
|
+
|
332
|
+
TC_Instance.prototype.clearListeners = function() {
|
333
|
+
this.listeners = { all: [], visible: [] };
|
334
|
+
};
|
335
|
+
|
336
|
+
TC_Instance.prototype.addTime = function(seconds_to_add) {
|
337
|
+
if(this.data.attributes.ref_date instanceof Date) {
|
338
|
+
var d = this.data.attributes.ref_date;
|
339
|
+
d.setSeconds(d.getSeconds() + seconds_to_add);
|
340
|
+
}
|
341
|
+
else if(!isNaN(this.data.attributes.ref_date)) {
|
342
|
+
this.data.attributes.ref_date += (seconds_to_add * 1000);
|
343
|
+
}
|
344
|
+
};
|
345
|
+
|
346
|
+
TC_Instance.prototype.initialize = function(clear_listeners) {
|
347
|
+
// Initialize drawn units
|
348
|
+
this.data.drawn_units = [];
|
349
|
+
for(var i = 0; i < Object.keys(this.config.time).length; i++) {
|
350
|
+
unit = Object.keys(this.config.time)[i];
|
351
|
+
if (this.config.time[unit].show) {
|
352
|
+
this.data.drawn_units.push(unit);
|
353
|
+
}
|
354
|
+
}
|
355
|
+
|
356
|
+
// Avoid stacking
|
357
|
+
$(this.element).children('div.time_circles').remove();
|
358
|
+
|
359
|
+
if (typeof clear_listeners === "undefined")
|
360
|
+
clear_listeners = true;
|
361
|
+
if (clear_listeners || this.listeners === null) {
|
362
|
+
this.clearListeners();
|
363
|
+
}
|
364
|
+
this.container = $("<div>");
|
365
|
+
this.container.addClass('time_circles');
|
366
|
+
this.container.appendTo(this.element);
|
367
|
+
|
368
|
+
// Determine the needed width and height of TimeCircles
|
369
|
+
var height = this.element.offsetHeight;
|
370
|
+
var width = this.element.offsetWidth;
|
371
|
+
if (height === 0)
|
372
|
+
height = $(this.element).height();
|
373
|
+
if (width === 0)
|
374
|
+
width = $(this.element).width();
|
375
|
+
|
376
|
+
if (height === 0 && width > 0)
|
377
|
+
height = width / this.data.drawn_units.length;
|
378
|
+
else if (width === 0 && height > 0)
|
379
|
+
width = height * this.data.drawn_units.length;
|
380
|
+
|
381
|
+
// Create our canvas and set it to the appropriate size
|
382
|
+
var canvasElement = document.createElement('canvas');
|
383
|
+
canvasElement.width = width;
|
384
|
+
canvasElement.height = height;
|
385
|
+
|
386
|
+
// Add canvas elements
|
387
|
+
this.data.attributes.canvas = $(canvasElement);
|
388
|
+
this.data.attributes.canvas.appendTo(this.container);
|
389
|
+
|
390
|
+
// Check if the browser has browser support
|
391
|
+
var canvasSupported = isCanvasSupported();
|
392
|
+
// If the browser doesn't have browser support, check if explorer canvas is loaded
|
393
|
+
// (A javascript library that adds canvas support to browsers that don't have it)
|
394
|
+
if(!canvasSupported && typeof G_vmlCanvasManager !== "undefined") {
|
395
|
+
G_vmlCanvasManager.initElement(canvasElement);
|
396
|
+
limited_mode = true;
|
397
|
+
canvasSupported = true;
|
398
|
+
}
|
399
|
+
if(canvasSupported) {
|
400
|
+
this.data.attributes.context = canvasElement.getContext('2d');
|
401
|
+
}
|
402
|
+
|
403
|
+
this.data.attributes.item_size = Math.min(width / this.data.drawn_units.length, height);
|
404
|
+
this.data.attributes.line_width = this.data.attributes.item_size * this.config.fg_width;
|
405
|
+
this.data.attributes.radius = ((this.data.attributes.item_size * 0.8) - this.data.attributes.line_width) / 2;
|
406
|
+
this.data.attributes.outer_radius = this.data.attributes.radius + 0.5 * Math.max(this.data.attributes.line_width, this.data.attributes.line_width * this.config.bg_width);
|
407
|
+
|
408
|
+
// Prepare Time Elements
|
409
|
+
var i = 0;
|
410
|
+
var textElement;
|
411
|
+
var headerElement;
|
412
|
+
var numberElement;
|
413
|
+
for (var key in this.data.text_elements) {
|
414
|
+
if (!this.config.time[key].show)
|
415
|
+
continue;
|
416
|
+
|
417
|
+
textElement = $("<div>");
|
418
|
+
textElement.addClass('textDiv_' + key);
|
419
|
+
textElement.css("top", Math.round(0.35 * this.data.attributes.item_size));
|
420
|
+
textElement.css("left", Math.round(i++ * this.data.attributes.item_size));
|
421
|
+
textElement.css("width", this.data.attributes.item_size);
|
422
|
+
textElement.appendTo(this.container);
|
423
|
+
|
424
|
+
headerElement = $("<h4>");
|
425
|
+
headerElement.text(this.config.time[key].text); // Options
|
426
|
+
headerElement.css("font-size", Math.round(this.config.text_size * this.data.attributes.item_size));
|
427
|
+
headerElement.css("line-height", Math.round(this.config.text_size * this.data.attributes.item_size) + "px");
|
428
|
+
headerElement.appendTo(textElement);
|
429
|
+
|
430
|
+
numberElement = $("<span>");
|
431
|
+
numberElement.css("font-size", Math.round(3 * this.config.text_size * this.data.attributes.item_size));
|
432
|
+
numberElement.css("line-height", Math.round(this.config.text_size * this.data.attributes.item_size) + "px");
|
433
|
+
numberElement.appendTo(textElement);
|
434
|
+
|
435
|
+
this.data.text_elements[key] = numberElement;
|
436
|
+
}
|
437
|
+
|
438
|
+
this.start();
|
439
|
+
if (!this.config.start) {
|
440
|
+
this.data.paused = true;
|
441
|
+
}
|
442
|
+
|
443
|
+
// Set up interval fallback
|
444
|
+
var _this = this;
|
445
|
+
this.data.interval_fallback = useWindow.setInterval(function(){
|
446
|
+
_this.update.call(_this, true);
|
447
|
+
}, 100);
|
448
|
+
};
|
449
|
+
|
450
|
+
TC_Instance.prototype.update = function(nodraw) {
|
451
|
+
if(typeof nodraw === "undefined") {
|
452
|
+
nodraw = false;
|
453
|
+
}
|
454
|
+
else if(nodraw && this.data.paused) {
|
455
|
+
return;
|
456
|
+
}
|
457
|
+
|
458
|
+
if(limited_mode) {
|
459
|
+
//Per unit clearing doesn't work in IE8 using explorer canvas, so do it in one time. The downside is that radial fade cant be used
|
460
|
+
this.data.attributes.context.clearRect(0, 0, this.data.attributes.canvas[0].width, this.data.attributes.canvas[0].hright);
|
461
|
+
}
|
462
|
+
var diff, old_diff;
|
463
|
+
|
464
|
+
var prevDate = this.data.prev_time;
|
465
|
+
var curDate = new Date();
|
466
|
+
this.data.prev_time = curDate;
|
467
|
+
|
468
|
+
if (prevDate === null)
|
469
|
+
prevDate = curDate;
|
470
|
+
|
471
|
+
// If not counting past zero, and time < 0, then simply draw the zero point once, and call stop
|
472
|
+
if (!this.config.count_past_zero) {
|
473
|
+
if (curDate > this.data.attributes.ref_date) {
|
474
|
+
var key;
|
475
|
+
var x;
|
476
|
+
var y;
|
477
|
+
var color;
|
478
|
+
|
479
|
+
for(var i = 0; i < this.data.drawn_units.length; i++) {
|
480
|
+
key = this.data.drawn_units[i];
|
481
|
+
|
482
|
+
// Set the text value
|
483
|
+
this.data.text_elements[key].text("0");
|
484
|
+
x = (i * this.data.attributes.item_size) + (this.data.attributes.item_size / 2);
|
485
|
+
y = this.data.attributes.item_size / 2;
|
486
|
+
color = this.config.time[key].color;
|
487
|
+
this.drawArc(x, y, color, 0);
|
488
|
+
this.notifyListeners(key, 0, 0, "visible");
|
489
|
+
}
|
490
|
+
this.stop();
|
491
|
+
return;
|
492
|
+
}
|
493
|
+
}
|
494
|
+
|
495
|
+
// Compare current time with reference
|
496
|
+
diff = (this.data.attributes.ref_date - curDate) / 1000;
|
497
|
+
old_diff = (this.data.attributes.ref_date - prevDate) / 1000;
|
498
|
+
|
499
|
+
var floor = this.config.animation !== "smooth";
|
500
|
+
|
501
|
+
var visible_times = parse_times(diff, old_diff, this.data.total_duration, this.data.drawn_units, floor);
|
502
|
+
var all_times = parse_times(diff, old_diff, secondsIn["Years"], allUnits, floor);
|
503
|
+
|
504
|
+
var i = 0;
|
505
|
+
var j = 0;
|
506
|
+
var lastKey = null;
|
507
|
+
|
508
|
+
var cur_shown = this.data.drawn_units.slice();
|
509
|
+
var key;
|
510
|
+
var x;
|
511
|
+
var y;
|
512
|
+
var color;
|
513
|
+
|
514
|
+
for (var i in allUnits) {
|
515
|
+
key = allUnits[i];
|
516
|
+
|
517
|
+
// Notify (all) listeners
|
518
|
+
if (Math.floor(all_times.raw_time[key]) !== Math.floor(all_times.raw_old_time[key])) {
|
519
|
+
this.notifyListeners(key, Math.floor(all_times.time[key]), Math.floor(diff), "all");
|
520
|
+
}
|
521
|
+
|
522
|
+
if (cur_shown.indexOf(key) < 0)
|
523
|
+
continue;
|
524
|
+
|
525
|
+
// Notify (visible) listeners
|
526
|
+
if (Math.floor(visible_times.raw_time[key]) !== Math.floor(visible_times.raw_old_time[key])) {
|
527
|
+
this.notifyListeners(key, Math.floor(visible_times.time[key]), Math.floor(diff), "visible");
|
528
|
+
}
|
529
|
+
|
530
|
+
if(!nodraw) {
|
531
|
+
// Set the text value
|
532
|
+
this.data.text_elements[key].text(Math.floor(Math.abs(visible_times.time[key])));
|
533
|
+
|
534
|
+
x = (j * this.data.attributes.item_size) + (this.data.attributes.item_size / 2);
|
535
|
+
y = this.data.attributes.item_size / 2;
|
536
|
+
color = this.config.time[key].color;
|
537
|
+
|
538
|
+
if (this.config.animation === "smooth") {
|
539
|
+
if (lastKey !== null && !limited_mode) {
|
540
|
+
if (Math.floor(visible_times.time[lastKey]) > Math.floor(visible_times.old_time[lastKey])) {
|
541
|
+
this.radialFade(x, y, color, 1, key);
|
542
|
+
this.data.state.fading[key] = true;
|
543
|
+
}
|
544
|
+
else if (Math.floor(visible_times.time[lastKey]) < Math.floor(visible_times.old_time[lastKey])) {
|
545
|
+
this.radialFade(x, y, color, 0, key);
|
546
|
+
this.data.state.fading[key] = true;
|
547
|
+
}
|
548
|
+
}
|
549
|
+
if (!this.data.state.fading[key]) {
|
550
|
+
this.drawArc(x, y, color, visible_times.pct[key]);
|
551
|
+
}
|
552
|
+
}
|
553
|
+
else {
|
554
|
+
this.animateArc(x, y, color, visible_times.pct[key], visible_times.old_pct[key], (new Date()).getTime() + tick_duration);
|
555
|
+
}
|
556
|
+
}
|
557
|
+
lastKey = key;
|
558
|
+
j++;
|
559
|
+
}
|
560
|
+
|
561
|
+
// Dont request another update if we should be paused
|
562
|
+
if(this.data.paused || nodraw) {
|
563
|
+
return;
|
564
|
+
}
|
565
|
+
|
566
|
+
// We need this for our next frame either way
|
567
|
+
var _this = this;
|
568
|
+
var update = function() {
|
569
|
+
_this.update.call(_this);
|
570
|
+
};
|
571
|
+
|
572
|
+
// Either call next update immediately, or in a second
|
573
|
+
if (this.config.animation === "smooth") {
|
574
|
+
// Smooth animation, Queue up the next frame
|
575
|
+
this.data.animation_frame = useWindow.requestAnimationFrame(update, _this.element, _this);
|
576
|
+
}
|
577
|
+
else {
|
578
|
+
// Tick animation, Don't queue until very slightly after the next second happens
|
579
|
+
var delay = (diff % 1) * 1000;
|
580
|
+
if (delay < 0)
|
581
|
+
delay = 1000 + delay;
|
582
|
+
delay += 50;
|
583
|
+
|
584
|
+
_this.data.animation_frame = useWindow.setTimeout(function() {
|
585
|
+
_this.data.animation_frame = useWindow.requestAnimationFrame(update, _this.element, _this);
|
586
|
+
}, delay);
|
587
|
+
}
|
588
|
+
};
|
589
|
+
|
590
|
+
TC_Instance.prototype.animateArc = function(x, y, color, target_pct, cur_pct, animation_end) {
|
591
|
+
if (this.data.attributes.context === null)
|
592
|
+
return;
|
593
|
+
|
594
|
+
var diff = cur_pct - target_pct;
|
595
|
+
if (Math.abs(diff) > 0.5) {
|
596
|
+
if (target_pct === 0) {
|
597
|
+
this.radialFade(x, y, color, 1);
|
598
|
+
}
|
599
|
+
else {
|
600
|
+
this.radialFade(x, y, color, 0);
|
601
|
+
}
|
602
|
+
}
|
603
|
+
else {
|
604
|
+
var progress = (tick_duration - (animation_end - (new Date()).getTime())) / tick_duration;
|
605
|
+
if (progress > 1)
|
606
|
+
progress = 1;
|
607
|
+
|
608
|
+
var pct = (cur_pct * (1 - progress)) + (target_pct * progress);
|
609
|
+
this.drawArc(x, y, color, pct);
|
610
|
+
|
611
|
+
//var show_pct =
|
612
|
+
if (progress >= 1)
|
613
|
+
return;
|
614
|
+
var _this = this;
|
615
|
+
useWindow.requestAnimationFrame(function() {
|
616
|
+
_this.animateArc(x, y, color, target_pct, cur_pct, animation_end);
|
617
|
+
}, this.element);
|
618
|
+
}
|
619
|
+
};
|
620
|
+
|
621
|
+
TC_Instance.prototype.drawArc = function(x, y, color, pct) {
|
622
|
+
if (this.data.attributes.context === null)
|
623
|
+
return;
|
624
|
+
|
625
|
+
var clear_radius = Math.max(this.data.attributes.outer_radius, this.data.attributes.item_size / 2);
|
626
|
+
if(!limited_mode) {
|
627
|
+
this.data.attributes.context.clearRect(
|
628
|
+
x - clear_radius,
|
629
|
+
y - clear_radius,
|
630
|
+
clear_radius * 2,
|
631
|
+
clear_radius * 2
|
632
|
+
);
|
633
|
+
}
|
634
|
+
|
635
|
+
if (this.config.use_background) {
|
636
|
+
this.data.attributes.context.beginPath();
|
637
|
+
this.data.attributes.context.arc(x, y, this.data.attributes.radius, 0, 2 * Math.PI, false);
|
638
|
+
this.data.attributes.context.lineWidth = this.data.attributes.line_width * this.config.bg_width;
|
639
|
+
|
640
|
+
// line color
|
641
|
+
this.data.attributes.context.strokeStyle = this.config.circle_bg_color;
|
642
|
+
this.data.attributes.context.stroke();
|
643
|
+
}
|
644
|
+
|
645
|
+
// Direction
|
646
|
+
var startAngle, endAngle, counterClockwise;
|
647
|
+
var defaultOffset = (-0.5 * Math.PI);
|
648
|
+
var fullCircle = 2 * Math.PI;
|
649
|
+
startAngle = defaultOffset + (this.config.start_angle / 360 * fullCircle);
|
650
|
+
var offset = (2 * pct * Math.PI);
|
651
|
+
|
652
|
+
if (this.config.direction === "Both") {
|
653
|
+
counterClockwise = false;
|
654
|
+
startAngle -= (offset / 2);
|
655
|
+
endAngle = startAngle + offset;
|
656
|
+
}
|
657
|
+
else {
|
658
|
+
if (this.config.direction === "Clockwise") {
|
659
|
+
counterClockwise = false;
|
660
|
+
endAngle = startAngle + offset;
|
661
|
+
}
|
662
|
+
else {
|
663
|
+
counterClockwise = true;
|
664
|
+
endAngle = startAngle - offset;
|
665
|
+
}
|
666
|
+
}
|
667
|
+
|
668
|
+
this.data.attributes.context.beginPath();
|
669
|
+
this.data.attributes.context.arc(x, y, this.data.attributes.radius, startAngle, endAngle, counterClockwise);
|
670
|
+
this.data.attributes.context.lineWidth = this.data.attributes.line_width;
|
671
|
+
|
672
|
+
// line color
|
673
|
+
this.data.attributes.context.strokeStyle = color;
|
674
|
+
this.data.attributes.context.stroke();
|
675
|
+
};
|
676
|
+
|
677
|
+
TC_Instance.prototype.radialFade = function(x, y, color, from, key) {
|
678
|
+
// TODO: Make fade_time option
|
679
|
+
var rgb = hexToRgb(color);
|
680
|
+
var _this = this; // We have a few inner scopes here that will need access to our instance
|
681
|
+
|
682
|
+
var step = 0.2 * ((from === 1) ? -1 : 1);
|
683
|
+
var i;
|
684
|
+
var delay;
|
685
|
+
var rgba;
|
686
|
+
for (i = 0; from <= 1 && from >= 0; i++) {
|
687
|
+
// Create inner scope so our variables are not changed by the time the Timeout triggers
|
688
|
+
(function() {
|
689
|
+
delay = 50 * i;
|
690
|
+
rgba = "rgba(" + rgb.r + ", " + rgb.g + ", " + rgb.b + ", " + (Math.round(from * 10) / 10) + ")";
|
691
|
+
useWindow.setTimeout(function() {
|
692
|
+
_this.drawArc(x, y, rgba, 1);
|
693
|
+
}, delay);
|
694
|
+
}());
|
695
|
+
from += step;
|
696
|
+
}
|
697
|
+
if (typeof key !== undefined) {
|
698
|
+
useWindow.setTimeout(function() {
|
699
|
+
_this.data.state.fading[key] = false;
|
700
|
+
}, 50 * i);
|
701
|
+
}
|
702
|
+
};
|
703
|
+
|
704
|
+
TC_Instance.prototype.timeLeft = function() {
|
705
|
+
if (this.data.paused && typeof this.data.timer === "number") {
|
706
|
+
return this.data.timer;
|
707
|
+
}
|
708
|
+
var now = new Date();
|
709
|
+
return ((this.data.attributes.ref_date - now) / 1000);
|
710
|
+
};
|
711
|
+
|
712
|
+
TC_Instance.prototype.start = function() {
|
713
|
+
useWindow.cancelAnimationFrame(this.data.animation_frame);
|
714
|
+
useWindow.clearTimeout(this.data.animation_frame)
|
715
|
+
|
716
|
+
// Check if a date was passed in html attribute or jquery data
|
717
|
+
var attr_data_date = $(this.element).data('date');
|
718
|
+
if (typeof attr_data_date === "undefined") {
|
719
|
+
attr_data_date = $(this.element).attr('data-date');
|
720
|
+
}
|
721
|
+
if (typeof attr_data_date === "string") {
|
722
|
+
this.data.attributes.ref_date = parse_date(attr_data_date);
|
723
|
+
}
|
724
|
+
// Check if this is an unpause of a timer
|
725
|
+
else if (typeof this.data.timer === "number") {
|
726
|
+
if (this.data.paused) {
|
727
|
+
this.data.attributes.ref_date = (new Date()).getTime() + (this.data.timer * 1000);
|
728
|
+
}
|
729
|
+
}
|
730
|
+
else {
|
731
|
+
// Try to get data-timer
|
732
|
+
var attr_data_timer = $(this.element).data('timer');
|
733
|
+
if (typeof attr_data_timer === "undefined") {
|
734
|
+
attr_data_timer = $(this.element).attr('data-timer');
|
735
|
+
}
|
736
|
+
if (typeof attr_data_timer === "string") {
|
737
|
+
attr_data_timer = parseFloat(attr_data_timer);
|
738
|
+
}
|
739
|
+
if (typeof attr_data_timer === "number") {
|
740
|
+
this.data.timer = attr_data_timer;
|
741
|
+
this.data.attributes.ref_date = (new Date()).getTime() + (attr_data_timer * 1000);
|
742
|
+
}
|
743
|
+
else {
|
744
|
+
// data-timer and data-date were both not set
|
745
|
+
// use config date
|
746
|
+
this.data.attributes.ref_date = this.config.ref_date;
|
747
|
+
}
|
748
|
+
}
|
749
|
+
|
750
|
+
// Start running
|
751
|
+
this.data.paused = false;
|
752
|
+
this.update.call(this);
|
753
|
+
};
|
754
|
+
|
755
|
+
TC_Instance.prototype.restart = function() {
|
756
|
+
this.data.timer = false;
|
757
|
+
this.start();
|
758
|
+
};
|
759
|
+
|
760
|
+
TC_Instance.prototype.stop = function() {
|
761
|
+
if (typeof this.data.timer === "number") {
|
762
|
+
this.data.timer = this.timeLeft(this);
|
763
|
+
}
|
764
|
+
// Stop running
|
765
|
+
this.data.paused = true;
|
766
|
+
useWindow.cancelAnimationFrame(this.data.animation_frame);
|
767
|
+
};
|
768
|
+
|
769
|
+
TC_Instance.prototype.destroy = function() {
|
770
|
+
this.clearListeners();
|
771
|
+
this.stop();
|
772
|
+
useWindow.clearInterval(this.data.interval_fallback);
|
773
|
+
this.data.interval_fallback = null;
|
774
|
+
|
775
|
+
this.container.remove();
|
776
|
+
$(this.element).removeAttr('data-tc-id');
|
777
|
+
$(this.element).removeData('tc-id');
|
778
|
+
};
|
779
|
+
|
780
|
+
TC_Instance.prototype.setOptions = function(options) {
|
781
|
+
if (this.config === null) {
|
782
|
+
this.default_options.ref_date = new Date();
|
783
|
+
this.config = $.extend(true, {}, this.default_options);
|
784
|
+
}
|
785
|
+
$.extend(true, this.config, options);
|
786
|
+
|
787
|
+
// Use window.top if use_top_frame is true
|
788
|
+
if(this.config.use_top_frame) {
|
789
|
+
useWindow = window.top;
|
790
|
+
}
|
791
|
+
else {
|
792
|
+
useWindow = window;
|
793
|
+
}
|
794
|
+
updateUsedWindow();
|
795
|
+
|
796
|
+
this.data.total_duration = this.config.total_duration;
|
797
|
+
if (typeof this.data.total_duration === "string") {
|
798
|
+
if (typeof secondsIn[this.data.total_duration] !== "undefined") {
|
799
|
+
// If set to Years, Months, Days, Hours or Minutes, fetch the secondsIn value for that
|
800
|
+
this.data.total_duration = secondsIn[this.data.total_duration];
|
801
|
+
}
|
802
|
+
else if (this.data.total_duration === "Auto") {
|
803
|
+
// If set to auto, total_duration is the size of 1 unit, of the unit type bigger than the largest shown
|
804
|
+
var unit;
|
805
|
+
for(var i = 0; i < Object.keys(this.config.time).length; i++) {
|
806
|
+
unit = Object.keys(this.config.time)[i];
|
807
|
+
if (this.config.time[unit].show) {
|
808
|
+
this.data.total_duration = secondsIn[nextUnits[unit]];
|
809
|
+
break;
|
810
|
+
}
|
811
|
+
}
|
812
|
+
}
|
813
|
+
else {
|
814
|
+
// If it's a string, but neither of the above, user screwed up.
|
815
|
+
this.data.total_duration = secondsIn["Years"];
|
816
|
+
console.error("Valid values for TimeCircles config.total_duration are either numeric, or (string) Years, Months, Days, Hours, Minutes, Auto");
|
817
|
+
}
|
818
|
+
}
|
819
|
+
};
|
820
|
+
|
821
|
+
TC_Instance.prototype.addListener = function(f, context, type) {
|
822
|
+
if (typeof f !== "function")
|
823
|
+
return;
|
824
|
+
if (typeof type === "undefined")
|
825
|
+
type = "visible";
|
826
|
+
this.listeners[type].push({func: f, scope: context});
|
827
|
+
};
|
828
|
+
|
829
|
+
TC_Instance.prototype.notifyListeners = function(unit, value, total, type) {
|
830
|
+
var listener;
|
831
|
+
for (var i = 0; i < this.listeners[type].length; i++) {
|
832
|
+
listener = this.listeners[type][i];
|
833
|
+
listener.func.apply(listener.scope, [unit, value, total]);
|
834
|
+
}
|
835
|
+
};
|
836
|
+
|
837
|
+
TC_Instance.prototype.default_options = {
|
838
|
+
ref_date: new Date(),
|
839
|
+
start: true,
|
840
|
+
animation: "smooth",
|
841
|
+
count_past_zero: true,
|
842
|
+
circle_bg_color: "#60686F",
|
843
|
+
use_background: true,
|
844
|
+
fg_width: 0.1,
|
845
|
+
bg_width: 1.2,
|
846
|
+
text_size: 0.07,
|
847
|
+
total_duration: "Auto",
|
848
|
+
direction: "Clockwise",
|
849
|
+
use_top_frame: false,
|
850
|
+
start_angle: 0,
|
851
|
+
time: {
|
852
|
+
Days: {
|
853
|
+
show: true,
|
854
|
+
text: "Days",
|
855
|
+
color: "#FC6"
|
856
|
+
},
|
857
|
+
Hours: {
|
858
|
+
show: true,
|
859
|
+
text: "Hours",
|
860
|
+
color: "#9CF"
|
861
|
+
},
|
862
|
+
Minutes: {
|
863
|
+
show: true,
|
864
|
+
text: "Minutes",
|
865
|
+
color: "#BFB"
|
866
|
+
},
|
867
|
+
Seconds: {
|
868
|
+
show: true,
|
869
|
+
text: "Seconds",
|
870
|
+
color: "#F99"
|
871
|
+
}
|
872
|
+
}
|
873
|
+
};
|
874
|
+
|
875
|
+
// Time circle class
|
876
|
+
var TC_Class = function(elements, options) {
|
877
|
+
this.elements = elements;
|
878
|
+
this.options = options;
|
879
|
+
this.foreach();
|
880
|
+
};
|
881
|
+
|
882
|
+
TC_Class.prototype.getInstance = function(element) {
|
883
|
+
var instance;
|
884
|
+
|
885
|
+
var cur_id = $(element).data("tc-id");
|
886
|
+
if (typeof cur_id === "undefined") {
|
887
|
+
cur_id = guid();
|
888
|
+
$(element).attr("data-tc-id", cur_id);
|
889
|
+
}
|
890
|
+
if (typeof TC_Instance_List[cur_id] === "undefined") {
|
891
|
+
var options = this.options;
|
892
|
+
var element_options = $(element).data('options');
|
893
|
+
if (typeof element_options === "string") {
|
894
|
+
element_options = JSON.parse(element_options);
|
895
|
+
}
|
896
|
+
if (typeof element_options === "object") {
|
897
|
+
options = $.extend(true, {}, this.options, element_options);
|
898
|
+
}
|
899
|
+
instance = new TC_Instance(element, options);
|
900
|
+
TC_Instance_List[cur_id] = instance;
|
901
|
+
}
|
902
|
+
else {
|
903
|
+
instance = TC_Instance_List[cur_id];
|
904
|
+
if (typeof this.options !== "undefined") {
|
905
|
+
instance.setOptions(this.options);
|
906
|
+
}
|
907
|
+
}
|
908
|
+
return instance;
|
909
|
+
};
|
910
|
+
|
911
|
+
TC_Class.prototype.addTime = function(seconds_to_add) {
|
912
|
+
this.foreach(function(instance) {
|
913
|
+
instance.addTime(seconds_to_add);
|
914
|
+
});
|
915
|
+
};
|
916
|
+
|
917
|
+
TC_Class.prototype.foreach = function(callback) {
|
918
|
+
var _this = this;
|
919
|
+
this.elements.each(function() {
|
920
|
+
var instance = _this.getInstance(this);
|
921
|
+
if (typeof callback === "function") {
|
922
|
+
callback(instance);
|
923
|
+
}
|
924
|
+
});
|
925
|
+
return this;
|
926
|
+
};
|
927
|
+
|
928
|
+
TC_Class.prototype.start = function() {
|
929
|
+
this.foreach(function(instance) {
|
930
|
+
instance.start();
|
931
|
+
});
|
932
|
+
return this;
|
933
|
+
};
|
934
|
+
|
935
|
+
TC_Class.prototype.stop = function() {
|
936
|
+
this.foreach(function(instance) {
|
937
|
+
instance.stop();
|
938
|
+
});
|
939
|
+
return this;
|
940
|
+
};
|
941
|
+
|
942
|
+
TC_Class.prototype.restart = function() {
|
943
|
+
this.foreach(function(instance) {
|
944
|
+
instance.restart();
|
945
|
+
});
|
946
|
+
return this;
|
947
|
+
};
|
948
|
+
|
949
|
+
TC_Class.prototype.rebuild = function() {
|
950
|
+
this.foreach(function(instance) {
|
951
|
+
instance.initialize(false);
|
952
|
+
});
|
953
|
+
return this;
|
954
|
+
};
|
955
|
+
|
956
|
+
TC_Class.prototype.getTime = function() {
|
957
|
+
return this.getInstance(this.elements[0]).timeLeft();
|
958
|
+
};
|
959
|
+
|
960
|
+
TC_Class.prototype.addListener = function(f, type) {
|
961
|
+
if (typeof type === "undefined")
|
962
|
+
type = "visible";
|
963
|
+
var _this = this;
|
964
|
+
this.foreach(function(instance) {
|
965
|
+
instance.addListener(f, _this.elements, type);
|
966
|
+
});
|
967
|
+
return this;
|
968
|
+
};
|
969
|
+
|
970
|
+
TC_Class.prototype.destroy = function() {
|
971
|
+
this.foreach(function(instance) {
|
972
|
+
instance.destroy();
|
973
|
+
});
|
974
|
+
return this;
|
975
|
+
};
|
976
|
+
|
977
|
+
TC_Class.prototype.end = function() {
|
978
|
+
return this.elements;
|
979
|
+
};
|
980
|
+
|
981
|
+
$.fn.TimeCircles = function(options) {
|
982
|
+
return new TC_Class(this, options);
|
983
|
+
};
|
984
|
+
}(jQuery));
|