puffer 0.0.32 → 0.1.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (117) hide show
  1. data/.gitignore +7 -0
  2. data/Gemfile +1 -26
  3. data/Gemfile.lock +66 -64
  4. data/README.md +34 -23
  5. data/Rakefile +1 -11
  6. data/VERSION +1 -1
  7. data/app/assets/javascripts/puffer/application.js +6 -1
  8. data/app/assets/javascripts/puffer/associations.js +18 -0
  9. data/app/assets/javascripts/puffer/puffer.js +7 -0
  10. data/app/assets/javascripts/puffer/right-calendar-src.js +19 -3
  11. data/app/assets/javascripts/puffer/right-dnd-src.js +591 -0
  12. data/app/assets/javascripts/puffer/right-in-edit-src.js +373 -0
  13. data/app/assets/javascripts/puffer/right-keys-src.js +87 -0
  14. data/app/assets/javascripts/puffer/{paginator.js → right-paginator-src.js} +0 -0
  15. data/app/assets/javascripts/puffer/right-slider-src.js +29 -32
  16. data/app/assets/javascripts/puffer/right-sortable-src.js +430 -0
  17. data/app/assets/javascripts/puffer/right-src.js +358 -99
  18. data/app/assets/stylesheets/puffer/puffer.css +29 -4
  19. data/app/components/base/form.html.erb +8 -14
  20. data/app/components/base_component.rb +1 -1
  21. data/app/components/boolean/form.html.erb +5 -3
  22. data/app/components/boolean/index.html.erb +6 -2
  23. data/app/components/boolean_component.rb +2 -2
  24. data/app/components/date_time/filter.html.erb +9 -0
  25. data/app/components/date_time/form.html.erb +8 -4
  26. data/app/components/date_time_component.rb +21 -5
  27. data/app/components/file/form.html.erb +8 -4
  28. data/app/components/hidden/form.html.erb +3 -1
  29. data/app/components/nested_attributes_many/form.html.erb +47 -0
  30. data/app/components/nested_attributes_many_component.rb +7 -0
  31. data/app/components/nested_attributes_one/form.html.erb +48 -0
  32. data/app/components/nested_attributes_one_component.rb +7 -0
  33. data/app/components/password/form.html.erb +8 -4
  34. data/app/components/password_component.rb +1 -1
  35. data/app/components/references_many/index.html.erb +1 -1
  36. data/app/components/references_one/choose.html.erb +1 -1
  37. data/app/components/references_one/form.html.erb +10 -9
  38. data/app/components/references_one_component.rb +0 -1
  39. data/app/components/render_component.rb +13 -0
  40. data/app/components/select/filter.html.erb +4 -2
  41. data/app/components/select/form.html.erb +8 -4
  42. data/app/components/text/form.html.erb +8 -4
  43. data/app/controllers/admin/sessions_controller.rb +1 -21
  44. data/app/controllers/puffer/base.rb +10 -3
  45. data/app/controllers/puffer/dashboard_base.rb +7 -1
  46. data/app/controllers/puffer/{sessions_base.rb → sessions/base.rb} +10 -7
  47. data/app/controllers/puffer/sessions/clearance.rb +29 -0
  48. data/app/controllers/puffer/{sessions_devise_base.rb → sessions/devise.rb} +1 -1
  49. data/app/controllers/puffer/sessions/simple.rb +28 -0
  50. data/app/controllers/puffer/tree_base.rb +1 -1
  51. data/app/models/puffer_user.rb +3 -0
  52. data/app/views/layouts/puffer.html.erb +3 -3
  53. data/app/views/puffer/base/_edit.html.erb +15 -0
  54. data/app/views/puffer/base/_index.html.erb +26 -0
  55. data/app/views/puffer/base/_show.html.erb +13 -0
  56. data/app/views/puffer/base/_table.html.erb +1 -1
  57. data/app/views/puffer/base/edit.html.erb +1 -15
  58. data/app/views/puffer/base/edit.js.erb +1 -0
  59. data/app/views/puffer/base/index.html.erb +1 -20
  60. data/app/views/puffer/base/index.js.erb +1 -0
  61. data/app/views/puffer/base/new.html.erb +1 -1
  62. data/app/views/puffer/base/show.html.erb +1 -22
  63. data/app/views/puffer/base/show.js.erb +1 -0
  64. data/app/views/puffer/base/update.js.erb +1 -0
  65. data/app/views/puffer/sessions/base/new.html.erb +11 -0
  66. data/app/views/puffer/tree_base/_record.html.erb +1 -1
  67. data/lib/puffer/component.rb +14 -47
  68. data/lib/puffer/controller/auth.rb +13 -9
  69. data/lib/puffer/controller/config.rb +18 -0
  70. data/lib/puffer/controller/mutate.rb +8 -8
  71. data/lib/puffer/engine.rb +5 -0
  72. data/lib/puffer/field.rb +5 -11
  73. data/lib/puffer/filters.rb +86 -56
  74. data/lib/puffer/helpers/component_helper.rb +24 -0
  75. data/lib/puffer/helpers/puffer_helper.rb +65 -0
  76. data/lib/puffer/helpers/puffer_tree_helper.rb +19 -0
  77. data/lib/puffer/orm_adapter/active_record.rb +40 -11
  78. data/lib/puffer/orm_adapter/base.rb +9 -0
  79. data/lib/puffer/orm_adapter/mongoid.rb +32 -9
  80. data/lib/puffer/resource/node.rb +2 -2
  81. data/lib/puffer/resource/routing.rb +30 -16
  82. data/lib/puffer/resource.rb +20 -20
  83. data/lib/puffer/version.rb +3 -0
  84. data/lib/puffer.rb +26 -5
  85. data/puffer.gemspec +34 -296
  86. data/spec/app/components/base_component_spec.rb +1 -1
  87. data/spec/app/components/boolean_component_spec.rb +2 -0
  88. data/spec/app/components/date_time_component_spec.rb +1 -0
  89. data/spec/app/components/file_component_spec.rb +1 -0
  90. data/spec/app/components/hidden_component_spec.rb +1 -0
  91. data/spec/app/components/password_component_spec.rb +2 -0
  92. data/spec/app/components/select_component_spec.rb +1 -0
  93. data/spec/app/components/string_component_spec.rb +1 -0
  94. data/spec/app/components/text_component_spec.rb +1 -0
  95. data/spec/dummy/app/controllers/admin/news_controller.rb +2 -0
  96. data/spec/dummy/app/controllers/admin/profiles_controller.rb +1 -1
  97. data/spec/dummy/app/controllers/admin/users_controller.rb +2 -0
  98. data/spec/dummy/app/controllers/orms/active_record_orm_primals_controller.rb +8 -0
  99. data/spec/dummy/app/helpers/news_helper.rb +7 -0
  100. data/spec/dummy/app/models/active_record_orm/has_many_reference.rb +5 -0
  101. data/spec/dummy/app/models/active_record_orm/has_one_reference.rb +5 -0
  102. data/spec/dummy/app/models/active_record_orm/primal.rb +4 -0
  103. data/spec/dummy/config/environments/development.rb +1 -1
  104. data/spec/dummy/db/migrate/20111120144025_create_active_record_orm_has_one_references.rb +10 -0
  105. data/spec/dummy/db/migrate/20111122203304_create_active_record_orm_has_many_references.rb +10 -0
  106. data/spec/dummy/db/schema.rb +15 -1
  107. data/spec/helpers/puffer_helper_spec.rb +1 -1
  108. data/spec/lib/fields_spec.rb +0 -9
  109. data/spec/lib/filters_spec.rb +4 -8
  110. data/spec/lib/orm_adapter/base_shared.rb +22 -0
  111. data/spec/spec_helper.rb +1 -1
  112. metadata +89 -60
  113. data/app/components/string/form.html.erb +0 -5
  114. data/app/helpers/puffer_helper.rb +0 -51
  115. data/app/helpers/puffer_tree_helper.rb +0 -15
  116. data/app/views/puffer/sessions_base/new.html.erb +0 -11
  117. data/lib/puffer/extensions/form.rb +0 -16
