dashing 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (54) hide show
  1. data/README.md +202 -0
  2. data/bin/dashing +82 -0
  3. data/javascripts/batman.jquery.js +109 -0
  4. data/javascripts/batman.js +11811 -0
  5. data/javascripts/dashing.coffee +96 -0
  6. data/javascripts/es5-shim.js +1021 -0
  7. data/javascripts/jquery.js +4 -0
  8. data/lib/dashing.rb +109 -0
  9. data/templates/dashboard/%name%.erb.tt +7 -0
  10. data/templates/job/%name%.rb +4 -0
  11. data/templates/project/Gemfile +3 -0
  12. data/templates/project/README.md +0 -0
  13. data/templates/project/assets/fonts/fontawesome-webfont.eot +0 -0
  14. data/templates/project/assets/fonts/fontawesome-webfont.svg +255 -0
  15. data/templates/project/assets/fonts/fontawesome-webfont.ttf +0 -0
  16. data/templates/project/assets/fonts/fontawesome-webfont.woff +0 -0
  17. data/templates/project/assets/images/favicon.ico +0 -0
  18. data/templates/project/assets/javascripts/application.coffee +24 -0
  19. data/templates/project/assets/javascripts/d3.v2.min.js +4 -0
  20. data/templates/project/assets/javascripts/dashing.gridster.coffee +32 -0
  21. data/templates/project/assets/javascripts/gridster/jquery.gridster.js +2890 -0
  22. data/templates/project/assets/javascripts/gridster/jquery.leanModal.min.js +5 -0
  23. data/templates/project/assets/javascripts/jquery.knob.js +646 -0
  24. data/templates/project/assets/javascripts/rickshaw.min.js +2 -0
  25. data/templates/project/assets/stylesheets/application.scss +229 -0
  26. data/templates/project/assets/stylesheets/font-awesome.css +303 -0
  27. data/templates/project/assets/stylesheets/jquery.gridster.css +57 -0
  28. data/templates/project/config.ru +18 -0
  29. data/templates/project/dashboards/layout.erb +32 -0
  30. data/templates/project/dashboards/sample.erb +25 -0
  31. data/templates/project/jobs/buzzwords.rb +9 -0
  32. data/templates/project/jobs/convergence.rb +13 -0
  33. data/templates/project/jobs/sample.rb +9 -0
  34. data/templates/project/lib/.empty_directory +1 -0
  35. data/templates/project/public/.empty_directory +1 -0
  36. data/templates/project/widgets/graph/graph.coffee +26 -0
  37. data/templates/project/widgets/graph/graph.html +5 -0
  38. data/templates/project/widgets/graph/graph.scss +51 -0
  39. data/templates/project/widgets/list/list.coffee +13 -0
  40. data/templates/project/widgets/list/list.html +15 -0
  41. data/templates/project/widgets/list/list.scss +52 -0
  42. data/templates/project/widgets/meter/meter.coffee +14 -0
  43. data/templates/project/widgets/meter/meter.html +5 -0
  44. data/templates/project/widgets/meter/meter.scss +37 -0
  45. data/templates/project/widgets/number/number.coffee +25 -0
  46. data/templates/project/widgets/number/number.html +9 -0
  47. data/templates/project/widgets/number/number.scss +35 -0
  48. data/templates/project/widgets/text/text.coffee +1 -0
  49. data/templates/project/widgets/text/text.html +5 -0
  50. data/templates/project/widgets/text/text.scss +25 -0
  51. data/templates/widget/%name%/%name%.coffee.tt +10 -0
  52. data/templates/widget/%name%/%name%.html +1 -0
  53. data/templates/widget/%name%/%name%.scss.tt +3 -0
  54. metadata +187 -0
