puffer 0.0.32 → 0.1.0

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 (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
  /**