@@ -1,5 +1,5 @@
1
1
  /**
2
- * RightJS v2.2.3 - http://rightjs.org
2
+ * RightJS v2.3.0 - http://rightjs.org
3
3
  * Released under the terms of MIT license
4
4
  *
5
5
  * Copyright (C) 2008-2011 Nikolay Nemshilov
@@ -20,7 +20,7 @@ var RightJS = function(value) {
20
20
  return value; // <- a dummy method to emulate the safe-mode
21
21
  };
22
22
 
23
- RightJS.version = "2.2.3";
23
+ RightJS.version = "2.3.0";
24
24
  RightJS.modules =["core", "dom", "form", "events", "xhr", "fx", "cookie", "olds"];
25
25
 
26
26
 
@@ -157,7 +157,7 @@ isString = RightJS.isString = function(value) {
157
157
  * @return boolean check result
158
158
  */
159
159
  isNumber = RightJS.isNumber = function(value) {
160
- return typeof(value) === 'number';
160
+ return typeof(value) === 'number' && !isNaN(value);
161
161
  },
162
162
 
163
163
  /**
@@ -471,8 +471,8 @@ $ext(Object, {
471
471
  * @return Object merged object
472
472
  */
473
473
  merge: function() {
474
- var object = {}, i=0, args=arguments, key;
475
- for (l = args.length; i < l; i++) {
474
+ var object = {}, i=0, args=arguments, l=args.length, key;
475
+ for (; i < l; i++) {
476
476
  if (isHash(args[i])) {
477
477
  for (key in args[i]) {
478
478
  object[key] = isHash(args[i][key]) && !(args[i][key] instanceof Class) ?
@@ -490,17 +490,55 @@ $ext(Object, {
490
490
  * @return String query
491
491
  */
492
492
  toQueryString: function(object) {
493
- var tokens = [], key, value, encode = encodeURIComponent;
494
- for (key in object) {
495
- value = ensure_array(object[key]);
496
- for (var i=0, l = value.length; i < l; i++) {
497
- tokens.push(encode(key) +'='+ encode(value[i]));
498
- }
493
+ var entries = to_query_string_map(object), i=0, result = [];
494
+
495
+ for (; i < entries.length; i++) {
496
+ result.push(encodeURIComponent(entries[i][0]) + "=" + encodeURIComponent(''+entries[i][1]));
499
497
  }
500
- return tokens.join('&');
498
+
499
+ return result.join('&');
501
500
  }
502
501
  }, true);
503
502
 
503
+ // private
504
+
505
+ /**
506
+ * pre-converts nested objects into a flat key-value structure
507
+ *
508
+ * @param {Object} data-hash
509
+ * @param {String} key-prefix
510
+ * @return {Array} key-value pairs
511
+ */
512
+ function to_query_string_map(hash, prefix) {
513
+ var result = [], key, value, i;
514
+
515
+ for (key in hash) {
516
+ value = hash[key];
517
+ if (prefix) {
518
+ key = prefix + "["+ key + "]";
519
+ }
520
+
521
+ if (typeof(value) === 'object') {
522
+ if (isArray(value)) {
523
+ if (!key.endsWith('[]')) {
524
+ key += "[]";
525
+ }
526
+ for (i=0; i < value.length; i++) {
527
+ result.push([key, value[i]]);
528
+ }
529
+ } else if (value) { // assuming it's an object
530
+ value = to_query_string_map(value, key);
531
+ for (i=0; i < value.length; i++) {
532
+ result.push(value[i]);
533
+ }
534
+ }
535
+ } else {
536
+ result.push([key, value]);
537
+ }
538
+ }
539
+
540
+ return result;
541
+ }
504
542
 
505
543
  /**
506
544
  * here are the starndard Math object extends
@@ -1122,6 +1160,15 @@ String.include({
1122
1160
  return this.charAt(0).toUpperCase() + this.substring(1).toLowerCase();
1123
1161
  },
1124
1162
 
1163
+ /**
1164
+ * Makes a dashed version of the string
1165
+ *
1166
+ * @return String dashed version
1167
+ */
1168
+ dasherize: function() {
1169
+ return this.underscored().replace(/_/g, '-');
1170
+ },
1171
+
1125
1172
  /**
1126
1173
  * checks if the string contains the given substring
1127
1174
  *
@@ -1417,6 +1464,80 @@ RegExp.escape = function(string) {
1417
1464
  };
1418
1465
 
1419
1466
 
1467
+ if (!window.JSON) {
1468
+ window.JSON = (function() {
1469
+ var
1470
+ // see the original JSON decoder implementation for descriptions http://www.json.org/json2.js
1471
+ cx = /[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
1472
+ specials = {'\b': '\\b', '\t': '\\t', '\n': '\\n', '\f': '\\f', '\r': '\\r', '"' : '\\"', '\\': '\\\\'},
1473
+ quotables = /[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g;
1474
+
1475
+
1476
+ // quotes the string
1477
+ function quote(string) {
1478
+ return string.replace(quotables, function(chr) {
1479
+ return specials[chr] || '\\u' + ('0000' + chr.charCodeAt(0).toString(16)).slice(-4);
1480
+ });
1481
+ }
1482
+
1483
+ // adds the leading zero symbol
1484
+ function zerofy(num) {
1485
+ return (num < 10 ? '0' : '')+num;
1486
+ }
1487
+
1488
+ return {
1489
+ stringify: function(value) {
1490
+ switch(typeof(value)) {
1491
+ case 'boolean': return String(value);
1492
+ case 'number': return String(value+0);
1493
+ case 'string': return '"'+ quote(value) + '"';
1494
+ case 'object':
1495
+ if (value === null) {
1496
+ return 'null';
1497
+ } else if (isArray(value)) {
1498
+ return '['+$A(value).map(JSON.stringify).join(',')+']';
1499
+
1500
+ } else if (to_s.call(value) === '[object Date]') {
1501
+ return '"' + value.getUTCFullYear() + '-' +
1502
+ zerofy(value.getUTCMonth() + 1) + '-' +
1503
+ zerofy(value.getUTCDate()) + 'T' +
1504
+ zerofy(value.getUTCHours()) + ':' +
1505
+ zerofy(value.getUTCMinutes()) + ':' +
1506
+ zerofy(value.getUTCSeconds()) + '.' +
1507
+ zerofy(value.getMilliseconds()) + 'Z' +
1508
+ '"';
1509
+
1510
+ } else {
1511
+ var result = [], key;
1512
+ for (key in value) {
1513
+ result.push('"'+key+'":'+JSON.stringify(value[key]));
1514
+ }
1515
+ return '{'+result.join(',')+'}';
1516
+ }
1517
+ }
1518
+ },
1519
+
1520
+ parse: function(string) {
1521
+ if (isString(string) && string) {
1522
+ // getting back the UTF-8 symbols
1523
+ string = string.replace(cx, function (a) {
1524
+ return '\\u' + ('0000' + a.charCodeAt(0).toString(16)).slice(-4);
1525
+ });
1526
+
1527
+ // checking the JSON string consistency
1528
+ if (/^[\],:{}\s]*$/.test(string.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g, '@')
1529
+ .replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g, ']')
1530
+ .replace(/(?:^|:|,)(?:\s*\[)+/g, ''))) {
1531
+ return new Function('return '+string)();
1532
+ }
1533
+ }
1534
+
1535
+ throw "JSON parse error: "+string;
1536
+ }
1537
+ };
1538
+ })();
1539
+ }
1540
+
1420
1541
  /**
1421
1542
  * The basic Class unit
1422
1543
  *
@@ -2333,11 +2454,13 @@ make_element = function (tag, options) {
2333
2454
  //
2334
2455
  if (IE8_OR_LESS) {
2335
2456
  make_element = function(tag, options) {
2336
- if (tag === 'input' && options !== undefined) {
2337
- tag = '<input name="'+ options.name +
2338
- '" type='+ options.type +
2339
- (options.checked ? ' checked' : '') +
2340
- '/>';
2457
+ if (options !== undefined && (tag === 'input' || tag === 'button')) {
2458
+ tag = '<'+ tag +' name="'+ options.name +
2459
+ '" type="'+ options.type +'"'+
2460
+ (options.checked ? ' checked' : '') + ' />';
2461
+
2462
+ delete(options.name);
2463
+ delete(options.type);
2341
2464
  }
2342
2465
 
2343
2466
  return document.createElement(tag);
@@ -2956,7 +3079,9 @@ Element.include({
2956
3079
  if (!(key in element)) {
2957
3080
  element.setAttribute(key, ''+hash[key]);
2958
3081
  }
2959
- element[key] = hash[key];
3082
+ if (key.substr(0,5) !== 'data-') {
3083
+ element[key] = hash[key];
3084
+ }
2960
3085
  }
2961
3086
  }
2962
3087
 
@@ -3077,6 +3202,60 @@ Element.include({
3077
3202
  radio: function(effect, options) {
3078
3203
  this.siblings().each('hide', effect, options);
3079
3204
  return this.show();
3205
+ },
3206
+
3207
+ /**
3208
+ * Sets/gets the `data-smth` data attribute and
3209
+ * automatically converts everything in/out JSON
3210
+ *
3211
+ * @param String key name
3212
+ * @param mixed data or `undefined` to erase
3213
+ * @return mixed Element self or extracted data
3214
+ */
3215
+ data: function(key, value) {
3216
+ var name, result, match, attrs, attr, i;
3217
+
3218
+ if (isHash(key)) {
3219
+ for (name in key) {
3220
+ value = this.data(name, key[name]);
3221
+ }
3222
+ } else if (value === undefined) {
3223
+ key = 'data-'+ (''+key).dasherize();
3224
+
3225
+ for (result = {}, match = false, attrs = this._.attributes, i=0; i < attrs.length; i++) {
3226
+ value = attrs[i].value;
3227
+ try { value = JSON.parse(value); } catch (e) {}
3228
+
3229
+ if (attrs[i].name === key) {
3230
+ result = value;
3231
+ match = true;
3232
+ break;
3233
+ } else if (attrs[i].name.indexOf(key) === 0) {
3234
+ result[attrs[i].name.substring(key.length+1).camelize()] = value;
3235
+ match = true;
3236
+ }
3237
+ }
3238
+
3239
+ value = match ? result : null;
3240
+ } else {
3241
+ key = 'data-'+ (''+key).dasherize();
3242
+
3243
+ if (!isHash(value)) { value = {'': value}; }
3244
+
3245
+ for (name in value) {
3246
+ attr = name.blank() ? key : key+'-'+name.dasherize();
3247
+
3248
+ if (value[name] === null) {
3249
+ this._.removeAttribute(attr);
3250
+ } else {
3251
+ this._.setAttribute(attr, isString(value[name]) ? value[name] : JSON.stringify(value[name]));
3252
+ }
3253
+ }
3254
+
3255
+ value = this;
3256
+ }
3257
+
3258
+ return value;
3080
3259
  }
3081
3260
  });
3082
3261
 
@@ -3645,20 +3824,36 @@ var Form = RightJS.Form = Element_wrappers.FORM = new Class(Element, {
3645
3824
  * @return Object values
3646
3825
  */
3647
3826
  values: function() {
3648
- var values = {}, value, name, element, input;
3649
-
3650
- this.inputs().each(function(element) {
3651
- input = element._;
3652
- name = input.name;
3653
- if (!input.disabled && name && (
3654
- !['checkbox', 'radio'].include(input.type) || input.checked
3655
- )) {
3656
- value = element.getValue();
3657
- if (name.endsWith('[]')) {
3658
- value = (values[name] || []).concat([value]);
3827
+ var values = {};
3828
+
3829
+ this.inputs().each(function (element) {
3830
+ var input = element._,
3831
+ hash = values, key,
3832
+ keys = input.name.match(/[^\[]+/g);
3833
+
3834
+ if (!input.disabled && input.name && (!(input.type === 'checkbox' || input.type === 'radio') || input.checked)) {
3835
+ // getting throught the smth[smth][smth][] in the name
3836
+ while (keys.length > 1) {
3837
+ key = keys.shift();
3838
+ if (key.endsWith(']')) {
3839
+ key = key.substr(0, key.length-1);
3840
+ }
3841
+ if (!hash[key]) {
3842
+ hash[key] = keys[0] === ']' ? [] : {};
3843
+ }
3844
+ hash = hash[key];
3845
+ }
3846
+
3847
+ key = keys.shift();
3848
+ if (key.endsWith(']')) {
3849
+ key = key.substr(0, key.length-1);
3659
3850
  }
3660
3851
 
3661
- values[name] = value;
3852
+ if (key === '') { // an array
3853
+ hash.push(element.value());
3854
+ } else {
3855
+ hash[key] = element.value();
3856
+ }
3662
3857
  }
3663
3858
  });
3664
3859
 
@@ -4563,10 +4758,6 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4563
4758
 
4564
4759
  // prepares user sending params
4565
4760
  prepareParams: function(params) {
4566
- if (params && params instanceof Form) {
4567
- this.form = params;
4568
- params = params.values();
4569
- }
4570
4761
  return params;
4571
4762
  },
4572
4763
 
@@ -4598,41 +4789,32 @@ var Xhr = RightJS.Xhr = new Class(Observer, {
4598
4789
  // called on success
4599
4790
  tryScripts: function(response) {
4600
4791
  var content_type = this.getHeader('Content-type');
4792
+ var x_json_data = this.getHeader('X-JSON');
4793
+
4794
+ if (x_json_data) {
4795
+ this.json = this.responseJSON = this.headerJSON = JSON.parse(x_json_data);
4796
+ }
4601
4797
 
4602
4798
  if (this.evalResponse || (this.evalJS && /(ecma|java)script/i.test(content_type))) {
4603
4799
  $eval(this.text);
4604
4800
  } else if (/json/.test(content_type) && this.evalJSON) {
4605
- this.json = this.responseJSON = this.sanitizedJSON();
4801
+ this.json = this.responseJSON = JSON.parse(this.text);
4606
4802
  } else if (this.evalScripts) {
4607
4803
  this.text.evalScripts();
4608
4804
  }
4609
4805
  },
4610
4806
 
4611
- // sanitizes the json-response texts
4612
- sanitizedJSON: function() {
4613
- if (!(/^[,:{}\[\]0-9.\-+Eaeflnr-u \n\r\t]*$/).test(
4614
- this.text.replace(/\\./g, '@').replace(/"[^"\\\n\r]*"/g, '')
4615
- )) {
4616
- if (this.secureJSON) {
4617
- throw "JSON error: "+this.text;
4618
- }
4619
- return null;
4620
- }
4621
-
4622
- return 'JSON' in window ? JSON.parse(this.text) :
4623
- (new Function("return "+this.text))();
4624
- },
4625
-
4626
4807
  // initializes the request callbacks
4627
4808
  initCallbacks: function() {
4628
4809
  // connecting basic callbacks
4629
4810
  this.on({
4630
- success: 'tryScripts',
4631
4811
  create: 'showSpinner',
4632
4812
  complete: 'hideSpinner',
4633
4813
  cancel: 'hideSpinner'
4634
4814
  });
4635
4815
 
4816
+ this.on('complete', 'tryScripts');
4817
+
4636
4818
  // wiring the global xhr callbacks
4637
4819
  Xhr.EVENTS.each(function(name) {
4638
4820
  this.on(name, function() { Xhr.fire(name, this, this.xhr); });
@@ -4767,6 +4949,22 @@ function Form_remote_send(event, options) {
4767
4949
  this.send(options);
4768
4950
  }
4769
4951
 
4952
+ /**
4953
+ * Adds Xhr params handling if a Form element is passed to Xhr#send
4954
+ *
4955
+ * @param Object params - could be Hash or Form element
4956
+ * @return Object
4957
+ */
4958
+ Xhr.include({
4959
+ prepareParams: function(params) {
4960
+ if (params && params instanceof Form) {
4961
+ this.form = params;
4962
+ params = params.values();
4963
+ }
4964
+ return params;
4965
+ }
4966
+ });
4967
+
4770
4968
 
4771
4969
  /**
4772
4970
  * this module contains the Element unit XHR related extensions
@@ -4940,7 +5138,9 @@ Xhr.JSONP = new Class({
4940
5138
  *
4941
5139
  * Credits:
4942
5140
  * The basic principles, structures and naming system are inspired by
4943
- * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
5141
+ * - MooTools (http://mootools.net) Copyright (C) Valerio Proietti
5142
+ * The cubic bezier emulation is backported from
5143
+ * - Lovely.IO (http://lovely.io) Copytirhgt (C) Nikolay Nemshilov
4944
5144
  *
4945
5145
  * Copyright (C) 2008-2011 Nikolay V. Nemshilov
4946
5146
  */
@@ -4959,31 +5159,9 @@ var Fx = RightJS.Fx = new Class(Observer, {
4959
5159
  Options: {
4960
5160
  fps: IE8_OR_LESS ? 40 : 60,
4961
5161
  duration: 'normal',
4962
- transition: 'Sin',
4963
- queue: true
4964
- },
4965
-
4966
- // list of basic transitions
4967
- Transitions: {
4968
- Sin: function(i) {
4969
- return -(Math.cos(Math.PI * i) - 1) / 2;
4970
- },
4971
-
4972
- Cos: function(i) {
4973
- return Math.asin((i-0.5) * 2)/Math.PI + 0.5;
4974
- },
4975
-
4976
- Exp: function(i) {
4977
- return Math.pow(2, 8 * (i - 1));
4978
- },
4979
-
4980
- Log: function(i) {
4981
- return 1 - Math.pow(2, - 8 * i);
4982
- },
4983
-
4984
- Lin: function(i) {
4985
- return i;
4986
- }
5162
+ transition: 'default',
5163
+ queue: true,
5164
+ engine: 'css'
4987
5165
  }
4988
5166
  },
4989
5167
 
@@ -5006,17 +5184,11 @@ var Fx = RightJS.Fx = new Class(Observer, {
5006
5184
  start: function() {
5007
5185
  if (fx_add_to_queue(this, arguments)) { return this; }
5008
5186
 
5009
- var options = this.options,
5010
- duration = Fx.Durations[options.duration] || options.duration,
5011
- transition = Fx.Transitions[options.transition] || options.transition,
5012
- steps = (duration / 1000 * this.options.fps).ceil(),
5013
- interval = (1000 / this.options.fps).round();
5014
-
5015
5187
  fx_mark_current(this);
5016
5188
 
5017
5189
  this.prepare.apply(this, arguments);
5018
5190
 
5019
- fx_start_timer(this, transition, interval, steps);
5191
+ fx_start_timer(this);
5020
5192
 
5021
5193
  return this.fire('start', this);
5022
5194
  },
@@ -5150,19 +5322,22 @@ function fx_cancel_all(element) {
5150
5322
  * Initializes the fx rendering timer
5151
5323
  *
5152
5324
  * @param Fx fx
5153
- * @param Function transition stops calculator
5154
- * @param Float interval
5155
- * @param Integer number of steps
5156
5325
  * @return void
5157
5326
  */
5158
- function fx_start_timer(fx, transition, interval, steps) {
5159
- var number = 1;
5327
+ function fx_start_timer(fx) {
5328
+ var options = fx.options,
5329
+ duration = Fx.Durations[options.duration] || options.duration,
5330
+ steps = Math.ceil(duration / 1000 * options.fps),
5331
+ transition = Bezier_sequence(options.transition, steps),
5332
+ interval = Math.round(1000 / options.fps),
5333
+ number = 0;
5334
+
5160
5335
  fx._timer = setInterval(function() {
5161
- if (number > steps) {
5336
+ if (number === steps) {
5162
5337
  fx.finish();
5163
5338
  } else {
5164
- fx.render(transition(number/steps));
5165
- number ++;
5339
+ fx.render(transition[number]);
5340
+ number++;
5166
5341
  }
5167
5342
  }, interval);
5168
5343
  }
@@ -5180,6 +5355,82 @@ function fx_stop_timer(fx) {
5180
5355
  }
5181
5356
 
5182
5357
 
5358
+ ///////////////////////////////////////////////////////////////////////////////
5359
+ // CSS3 Cubic Bezier sequentions emulator
5360
+ // Backport from Lovely.IO (http://lovely.io)
5361
+ // See also:
5362
+ // http://st-on-it.blogspot.com/2011/05/calculating-cubic-bezier-function.html
5363
+ ///////////////////////////////////////////////////////////////////////////////
5364
+
5365
+ // CSS3 cubic-bezier presets
5366
+ var Bezier_presets = {
5367
+ 'default': '(.25,.1,.25,1)',
5368
+ 'linear': '(0,0,1,1)',
5369
+ 'ease-in': '(.42,0,1,1)',
5370
+ 'ease-out': '(0,0,.58,1)',
5371
+ 'ease-in-out': '(.42,0,.58,1)',
5372
+ 'ease-out-in': '(0,.42,1,.58)'
5373
+ },
5374
+
5375
+ // Bezier loockup tables cache
5376
+ Bezier_cache = {};
5377
+
5378
+ // builds a loockup table of parametric values with a given size
5379
+ function Bezier_sequence(params, size) {
5380
+ params = Bezier_presets[params] || native_fx_functions[params] || params;
5381
+ params = params.match(/([\d\.]+)[\s,]+([\d\.]+)[\s,]+([\d\.]+)[\s,]+([\d\.]+)/);
5382
+ params = [0, params[1]-0, params[2]-0, params[3]-0, params[4]-0]; // cleaning up
5383
+
5384
+ var name = params.join(',') + ',' + size, Cx, Bx, Ax, Cy, By, Ay, sequence, step, x;
5385
+
5386
+ function bezier_x(t) { return t * (Cx + t * (Bx + t * Ax)); }
5387
+ function bezier_y(t) { return t * (Cy + t * (By + t * Ay)); }
5388
+
5389
+ // a quick search for a more or less close parametric
5390
+ // value using several iterations by Newton's method
5391
+
5392
+ function bezier_x_der(t) { // bezier_x derivative
5393
+ return Cx + t * (2*Bx + t * 3*Ax) + 1e-3;
5394
+ }
5395
+ function find_parametric(t) {
5396
+ var x=t, i=0, z;
5397
+
5398
+ while (i < 5) {
5399
+ z = bezier_x(x) - t;
5400
+
5401
+ if (Math.abs(z) < 1e-3) { break; }
5402
+
5403
+ x = x - z/bezier_x_der(x);
5404
+ i++;
5405
+ }
5406
+
5407
+ return x;
5408
+ }
5409
+
5410
+ if (!(name in Bezier_cache)) {
5411
+ // defining bezier functions in a polynomial form (coz it's faster)
5412
+ Cx = 3 * params[1];
5413
+ Bx = 3 * (params[3] - params[1]) - Cx;
5414
+ Ax = 1 - Cx - Bx;
5415
+
5416
+ Cy = 3 * params[2];
5417
+ By = 3 * (params[4] - params[2]) - Cy;
5418
+ Ay = 1 - Cy - By;
5419
+
5420
+
5421
+ // building the actual lookup table
5422
+ Bezier_cache[name] = sequence = [];
5423
+ x=0; step=1/size;
5424
+
5425
+ while (x < 1.0001) { // should include 1.0
5426
+ sequence.push(bezier_y(find_parametric(x)));
5427
+ x += step;
5428
+ }
5429
+ }
5430
+
5431
+ return Bezier_cache[name];
5432
+ }
5433
+
5183
5434
  /**
5184
5435
  * There are the String unit extensions for the effects library
5185
5436
  *
@@ -5423,7 +5674,7 @@ native_fx_function = native_fx_transition + 'TimingFunction',
5423
5674
  native_fx_functions = {
5424
5675
  Sin: 'cubic-bezier(.3,0,.6,1)',
5425
5676
  Cos: 'cubic-bezier(0,.3,.6,0)',
5426
- Log: 'cubic-bezier(0.6,.3,.8)',
5677
+ Log: 'cubic-bezier(0,.6,.3,.8)',
5427
5678
  Exp: 'cubic-bezier(.6,0,.8,.3)',
5428
5679
  Lin: 'cubic-bezier(0,0,1,1)'
5429
5680
  };
@@ -5900,7 +6151,7 @@ Fx.Scroll = new Class(Fx.Attr, {
5900
6151
  this.$super(
5901
6152
  element instanceof Window ?
5902
6153
  element._.document[
5903
- 'body' in element._.document ? 'body' : 'documentElement'
6154
+ Browser.WebKit ? 'body' : 'documentElement'
5904
6155
  ] : element,
5905
6156
  options
5906
6157
  );
@@ -5936,12 +6187,12 @@ var Cookie = RightJS.Cookie = new Class({
5936
6187
  return new this(name, options).set(value);
5937
6188
  },
5938
6189
  // gets the cookie
5939
- get: function(name) {
5940
- return new this(name).get();
6190
+ get: function(name, options) {
6191
+ return new this(name, options).get();
5941
6192
  },
5942
6193
  // deletes the cookie
5943
- remove: function(name) {
5944
- return new this(name).remove();
6194
+ remove: function(name, options) {
6195
+ return new this(name, options).remove();
5945
6196
  },
5946
6197
 
5947
6198
  // checks if the cookies are enabled
@@ -5975,7 +6226,10 @@ var Cookie = RightJS.Cookie = new Class({
5975
6226
  * @return Cookie this
5976
6227
  */
5977
6228
  set: function(data) {
6229
+ if (!isString(data)) { data = JSON.stringify(data); }
6230
+
5978
6231
  var value = encodeURIComponent(data), options = this.options;
6232
+
5979
6233
  if (options.domain) { value += '; domain=' + options.domain; }
5980
6234
  if (options.path) { value += '; path=' + options.path; }
5981
6235
  if (options.duration) {
@@ -5997,7 +6251,12 @@ var Cookie = RightJS.Cookie = new Class({
5997
6251
  var value = this.options.document.cookie.match(
5998
6252
  '(?:^|;)\\s*' + RegExp.escape(this.name) + '=([^;]*)'
5999
6253
  );
6000
- return value ? decodeURIComponent(value[1]) : null;
6254
+ if (value) {
6255
+ value = decodeURIComponent(value[1]);
6256
+ try { value = JSON.parse(value); }
6257
+ catch (e) {}
6258
+ }
6259
+ return value || null;
6001
6260
  },
6002
6261
 
6003
6262
  /**