ruote-kit 2.1.10 → 2.1.11

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (91) hide show
  1. data/.gitignore +2 -0
  2. data/CHANGELOG.txt +10 -0
  3. data/Gemfile +21 -5
  4. data/LICENSE.txt +20 -0
  5. data/README.rdoc +132 -80
  6. data/Rakefile +4 -15
  7. data/TODO.txt +12 -0
  8. data/config.ru +22 -14
  9. data/lib/ruote-kit/application.rb +46 -22
  10. data/lib/ruote-kit/helpers/json_helpers.rb +280 -0
  11. data/lib/ruote-kit/helpers/link_helpers.rb +117 -0
  12. data/lib/ruote-kit/helpers/misc_helpers.rb +35 -0
  13. data/lib/ruote-kit/helpers/pagination_helpers.rb +30 -0
  14. data/lib/ruote-kit/helpers/render_helpers.rb +39 -92
  15. data/lib/ruote-kit/public/_ruote/images/favicon.ico +0 -0
  16. data/lib/ruote-kit/public/_ruote/images/ruote.png +0 -0
  17. data/lib/ruote-kit/public/_ruote/images/ruote_buttons.png +0 -0
  18. data/lib/ruote-kit/public/_ruote/javascripts/jquery-1.4.2.min.js +154 -0
  19. data/lib/ruote-kit/public/_ruote/javascripts/rk.js +40 -0
  20. data/lib/ruote-kit/public/_ruote/javascripts/ruote-fluo-editor.js +548 -0
  21. data/lib/ruote-kit/public/_ruote/javascripts/ruote-fluo.js +32 -1
  22. data/lib/ruote-kit/public/_ruote/stylesheets/reset.css +53 -0
  23. data/lib/ruote-kit/public/_ruote/stylesheets/rk.css +355 -16
  24. data/lib/ruote-kit/public/_ruote/stylesheets/ruote-fluo-editor.css +108 -0
  25. data/lib/ruote-kit/resources/errors.rb +46 -43
  26. data/lib/ruote-kit/resources/expressions.rb +92 -35
  27. data/lib/ruote-kit/resources/participants.rb +53 -0
  28. data/lib/ruote-kit/resources/processes.rb +68 -36
  29. data/lib/ruote-kit/resources/schedules.rb +27 -0
  30. data/lib/ruote-kit/resources/workitems.rb +93 -31
  31. data/lib/ruote-kit/spec/ruote_helpers.rb +25 -16
  32. data/lib/ruote-kit/version.rb +3 -1
  33. data/lib/ruote-kit/views/_pagination.html.haml +38 -0
  34. data/lib/ruote-kit/views/_tree_editor.html.haml +52 -0
  35. data/lib/ruote-kit/views/error.html.haml +69 -0
  36. data/lib/ruote-kit/views/errors.html.haml +28 -12
  37. data/lib/ruote-kit/views/expression.html.haml +161 -30
  38. data/lib/ruote-kit/views/expressions.html.haml +26 -21
  39. data/lib/ruote-kit/views/http_error.html.haml +11 -0
  40. data/lib/ruote-kit/views/index.html.haml +4 -0
  41. data/lib/ruote-kit/views/layout.html.haml +52 -32
  42. data/lib/ruote-kit/views/participants.html.haml +79 -0
  43. data/lib/ruote-kit/views/process.html.haml +109 -42
  44. data/lib/ruote-kit/views/process_launched.html.haml +6 -2
  45. data/lib/ruote-kit/views/processes.html.haml +55 -24
  46. data/lib/ruote-kit/views/processes_new.html.haml +36 -0
  47. data/lib/ruote-kit/views/schedules.html.haml +42 -0
  48. data/lib/ruote-kit/views/workitem.html.haml +83 -29
  49. data/lib/ruote-kit/views/workitems.html.haml +42 -19
  50. data/lib/ruote-kit.rb +17 -88
  51. data/ruote-kit.gemspec +68 -80
  52. data/spec/it_has_an_engine.rb +69 -0
  53. data/spec/resources/errors_spec.rb +198 -270
  54. data/spec/resources/expressions_spec.rb +308 -52
  55. data/spec/resources/index_spec.rb +28 -16
  56. data/spec/resources/participants_spec.rb +102 -0
  57. data/spec/resources/processes_spec.rb +218 -104
  58. data/spec/resources/schedules_spec.rb +97 -0
  59. data/spec/resources/workitems_spec.rb +195 -100
  60. data/spec/ruote-kit_configure_spec.rb +32 -75
  61. data/spec/spec.opts +0 -1
  62. data/spec/spec_helper.rb +31 -92
  63. data/spec/webapp_helpers_spec.rb +309 -0
  64. metadata +87 -152
  65. data/lib/ruote-kit/configuration.rb +0 -83
  66. data/lib/ruote-kit/helpers/engine_helpers.rb +0 -24
  67. data/lib/ruote-kit/helpers/form_helpers.rb +0 -11
  68. data/lib/ruote-kit/helpers/launch_item_parser.rb +0 -59
  69. data/lib/ruote-kit/helpers/navigation_helpers.rb +0 -54
  70. data/lib/ruote-kit/helpers.rb +0 -9
  71. data/lib/ruote-kit/public/_ruote/images/bg.gif +0 -0
  72. data/lib/ruote-kit/public/_ruote/images/bg_button_left.gif +0 -0
  73. data/lib/ruote-kit/public/_ruote/images/bg_button_left_cancel.gif +0 -0
  74. data/lib/ruote-kit/public/_ruote/images/bg_button_left_submit.gif +0 -0
  75. data/lib/ruote-kit/public/_ruote/images/bg_button_right.gif +0 -0
  76. data/lib/ruote-kit/public/_ruote/javascripts/SimplyButtons.js +0 -191
  77. data/lib/ruote-kit/public/_ruote/javascripts/fluo-dial.js +0 -149
  78. data/lib/ruote-kit/public/_ruote/stylesheets/SimplyButtons.css +0 -226
  79. data/lib/ruote-kit/public/_ruote/stylesheets/base.css +0 -336
  80. data/lib/ruote-kit/public/_ruote/stylesheets/style.css +0 -393
  81. data/lib/ruote-kit/views/launch_process.html.haml +0 -19
  82. data/lib/ruote-kit/views/process_failed_to_launch.html.haml +0 -7
  83. data/lib/ruote-kit/views/resource_not_found.html.haml +0 -7
  84. data/spec/helpers/render_helpers_spec.rb +0 -214
  85. data/spec/ruote-kit_spec.rb +0 -4
  86. data/spec/views/expressions.html.haml_spec.rb +0 -31
  87. data/spec/views/launch_process.html.haml_spec.rb +0 -22
  88. data/spec/views/process.html.haml_spec.rb +0 -17
  89. data/spec/views/process_launched.html.haml_spec.rb +0 -16
  90. data/spec/views/processes.html.haml_spec.rb +0 -31
  91. data/spec/views/workitems.html.haml_spec.rb +0 -69