@@ -0,0 +1,5 @@
1
+ // leanModal v1.1 by Ray Stone - http://finelysliced.com.au
2
+ // Dual licensed under the MIT and GPL
3
+
4
+ (function($){$.fn.extend({leanModal:function(options){var defaults={top:100,overlay:0.5,closeButton:null};var overlay=$("<div id='lean_overlay'></div>");$("body").append(overlay);options=$.extend(defaults,options);return this.each(function(){var o=options;$(this).click(function(e){var modal_id=$(this).attr("href");$("#lean_overlay").click(function(){close_modal(modal_id)});$(o.closeButton).click(function(){close_modal(modal_id)});var modal_height=$(modal_id).outerHeight();var modal_width=$(modal_id).outerWidth();
5
+ $("#lean_overlay").css({"display":"block",opacity:0});$("#lean_overlay").fadeTo(200,o.overlay);$(modal_id).css({"display":"block","position":"fixed","opacity":0,"z-index":11000,"left":50+"%","margin-left":-(modal_width/2)+"px","top":o.top+"px"});$(modal_id).fadeTo(200,1);e.preventDefault()})});function close_modal(modal_id){$("#lean_overlay").fadeOut(200);$(modal_id).css({"display":"none"})}}})})(jQuery);
@@ -0,0 +1,646 @@
1
+ /*!jQuery Knob*/
2
+ /**
3
+ * Downward compatible, touchable dial
4
+ *
5
+ * Version: 1.2.0 (15/07/2012)
6
+ * Requires: jQuery v1.7+
7
+ *
8
+ * Copyright (c) 2012 Anthony Terrien
9
+ * Under MIT and GPL licenses:
10
+ * http://www.opensource.org/licenses/mit-license.php
11
+ * http://www.gnu.org/licenses/gpl.html
12
+ *
13
+ * Thanks to vor, eskimoblood, spiffistan, FabrizioC
14
+ */
15
+ $(function () {
16
+
17
+ /**
18
+ * Kontrol library
19
+ */
20
+ "use strict";
21
+
22
+ /**
23
+ * Definition of globals and core
24
+ */
25
+ var k = {}, // kontrol
26
+ max = Math.max,
27
+ min = Math.min;
28
+
29
+ k.c = {};
30
+ k.c.d = $(document);
31
+ k.c.t = function (e) {
32
+ return e.originalEvent.touches.length - 1;
33
+ };
34
+
35
+ /**
36
+ * Kontrol Object
37
+ *
38
+ * Definition of an abstract UI control
39
+ *
40
+ * Each concrete component must call this one.
41
+ * <code>
42
+ * k.o.call(this);
43
+ * </code>
44
+ */
45
+ k.o = function () {
46
+ var s = this;
47
+
48
+ this.o = null; // array of options
49
+ this.$ = null; // jQuery wrapped element
50
+ this.i = null; // mixed HTMLInputElement or array of HTMLInputElement
51
+ this.g = null; // 2D graphics context for 'pre-rendering'
52
+ this.v = null; // value ; mixed array or integer
53
+ this.cv = null; // change value ; not commited value
54
+ this.x = 0; // canvas x position
55
+ this.y = 0; // canvas y position
56
+ this.$c = null; // jQuery canvas element
57
+ this.c = null; // rendered canvas context
58
+ this.t = 0; // touches index
59
+ this.isInit = false;
60
+ this.fgColor = null; // main color
61
+ this.pColor = null; // previous color
62
+ this.dH = null; // draw hook
63
+ this.cH = null; // change hook
64
+ this.eH = null; // cancel hook
65
+ this.rH = null; // release hook
66
+
67
+ this.run = function () {
68
+ var cf = function (e, conf) {
69
+ var k;
70
+ for (k in conf) {
71
+ s.o[k] = conf[k];
72
+ }
73
+ s.init();
74
+ s._configure()
75
+ ._draw();
76
+ };
77
+
78
+ if(this.$.data('kontroled')) return;
79
+ this.$.data('kontroled', true);
80
+
81
+ this.extend();
82
+ this.o = $.extend(
83
+ {
84
+ // Config
85
+ min : this.$.data('min') || 0,
86
+ max : this.$.data('max') || 100,
87
+ stopper : true,
88
+ readOnly : this.$.data('readonly'),
89
+
90
+ // UI
91
+ cursor : (this.$.data('cursor') === true && 30)
92
+ || this.$.data('cursor')
93
+ || 0,
94
+ thickness : this.$.data('thickness') || 0.35,
95
+ width : this.$.data('width') || 200,
96
+ height : this.$.data('height') || 200,
97
+ displayInput : this.$.data('displayinput') == null || this.$.data('displayinput'),
98
+ displayPrevious : this.$.data('displayprevious'),
99
+ fgColor : this.$.data('fgcolor') || '#87CEEB',
100
+ inline : false,
101
+
102
+ // Hooks
103
+ draw : null, // function () {}
104
+ change : null, // function (value) {}
105
+ cancel : null, // function () {}
106
+ release : null // function (value) {}
107
+ }, this.o
108
+ );
109
+
110
+ // routing value
111
+ if(this.$.is('fieldset')) {
112
+
113
+ // fieldset = array of integer
114
+ this.v = {};
115
+ this.i = this.$.find('input')
116
+ this.i.each(function(k) {
117
+ var $this = $(this);
118
+ s.i[k] = $this;
119
+ s.v[k] = $this.val();
120
+
121
+ $this.bind(
122
+ 'change'
123
+ , function () {
124
+ var val = {};
125
+ val[k] = $this.val();
126
+ s.val(val);
127
+ }
128
+ );
129
+ });
130
+ this.$.find('legend').remove();
131
+
132
+ } else {
133
+ // input = integer
134
+ this.i = this.$;
135
+ this.v = this.$.val();
136
+ (this.v == '') && (this.v = this.o.min);
137
+
138
+ this.$.bind(
139
+ 'change'
140
+ , function () {
141
+ s.val(s.$.val());
142
+ }
143
+ );
144
+ }
145
+
146
+ (!this.o.displayInput) && this.$.hide();
147
+
148
+ this.$c = $('<canvas width="' +
149
+ this.o.width + 'px" height="' +
150
+ this.o.height + 'px"></canvas>');
151
+ this.c = this.$c[0].getContext("2d");
152
+
153
+ this.$
154
+ .wrap($('<div style="' + (this.o.inline ? 'display:inline;' : '') +
155
+ 'width:' + this.o.width + 'px;height:' +
156
+ this.o.height + 'px;"></div>'))
157
+ .before(this.$c);
158
+
159
+ if (this.v instanceof Object) {
160
+ this.cv = {};
161
+ this.copy(this.v, this.cv);
162
+ } else {
163
+ this.cv = this.v;
164
+ }
165
+
166
+ this.$
167
+ .bind("configure", cf)
168
+ .parent()
169
+ .bind("configure", cf);
170
+
171
+ this._listen()
172
+ ._configure()
173
+ ._xy()
174
+ .init();
175
+
176
+ this.isInit = true;
177
+
178
+ this._draw();
179
+
180
+ return this;
181
+ };
182
+
183
+ this._draw = function () {
184
+
185
+ // canvas pre-rendering
186
+ var d = true,
187
+ c = document.createElement('canvas');
188
+
189
+ c.width = s.o.width;
190
+ c.height = s.o.height;
191
+ s.g = c.getContext('2d');
192
+
193
+ s.clear();
194
+
195
+ s.dH
196
+ && (d = s.dH());
197
+
198
+ (d !== false) && s.draw();
199
+
200
+ s.c.drawImage(c, 0, 0);
201
+ c = null;
202
+ };
203
+
204
+ this._touch = function (e) {
205
+
206
+ var touchMove = function (e) {
207
+
208
+ var v = s.xy2val(
209
+ e.originalEvent.touches[s.t].pageX,
210
+ e.originalEvent.touches[s.t].pageY
211
+ );
212
+
213
+ if (v == s.cv) return;
214
+
215
+ if (
216
+ s.cH
217
+ && (s.cH(v) === false)
218
+ ) return;
219
+
220
+
221
+ s.change(v);
222
+ s._draw();
223
+ };
224
+
225
+ // get touches index
226
+ this.t = k.c.t(e);
227
+
228
+ // First touch
229
+ touchMove(e);
230
+
231
+ // Touch events listeners
232
+ k.c.d
233
+ .bind("touchmove.k", touchMove)
234
+ .bind(
235
+ "touchend.k"
236
+ , function () {
237
+ k.c.d.unbind('touchmove.k touchend.k');
238
+
239
+ if (
240
+ s.rH
241
+ && (s.rH(s.cv) === false)
242
+ ) return;
243
+
244
+ s.val(s.cv);
245
+ }
246
+ );
247
+
248
+ return this;
249
+ };
250
+
251
+ this._mouse = function (e) {
252
+
253
+ var mouseMove = function (e) {
254
+ var v = s.xy2val(e.pageX, e.pageY);
255
+ if (v == s.cv) return;
256
+
257
+ if (
258
+ s.cH
259
+ && (s.cH(v) === false)
260
+ ) return;
261
+
262
+ s.change(v);
263
+ s._draw();
264
+ };
265
+
266
+ // First click
267
+ mouseMove(e);
268
+
269
+ // Mouse events listeners
270
+ k.c.d
271
+ .bind("mousemove.k", mouseMove)
272
+ .bind(
273
+ // Escape key cancel current change
274
+ "keyup.k"
275
+ , function (e) {
276
+ if (e.keyCode === 27) {
277
+ k.c.d.unbind("mouseup.k mousemove.k keyup.k");
278
+
279
+ if (
280
+ s.eH
281
+ && (s.eH() === false)
282
+ ) return;
283
+
284
+ s.cancel();
285
+ }
286
+ }
287
+ )
288
+ .bind(
289
+ "mouseup.k"
290
+ , function (e) {
291
+ k.c.d.unbind('mousemove.k mouseup.k keyup.k');
292
+
293
+ if (
294
+ s.rH
295
+ && (s.rH(s.cv) === false)
296
+ ) return;
297
+
298
+ s.val(s.cv);
299
+ }
300
+ );
301
+
302
+ return this;
303
+ };
304
+
305
+ this._xy = function () {
306
+ var o = this.$c.offset();
307
+ this.x = o.left;
308
+ this.y = o.top;
309
+ return this;
310
+ };
311
+
312
+ this._listen = function () {
313
+
314
+ if (!this.o.readOnly) {
315
+ this.$c
316
+ .bind(
317
+ "mousedown"
318
+ , function (e) {
319
+ e.preventDefault();
320
+ s._xy()._mouse(e);
321
+ }
322
+ )
323
+ .bind(
324
+ "touchstart"
325
+ , function (e) {
326
+ e.preventDefault();
327
+ s._xy()._touch(e);
328
+ }
329
+ );
330
+ this.listen();
331
+ } else {
332
+ this.$.attr('readonly', 'readonly');
333
+ }
334
+
335
+ return this;
336
+ };
337
+
338
+ this._configure = function () {
339
+
340
+ // Hooks
341
+ if (this.o.draw) this.dH = this.o.draw;
342
+ if (this.o.change) this.cH = this.o.change;
343
+ if (this.o.cancel) this.eH = this.o.cancel;
344
+ if (this.o.release) this.rH = this.o.release;
345
+
346
+ if (this.o.displayPrevious) {
347
+ this.pColor = this.h2rgba(this.o.fgColor, "0.4");
348
+ this.fgColor = this.h2rgba(this.o.fgColor, "0.6");
349
+ } else {
350
+ this.fgColor = this.o.fgColor;
351
+ }
352
+
353
+ return this;
354
+ };
355
+
356
+ this._clear = function () {
357
+ this.$c[0].width = this.$c[0].width;
358
+ };
359
+
360
+ // Abstract methods
361
+ this.listen = function () {}; // on start, one time
362
+ this.extend = function () {}; // each time configure triggered
363
+ this.init = function () {}; // each time configure triggered
364
+ this.change = function (v) {}; // on change
365
+ this.val = function (v) {}; // on release
366
+ this.xy2val = function (x, y) {}; //
367
+ this.draw = function () {}; // on change / on release
368
+ this.clear = function () { this._clear(); };
369
+
370
+ // Utils
371
+ this.h2rgba = function (h, a) {
372
+ var rgb;
373
+ h = h.substring(1,7)
374
+ rgb = [parseInt(h.substring(0,2),16)
375
+ ,parseInt(h.substring(2,4),16)
376
+ ,parseInt(h.substring(4,6),16)];
377
+ return "rgba(" + rgb[0] + "," + rgb[1] + "," + rgb[2] + "," + a + ")";
378
+ };
379
+
380
+ this.copy = function (f, t) {
381
+ for (var i in f) { t[i] = f[i]; }
382
+ };
383
+ };
384
+
385
+
386
+ /**
387
+ * k.Dial
388
+ */
389
+ k.Dial = function () {
390
+ k.o.call(this);
391
+
392
+ this.startAngle = null;
393
+ this.xy = null;
394
+ this.radius = null;
395
+ this.lineWidth = null;
396
+ this.cursorExt = null;
397
+ this.w2 = null;
398
+ this.PI2 = 2*Math.PI;
399
+
400
+ this.extend = function () {
401
+ this.o = $.extend(
402
+ {
403
+ bgColor : this.$.data('bgcolor') || '#EEEEEE',
404
+ angleOffset : this.$.data('angleoffset') || 0,
405
+ angleArc : this.$.data('anglearc') || 360,
406
+ inline : true
407
+ }, this.o
408
+ );
409
+ };
410
+
411
+ this.val = function (v) {
412
+ if (null != v) {
413
+ this.cv = this.o.stopper ? max(min(v, this.o.max), this.o.min) : v;
414
+ this.v = this.cv;
415
+ this.$.val(this.v);
416
+ this._draw();
417
+ } else {
418
+ return this.v;
419
+ }
420
+ };
421
+
422
+ this.xy2val = function (x, y) {
423
+ var a, ret;
424
+
425
+ a = Math.atan2(
426
+ x - (this.x + this.w2)
427
+ , - (y - this.y - this.w2)
428
+ ) - this.angleOffset;
429
+
430
+ if(this.angleArc != this.PI2 && (a < 0) && (a > -0.5)) {
431
+ // if isset angleArc option, set to min if .5 under min
432
+ a = 0;
433
+ } else if (a < 0) {
434
+ a += this.PI2;
435
+ }
436
+
437
+ ret = ~~ (0.5 + (a * (this.o.max - this.o.min) / this.angleArc))
438
+ + this.o.min;
439
+
440
+ this.o.stopper
441
+ && (ret = max(min(ret, this.o.max), this.o.min));
442
+
443
+ return ret;
444
+ };
445
+
446
+ this.listen = function () {
447
+ // bind MouseWheel
448
+ var s = this,
449
+ mw = function (e) {
450
+ e.preventDefault();
451
+
452
+ var ori = e.originalEvent
453
+ ,deltaX = ori.detail || ori.wheelDeltaX
454
+ ,deltaY = ori.detail || ori.wheelDeltaY
455
+ ,v = parseInt(s.$.val()) + (deltaX>0 || deltaY>0 ? 1 : deltaX<0 || deltaY<0 ? -1 : 0);
456
+
457
+ if (
458
+ s.cH
459
+ && (s.cH(v) === false)
460
+ ) return;
461
+
462
+ s.val(v);
463
+ }
464
+ , kval, to, m = 1, kv = {37:-1, 38:1, 39:1, 40:-1};
465
+
466
+ this.$
467
+ .bind(
468
+ "keydown"
469
+ ,function (e) {
470
+ var kc = e.keyCode;
471
+ kval = parseInt(String.fromCharCode(kc));
472
+
473
+ if (isNaN(kval)) {
474
+
475
+ (kc !== 13) // enter
476
+ && (kc !== 8) // bs
477
+ && (kc !== 9) // tab
478
+ && (kc !== 189) // -
479
+ && e.preventDefault();
480
+
481
+ // arrows
482
+ if ($.inArray(kc,[37,38,39,40]) > -1) {
483
+ e.preventDefault();
484
+
485
+ var v = parseInt(s.$.val()) + kv[kc] * m;
486
+
487
+ s.o.stopper
488
+ && (v = max(min(v, s.o.max), s.o.min));
489
+
490
+ s.change(v);
491
+ s._draw();
492
+
493
+ // long time keydown speed-up
494
+ to = window.setTimeout(
495
+ function () { m*=2; }
496
+ ,30
497
+ );
498
+ }
499
+ }
500
+ }
501
+ )
502
+ .bind(
503
+ "keyup"
504
+ ,function (e) {
505
+ if (isNaN(kval)) {
506
+ if (to) {
507
+ window.clearTimeout(to);
508
+ to = null;
509
+ m = 1;
510
+ s.val(s.$.val());
511
+ }
512
+ } else {
513
+ // kval postcond
514
+ (s.$.val() > s.o.max && s.$.val(s.o.max))
515
+ || (s.$.val() < s.o.min && s.$.val(s.o.min));
516
+ }
517
+
518
+ }
519
+ );
520
+
521
+ this.$c.bind("mousewheel DOMMouseScroll", mw);
522
+ this.$.bind("mousewheel DOMMouseScroll", mw)
523
+ };
524
+
525
+ this.init = function () {
526
+
527
+ if (
528
+ this.v < this.o.min
529
+ || this.v > this.o.max
530
+ ) this.v = this.o.min;
531
+
532
+ this.$.val(this.v);
533
+ this.w2 = this.o.width / 2;
534
+ this.cursorExt = this.o.cursor / 100;
535
+ this.xy = this.w2;
536
+ this.lineWidth = this.xy * this.o.thickness;
537
+ this.radius = this.xy - this.lineWidth / 2;
538
+
539
+ this.o.angleOffset
540
+ && (this.o.angleOffset = isNaN(this.o.angleOffset) ? 0 : this.o.angleOffset);
541
+
542
+ this.o.angleArc
543
+ && (this.o.angleArc = isNaN(this.o.angleArc) ? this.PI2 : this.o.angleArc);
544
+
545
+ // deg to rad
546
+ this.angleOffset = this.o.angleOffset * Math.PI / 180;
547
+ this.angleArc = this.o.angleArc * Math.PI / 180;
548
+
549
+ // compute start and end angles
550
+ this.startAngle = 1.5 * Math.PI + this.angleOffset;
551
+ this.endAngle = 1.5 * Math.PI + this.angleOffset + this.angleArc;
552
+
553
+ var s = max(
554
+ String(Math.abs(this.o.max)).length
555
+ , String(Math.abs(this.o.min)).length
556
+ , 2
557
+ ) + 2;
558
+
559
+ this.o.displayInput
560
+ && this.i.css({
561
+ 'width' : ((this.o.width / 2 + 4) >> 0) + 'px'
562
+ ,'height' : ((this.o.width / 3) >> 0) + 'px'
563
+ ,'position' : 'absolute'
564
+ ,'vertical-align' : 'middle'
565
+ ,'margin-top' : ((this.o.width / 3) >> 0) + 'px'
566
+ ,'margin-left' : '-' + ((this.o.width * 3 / 4 + 2) >> 0) + 'px'
567
+ ,'border' : 0
568
+ ,'background' : 'none'
569
+ ,'font' : 'bold ' + ((this.o.width / s) >> 0) + 'px Arial'
570
+ ,'text-align' : 'center'
571
+ ,'color' : this.o.fgColor
572
+ ,'padding' : '0px'
573
+ ,'-webkit-appearance': 'none'
574
+ })
575
+ || this.i.css({
576
+ 'width' : '0px'
577
+ ,'visibility' : 'hidden'
578
+ });
579
+ };
580
+
581
+ this.change = function (v) {
582
+ this.cv = v;
583
+ this.$.val(v);
584
+ };
585
+
586
+ this.angle = function (v) {
587
+ return (v - this.o.min) * this.angleArc / (this.o.max - this.o.min);
588
+ };
589
+
590
+ this.draw = function () {
591
+
592
+ var c = this.g, // context
593
+ a = this.angle(this.cv) // Angle
594
+ , sat = this.startAngle // Start angle
595
+ , eat = sat + a // End angle
596
+ , sa, ea // Previous angles
597
+ , r = 1;
598
+
599
+ c.lineWidth = this.lineWidth;
600
+
601
+ this.o.cursor
602
+ && (sat = eat - this.cursorExt)
603
+ && (eat = eat + this.cursorExt);
604
+
605
+ c.beginPath();
606
+ c.strokeStyle = this.o.bgColor;
607
+ c.arc(this.xy, this.xy, this.radius, this.endAngle, this.startAngle, true);
608
+ c.stroke();
609
+
610
+ if (this.o.displayPrevious) {
611
+ ea = this.startAngle + this.angle(this.v);
612
+ sa = this.startAngle;
613
+ this.o.cursor
614
+ && (sa = ea - this.cursorExt)
615
+ && (ea = ea + this.cursorExt);
616
+
617
+ c.beginPath();
618
+ c.strokeStyle = this.pColor;
619
+ c.arc(this.xy, this.xy, this.radius, sa, ea, false);
620
+ c.stroke();
621
+ r = (this.cv == this.v);
622
+ }
623
+
624
+ c.beginPath();
625
+ c.strokeStyle = r ? this.o.fgColor : this.fgColor ;
626
+ c.arc(this.xy, this.xy, this.radius, sat, eat, false);
627
+ c.stroke();
628
+ };
629
+
630
+ this.cancel = function () {
631
+ this.val(this.v);
632
+ };
633
+ };
634
+
635
+ $.fn.dial = $.fn.knob = function (o) {
636
+ return this.each(
637
+ function () {
638
+ var d = new k.Dial();
639
+ d.o = o;
640
+ d.$ = $(this);
641
+ d.run();
642
+ }
643
+ ).parent();
644
+ };
645
+
646
+ });