@@ -0,0 +1,548 @@
1
+
2
+ /*
3
+ * Ruote - open source ruby workflow engine
4
+ * (c) 2005-2010 John Mettraux
5
+ *
6
+ * Ruote is freely distributable under the terms of the MIT license.
7
+ * For details, see the ruote web site: http://ruote.rubyforge.org
8
+ *
9
+ * This piece of hack was created during the RubyKaigi2008,
10
+ * between Tsukuba and Akihabara.
11
+ */
12
+
13
+ //var flow = [ 'process-definition', { 'name': 'toto', 'revision': '1.0' }, [
14
+ // [ 'sequence', {}, [
15
+ // [ 'participant', { 'ref': 'alpha' }, [] ],
16
+ // [ 'bravo', {}, [] ]
17
+ // ]]
18
+ // ]
19
+ //]
20
+
21
+ try {
22
+ HTMLElement.prototype.firstChildOfClass = function (className) {
23
+ for (var i=0; i < this.childNodes.length; i++) {
24
+ var c = this.childNodes[i];
25
+ if (c.className == className) return c;
26
+ }
27
+ return null;
28
+ }
29
+ } catch (e) {
30
+ // when testing via spidermonkey
31
+ }
32
+
33
+ String.prototype.tstrip = function () {
34
+ var s = this;
35
+ while (s.charAt(0) == ' ') s = s.substring(1);
36
+ while (s.charAt(s.length - 1) == ' ') s = s.substring(0, s.length - 1);
37
+ return s;
38
+ }
39
+
40
+ var FluoEditor = function () {
41
+
42
+ var TEXTS = {
43
+ add_child_expression: 'add a child expression',
44
+ cut_expression: 'cut expression',
45
+ moveup_expression: 'move expression up',
46
+ movedown_expression: 'move expression down',
47
+ paste_expression: 'paste expression here'
48
+ };
49
+
50
+ // it's easy to override this var to let FluoEditor point to another root
51
+ //
52
+ // FluoEditor.imageRoot = 'http://my.image.server.exmaple.com/img'
53
+ //
54
+ var imageRoot = '/images';
55
+
56
+ var Attributes = function() {
57
+
58
+ function tryParse (s) {
59
+ try { return JSON.parse(s); } catch (e) {}
60
+ return undefined;
61
+ }
62
+
63
+ function parse (s) {
64
+
65
+ s = s.tstrip();
66
+
67
+ var r = tryParse("{" + s + "}");
68
+ if (r != undefined) return r;
69
+
70
+ var head = undefined;
71
+ var tail = undefined;
72
+
73
+ var m = s.match(/^([^",]+)(.*)$/)
74
+ if (m) {
75
+ r = tryParse(m[1]);
76
+ if (r != undefined) head = r;
77
+ else head = tryParse('"' + m[1] + '"');
78
+ tail = m[2];
79
+ }
80
+ else {
81
+ for (var i = 1; i <= s.length; i++) {
82
+ r = tryParse(s.slice(0, i));
83
+ if (r != undefined) {
84
+ head = r;
85
+ break;
86
+ }
87
+ }
88
+ tail = s.slice(i);
89
+ }
90
+
91
+ var h = {};
92
+ h[head] = null;
93
+ m = tail.match(/^[ ,]*(.*)$/);
94
+ var hh = tryParse("{" + m[1] + "}");
95
+ for (var k in hh) { h[k] = hh[k]; }
96
+
97
+ return h;
98
+ }
99
+
100
+ return { parse: parse };
101
+ }();
102
+
103
+ var ExpressionHead = function () {
104
+
105
+ function createButton (rfeClass, tooltip, callback) {
106
+
107
+ var i = document.createElement('a');
108
+ i.callback = callback;
109
+ i.className = 'rfe_button ' + rfeClass;
110
+ i.setAttribute('href', '');
111
+ i.setAttribute('title', tooltip);
112
+ i.setAttribute('onclick', 'this.callback(); return false;');
113
+ return i;
114
+ }
115
+
116
+ function addHeadButtons (expdiv) {
117
+
118
+ var outOpacity = 0.0;
119
+
120
+ var buttons = document.createElement('span');
121
+ buttons.className = 'rfe_buttons';
122
+ buttons.style.opacity = outOpacity;
123
+
124
+ var root = findRfeRoot(expdiv);
125
+
126
+ expdiv.onmouseover = function () {
127
+ buttons.style.opacity = 1.0;
128
+ if (root.onOver) root.onOver(computeExpId(expdiv.parentNode));
129
+ };
130
+ expdiv.onmouseout = function () {
131
+ buttons.style.opacity = outOpacity;
132
+ if (root.onOver) root.onOver(null);
133
+ };
134
+
135
+ buttons.appendChild(createButton(
136
+ 'rfe_add',
137
+ FluoEditor.TEXTS.add_child_expression,
138
+ function () {
139
+ FluoEditor.addExpression(expdiv.parentNode, [ '---', {}, [] ]);
140
+ }));
141
+
142
+ if (expdiv.parentNode.parentNode != root) {
143
+
144
+ buttons.appendChild(createButton(
145
+ 'rfe_cut',
146
+ FluoEditor.TEXTS.cut_expression,
147
+ function () {
148
+ FluoEditor.removeExpression(expdiv.parentNode);
149
+ }));
150
+ buttons.appendChild(createButton(
151
+ 'rfe_moveup',
152
+ FluoEditor.TEXTS.moveup_expression,
153
+ function () {
154
+ FluoEditor.moveExpression(expdiv.parentNode, -1);
155
+ buttons.style.opacity = outOpacity;
156
+ }));
157
+ buttons.appendChild(createButton(
158
+ 'rfe_movedown',
159
+ FluoEditor.TEXTS.movedown_expression,
160
+ function () {
161
+ FluoEditor.moveExpression(expdiv.parentNode, +1);
162
+ buttons.style.opacity = outOpacity;
163
+ }));
164
+ buttons.appendChild(createButton(
165
+ 'rfe_paste',
166
+ FluoEditor.TEXTS.paste_expression,
167
+ function () {
168
+ var clip = document._rfe_clipboard;
169
+ if (clip) FluoEditor.insertExpression(expdiv.parentNode, clip);
170
+ }));
171
+ }
172
+
173
+ expdiv.appendChild(buttons);
174
+ }
175
+
176
+ var headPattern = /^(\S+)(.*)$/;
177
+
178
+ function renderAttributes (h) {
179
+
180
+ //var keys = [];
181
+ //for (var k in h) keys.push(k);
182
+ //keys = keys.sort();
183
+ //s = '';
184
+ //for (var i = 0; i < keys.length; i++) {
185
+ // var k = keys[i];
186
+ // s += k;
187
+ // var v = JSON.stringify(h[k]);
188
+ // if (v != 'null') s += (': ' + v);
189
+ // s += ', ';
190
+ //}
191
+ //if (s.length > 1) s = s.substring(0, s.length - 2);
192
+ //return s;
193
+
194
+ var a = [];
195
+
196
+ for (var k in h) {
197
+ var v = h[k];
198
+ if (v == null) {
199
+ a.push(JSON.stringify(k));
200
+ break;
201
+ }
202
+ }
203
+ for (var k in h) {
204
+ var v = h[k];
205
+ if (v == null) continue;
206
+ a.push(JSON.stringify(k) + ': ' + JSON.stringify(v));
207
+ }
208
+
209
+ return a.join(', ');
210
+ }
211
+
212
+ return {
213
+
214
+ render: function (node, exp) {
215
+
216
+ var expname = exp[0];
217
+
218
+ var text = '';
219
+ if ((typeof exp[2][0]) == 'string') text = exp[2].shift();
220
+
221
+ var atts = renderAttributes(exp[1]);
222
+
223
+ var d = document.createElement('div');
224
+ d.setAttribute('class', 'rfe_exp');
225
+ node.appendChild(d);
226
+
227
+ var sen = document.createElement('span');
228
+ sen.setAttribute('class', 'rfe_exp_span rfe_expression_name');
229
+ sen.appendChild(document.createTextNode(expname));
230
+ d.appendChild(sen);
231
+
232
+ var sea = document.createElement('span');
233
+ sea.setAttribute('class', 'rfe_exp_span rfe_expression_atts');
234
+ sea.appendChild(document.createTextNode(' ' + atts));
235
+ d.appendChild(sea);
236
+
237
+ addHeadButtons(d);
238
+
239
+ var onblur = function () {
240
+
241
+ var p = d.parentNode;
242
+ var d2 = ExpressionHead.render(p, ExpressionHead.parse(this.value));
243
+ p.replaceChild(d2, d);
244
+
245
+ triggerChange(p); // trigger onChange()...
246
+ };
247
+
248
+ // blurring on "enter"
249
+ //
250
+ var onkeyup = function (evt) {
251
+
252
+ var e = evt || window.event;
253
+ var c = e.charCode || e.keyCode;
254
+ if (c == 13) this.blur();
255
+
256
+ return false;
257
+ }
258
+
259
+ // preventing propagation of "enter"
260
+ //
261
+ var onkeypress = function (evt) {
262
+
263
+ var e = evt || window.event;
264
+ var c = e.charCode || e.keyCode;
265
+
266
+ return (c != 13);
267
+ }
268
+
269
+ var onclick = function () {
270
+ d.removeChild(sen);
271
+ var input = document.createElement('input');
272
+ input.setAttribute('type', 'text');
273
+ input.value = expname + ' ' + atts;
274
+ if (text != '') input.value = expname + ' ' + text + ' ' + atts;
275
+ d.replaceChild(input, sea);
276
+ input.onblur = onblur;
277
+ input.onkeyup = onkeyup;
278
+ input.onkeypress = onkeypress;
279
+ input.focus();
280
+ };
281
+
282
+ sen.onclick = onclick;
283
+ sea.onclick = onclick;
284
+
285
+ return d;
286
+ },
287
+
288
+ parse: function (s) {
289
+
290
+ var m = s.match(headPattern);
291
+
292
+ if (m == null) return [ '---', {}, [] ];
293
+
294
+ var attributes = Attributes.parse(m[2]);
295
+
296
+ return [ m[1], attributes, [] ];
297
+ },
298
+
299
+ toExp: function (node) {
300
+
301
+ node = node.firstChild;
302
+
303
+ var name = node.childNodes[0].firstChild.nodeValue;
304
+ var atts = node.childNodes[1].firstChild.nodeValue;
305
+
306
+ atts = Attributes.parse(atts);
307
+
308
+ var children = [];
309
+
310
+ return [ name, atts, children ];
311
+ }
312
+ };
313
+ }();
314
+
315
+ function asJson (node) {
316
+
317
+ if ((typeof node) == 'string')
318
+ node = document.getElementById(node);
319
+
320
+ return JSON.stringify(toTree(node));
321
+ }
322
+
323
+ function renderEnding (node, exp) {
324
+
325
+ var ending = document.createElement('div');
326
+ ending.className = 'rfe_text';
327
+ if (exp[2].length > 0) ending.appendChild(document.createTextNode('end'));
328
+ node.appendChild(ending);
329
+ }
330
+
331
+ function addExpression (parentExpNode, exp) {
332
+
333
+ var end = parentExpNode.lastChild;
334
+ var node = renderExpression(parentExpNode, exp);
335
+ parentExpNode.replaceChild(node, end);
336
+ parentExpNode.appendChild(end);
337
+
338
+ if (end.childNodes.length == 0)
339
+ end.appendChild(document.createTextNode('end'));
340
+
341
+ triggerChange(parentExpNode);
342
+ }
343
+
344
+ function removeExpression (expNode) {
345
+
346
+ var p = expNode.parentNode;
347
+ p.removeChild(expNode);
348
+
349
+ if (p.childNodes.length == 2)
350
+ p.lastChild.removeChild(p.lastChild.firstChild);
351
+
352
+ document._rfe_clipboard = toTree(expNode);
353
+
354
+ triggerChange(p);
355
+ }
356
+
357
+ function renderExpression (parentNode, exp, isRootExp) {
358
+
359
+ //
360
+ // draw expression
361
+
362
+ var node = document.createElement('div');
363
+ node.className = 'rfe_expression';
364
+
365
+ if ( ! isRootExp)
366
+ node.setAttribute('style', 'margin-left: 14px;');
367
+
368
+ parentNode.appendChild(node);
369
+
370
+ if ( ! (exp instanceof Array)) {
371
+ renderExpressionString(node, exp.toString());
372
+ return;
373
+ }
374
+
375
+ ExpressionHead.render(node, exp);
376
+
377
+ //
378
+ // draw children
379
+
380
+ for (var i=0; i < exp[2].length; i++) renderExpression(node, exp[2][i]);
381
+
382
+ //
383
+ // over
384
+
385
+ renderEnding(node, exp);
386
+
387
+ return node;
388
+ }
389
+
390
+ function renderFlow (parentNode, flow) {
391
+
392
+ if ((typeof parentNode) == 'string') {
393
+ parentNode = document.getElementById(parentNode);
394
+ }
395
+
396
+ parentNode.className = 'rfe_root';
397
+
398
+ while(parentNode.firstChild) {
399
+ parentNode.removeChild(parentNode.firstChild);
400
+ }
401
+
402
+ renderExpression(parentNode, flow, true);
403
+
404
+ parentNode.stack = []; // the undo stack
405
+ parentNode.currentTree = flow;
406
+ }
407
+
408
+ function moveExpression (elt, delta) {
409
+
410
+ var p = elt.parentNode;
411
+
412
+ if (delta == -1) { // move up
413
+ if (elt.previousSibling.className != 'rfe_expression') return;
414
+ p.insertBefore(elt, elt.previousSibling);
415
+ }
416
+ else { // move down
417
+ if (elt.nextSibling.className != 'rfe_expression') return;
418
+ p.insertBefore(elt, elt.nextSibling.nextSibling);
419
+ }
420
+
421
+ FluoEditor.triggerChange(p);
422
+ }
423
+
424
+ function insertExpression (before, exp) {
425
+
426
+ var newNode = renderExpression(before.parentNode, exp);
427
+
428
+ before.parentNode.insertBefore(newNode, before);
429
+
430
+ FluoEditor.triggerChange(before.parentNode);
431
+ }
432
+
433
+ function triggerChange (elt) {
434
+
435
+ var rfeRoot = findRfeRoot(elt);
436
+ var tree = toTree(rfeRoot);
437
+
438
+ stack(rfeRoot, tree);
439
+
440
+ if (rfeRoot.onChange) rfeRoot.onChange(tree);
441
+ }
442
+
443
+ function stack(root, tree) {
444
+ root.stack.push(root.currentTree);
445
+ root.currentTree = tree;
446
+ }
447
+
448
+ function undo (root) {
449
+
450
+ if ((typeof root) == 'string') root = document.getElementById(root);
451
+ if (root.stack.length < 1) return;
452
+
453
+ while (root.firstChild != null) root.removeChild(root.firstChild);
454
+
455
+ var tree = root.stack.pop();
456
+
457
+ root.currentTree = tree;
458
+ renderExpression(root, tree, true);
459
+
460
+ if (root.onChange) root.onChange(tree);
461
+ }
462
+
463
+ function findRfeRoot (node) {
464
+
465
+ if (node.className == 'rfe_root') return node;
466
+ return findRfeRoot(node.parentNode);
467
+ }
468
+
469
+ function computeExpId (node, from, expid) {
470
+
471
+ if (from == null) {
472
+ from = findRfeRoot(node);
473
+ expid = '';
474
+ }
475
+ if (from == node) return expid.substring(1, expid.length);
476
+
477
+ var divs = from.childNodes;
478
+ var childid = -1;
479
+
480
+ for (var i=0; i<divs.length; i++) {
481
+ var e = divs[i];
482
+ if (e.nodeType != 1) continue;
483
+ if (e.className != 'rfe_expression') continue;
484
+ childid += 1;
485
+ var ei = computeExpId(node, e, expid + '_' + childid);
486
+ if (ei != null) return ei;
487
+ }
488
+
489
+ return null;
490
+ }
491
+
492
+ function toTree (node) {
493
+
494
+ node.focus();
495
+ //
496
+ // making sure all the input boxes get blurred...
497
+
498
+ if (node.className != 'rfe_expression') {
499
+ node = node.firstChildOfClass('rfe_expression');
500
+ }
501
+
502
+ //
503
+ // expression itself
504
+
505
+ var exp = ExpressionHead.toExp(node);
506
+
507
+ //
508
+ // children
509
+
510
+ var divs = node.childNodes;
511
+
512
+ var children = exp[2];
513
+
514
+ for (var i=0; i<divs.length; i++) {
515
+ var e = divs[i];
516
+ if (e.nodeType != 1) continue;
517
+ if (e.className != 'rfe_expression') continue;
518
+ children.push(toTree(e));
519
+ }
520
+
521
+ //
522
+ // done
523
+
524
+ return exp;
525
+ }
526
+
527
+ //
528
+ // public methods
529
+ //
530
+ return {
531
+
532
+ TEXTS: TEXTS,
533
+
534
+ ExpressionHead: ExpressionHead,
535
+ Attributes: Attributes, // for testing purposes
536
+
537
+ renderFlow: renderFlow,
538
+ addExpression: addExpression,
539
+ removeExpression: removeExpression,
540
+ moveExpression: moveExpression,
541
+ insertExpression: insertExpression,
542
+ triggerChange: triggerChange,
543
+ undo: undo,
544
+ asJson: asJson,
545
+ imageRoot: imageRoot
546
+ };
547
+ }();
548
+
@@ -1,3 +1,4 @@
1
+
1
2
  /*
2
3
  * Ruote - open source ruby workflow engine
3
4
  * (c) 2005-2010 jmettraux@gmail.com
@@ -30,7 +31,7 @@ var FluoConstants = {
30
31
  FONT: '12px Helvetica Neue'
31
32
  }
32
33
 
33
- var FluoCanvas = function() {
34
+ var FluoCanvas = function () {
34
35
 
35
36
  //
36
37
  // draws centered text
@@ -805,6 +806,7 @@ var Fluo = function () {
805
806
  'continue': TextHandler,
806
807
  'back': TextHandler,
807
808
  'break': TextHandler,
809
+ 'stop': TextHandler,
808
810
  'cancel': TextHandler,
809
811
  'skip': TextHandler,
810
812
  'jump': TextHandler,
@@ -991,6 +993,33 @@ var Fluo = function () {
991
993
  canvas.parentNode.replaceChild(nc, canvas);
992
994
  }
993
995
 
996
+ // For example :
997
+ //
998
+ // Fluo.resize('fluo', 0.5)
999
+ //
1000
+ function resize (canvas, factor) {
1001
+
1002
+ canvas = resolveCanvas(canvas);
1003
+ var w = canvas.width;
1004
+ var h = canvas.height;
1005
+ canvas.style.width = '' + (w * factor) + 'px';
1006
+ canvas.style.height = '' + (h * factor) + 'px';
1007
+ }
1008
+
1009
+ // For example :
1010
+ //
1011
+ // Fluo.resizeForMaxWidth('fluo', 200)
1012
+ //
1013
+ function resizeForMaxWidth (canvas, maxWidth) {
1014
+
1015
+ canvas = resolveCanvas(canvas);
1016
+ var w = canvas.width;
1017
+
1018
+ if (w < maxWidth) return;
1019
+
1020
+ resize(canvas, maxWidth / w);
1021
+ }
1022
+
994
1023
  function neutralizeContext (c) {
995
1024
  if (window.navigator.userAgent.match(/Firefox/)) {
996
1025
  c.write = function (t) {
@@ -1081,6 +1110,8 @@ var Fluo = function () {
1081
1110
  getHeight: getHeight,
1082
1111
  getWidth: getWidth,
1083
1112
  crop: crop,
1113
+ resize: resize,
1114
+ resizeForMaxWidth: resizeForMaxWidth,
1084
1115
  toggleMinor: toggleMinor,
1085
1116
  toggleVertical: toggleVertical
1086
1117
  };
@@ -0,0 +1,53 @@
1
+ /* http://meyerweb.com/eric/tools/css/reset/ */
2
+ /* v1.0 | 20080212 */
3
+
4
+ html, body, div, span, applet, object, iframe,
5
+ h1, h2, h3, h4, h5, h6, p, blockquote, pre,
6
+ a, abbr, acronym, address, big, cite, code,
7
+ del, dfn, em, font, img, ins, kbd, q, s, samp,
8
+ small, strike, strong, sub, sup, tt, var,
9
+ b, u, i, center,
10
+ dl, dt, dd, ol, ul, li,
11
+ fieldset, form, label, legend,
12
+ table, caption, tbody, tfoot, thead, tr, th, td {
13
+ margin: 0;
14
+ padding: 0;
15
+ border: 0;
16
+ outline: 0;
17
+ font-size: 100%;
18
+ vertical-align: baseline;
19
+ background: transparent;
20
+ }
21
+ body {
22
+ line-height: 1;
23
+ }
24
+ ol, ul {
25
+ list-style: none;
26
+ }
27
+ blockquote, q {
28
+ quotes: none;
29
+ }
30
+ blockquote:before, blockquote:after,
31
+ q:before, q:after {
32
+ content: '';
33
+ content: none;
34
+ }
35
+
36
+ /* remember to define focus styles! */
37
+ :focus {
38
+ outline: 0;
39
+ }
40
+
41
+ /* remember to highlight inserts somehow! */
42
+ ins {
43
+ text-decoration: none;
44
+ }
45
+ del {
46
+ text-decoration: line-through;
47
+ }
48
+
49
+ /* tables still need 'cellspacing="0"' in the markup */
50
+ table {
51
+ border-collapse: collapse;
52
+ border-spacing: 0;
53
+ }