puffer 0.0.19 → 0.0.20

Sign up to get free protection for your applications and to get access to all the features.
Files changed (105) hide show
  1. data/.rvmrc +1 -0
  2. data/Gemfile +11 -8
  3. data/Gemfile.lock +117 -103
  4. data/Guardfile +20 -0
  5. data/VERSION +1 -1
  6. data/app/assets/javascripts/puffer/application.js +5 -0
  7. data/{lib/generators/puffer/install/templates/puffer/javascripts → app/assets/javascripts/puffer}/puffer.js +0 -0
  8. data/{lib/generators/puffer/install/templates/puffer/javascripts → app/assets/javascripts/puffer}/rails.js +0 -0
  9. data/{lib/generators/puffer/install/templates/puffer/javascripts → app/assets/javascripts/puffer}/right-autocompleter.js +0 -0
  10. data/{lib/generators/puffer/install/templates/puffer/javascripts → app/assets/javascripts/puffer}/right-calendar.js +0 -0
  11. data/{lib/generators/puffer/install/templates/puffer/javascripts → app/assets/javascripts/puffer}/right.js +0 -0
  12. data/app/assets/stylesheets/puffer/application.css +4 -0
  13. data/{lib/generators/puffer/install/templates/puffer/stylesheets → app/assets/stylesheets/puffer}/puffer.css +2 -1
  14. data/{lib/generators/puffer/install/templates/puffer/stylesheets → app/assets/stylesheets/puffer}/reset.css +0 -0
  15. data/app/controllers/puffer/dashboard.rb +12 -0
  16. data/app/controllers/puffer/{sessions_base.rb → sessions.rb} +1 -2
  17. data/app/helpers/puffer_helper.rb +2 -10
  18. data/app/views/layouts/puffer.html.erb +24 -5
  19. data/app/views/layouts/puffer_dashboard.html.erb +3 -3
  20. data/app/views/layouts/puffer_sessions.html.erb +3 -3
  21. data/app/views/puffer/{_form.html.erb → base/_form.html.erb} +2 -2
  22. data/app/views/puffer/{associated → base/associated}/_many.html.erb +1 -1
  23. data/app/views/puffer/{associated → base/associated}/many.rjs +0 -0
  24. data/app/views/puffer/{associated → base/associated}/one.js.erb +1 -1
  25. data/app/views/puffer/{association → base/association}/_many.html.erb +0 -0
  26. data/app/views/puffer/{edit.html.erb → base/edit.html.erb} +1 -1
  27. data/app/views/puffer/{index.html.erb → base/index.html.erb} +2 -2
  28. data/app/views/puffer/{new.html.erb → base/new.html.erb} +1 -1
  29. data/app/views/puffer/{show.html.erb → base/show.html.erb} +1 -1
  30. data/app/views/{puffer_dashboard → puffer/dashboard}/index.html.erb +0 -0
  31. data/app/views/{puffer_sessions → puffer/sessions}/new.html.erb +0 -0
  32. data/config/locales/puffer.yml +5 -0
  33. data/lib/generators/puffer/install/install_generator.rb +0 -8
  34. data/lib/generators/puffer/install/templates/dashboard_controller.rb +1 -1
  35. data/lib/generators/puffer/install/templates/sessions_controller.rb +1 -1
  36. data/lib/puffer.rb +0 -16
  37. data/lib/puffer/base.rb +8 -3
  38. data/lib/puffer/controller/config.rb +2 -0
  39. data/lib/puffer/controller/dsl.rb +2 -2
  40. data/lib/puffer/controller/generated.rb +4 -4
  41. data/lib/puffer/controller/helpers.rb +1 -1
  42. data/lib/puffer/controller/mutate.rb +0 -14
  43. data/lib/puffer/customs.rb +1 -0
  44. data/lib/puffer/engine.rb +0 -4
  45. data/lib/puffer/extensions/mapper.rb +5 -1
  46. data/lib/puffer/fields.rb +2 -2
  47. data/lib/puffer/fields/field.rb +16 -17
  48. data/lib/puffer/inputs/association.rb +3 -2
  49. data/lib/puffer/resource.rb +13 -12
  50. data/lib/puffer/resource/routing.rb +1 -1
  51. data/lib/puffer/resource/scoping.rb +2 -2
  52. data/puffer.gemspec +63 -126
  53. data/spec/dummy/.rvmrc +1 -0
  54. data/spec/dummy/Rakefile +1 -1
  55. data/spec/dummy/app/assets/images/rails.png +0 -0
  56. data/spec/dummy/app/assets/javascripts/application.js +9 -0
  57. data/spec/dummy/app/assets/stylesheets/application.css +7 -0
  58. data/spec/dummy/app/controllers/admin/posts_controller.rb +3 -1
  59. data/spec/dummy/app/controllers/admin/profiles_controller.rb +4 -1
  60. data/spec/dummy/app/controllers/puffer/dashboard_controller.rb +1 -1
  61. data/spec/dummy/app/controllers/puffer/sessions_controller.rb +1 -1
  62. data/spec/dummy/app/views/layouts/application.html.erb +14 -0
  63. data/spec/dummy/config/application.rb +5 -9
  64. data/spec/dummy/config/boot.rb +5 -7
  65. data/spec/dummy/config/database.yml +4 -1
  66. data/spec/dummy/config/environments/development.rb +4 -3
  67. data/spec/dummy/config/environments/production.rb +17 -12
  68. data/spec/dummy/config/environments/test.rb +5 -1
  69. data/spec/dummy/config/initializers/secret_token.rb +1 -1
  70. data/spec/dummy/config/initializers/session_store.rb +1 -1
  71. data/spec/dummy/config/initializers/wrap_parameters.rb +12 -0
  72. data/spec/dummy/config/locales/en.yml +1 -1
  73. data/spec/dummy/db/seeds.rb +7 -0
  74. data/spec/dummy/public/robots.txt +5 -0
  75. data/spec/fabricators/posts_fabricator.rb +1 -1
  76. data/spec/fabricators/profiles_fabricator.rb +1 -1
  77. data/spec/fabricators/users_fabricator.rb +1 -1
  78. data/spec/lib/resource/routing_spec.rb +5 -5
  79. data/spec/lib/resource_spec.rb +37 -88
  80. data/spec/spec_helper.rb +15 -0
  81. metadata +171 -272
  82. data/app/cells/puffer/base/additional.html.erb +0 -25
  83. data/app/cells/puffer/base_cell.rb +0 -25
  84. data/app/controllers/puffer/dashboard_base.rb +0 -13
  85. data/autotest/discover.rb +0 -2
  86. data/lib/generators/puffer/install/templates/puffer.rb +0 -12
  87. data/lib/puffer/path_set.rb +0 -24
  88. data/spec/dummy/app/views/admin/users/index.html.erb +0 -3
  89. data/spec/dummy/config/initializers/puffer.rb +0 -12
  90. data/spec/dummy/db/schema.rb +0 -83
  91. data/spec/dummy/public/javascripts/application.js +0 -2
  92. data/spec/dummy/public/javascripts/controls.js +0 -965
  93. data/spec/dummy/public/javascripts/dragdrop.js +0 -974
  94. data/spec/dummy/public/javascripts/effects.js +0 -1123
  95. data/spec/dummy/public/javascripts/prototype.js +0 -6001
  96. data/spec/dummy/public/javascripts/rails.js +0 -175
  97. data/spec/dummy/public/puffer/javascripts/puffer.js +0 -10
  98. data/spec/dummy/public/puffer/javascripts/rails.js +0 -57
  99. data/spec/dummy/public/puffer/javascripts/right-autocompleter.js +0 -621
  100. data/spec/dummy/public/puffer/javascripts/right-calendar.js +0 -1461
  101. data/spec/dummy/public/puffer/javascripts/right.js +0 -5892
  102. data/spec/dummy/public/puffer/stylesheets/puffer.css +0 -469
  103. data/spec/dummy/public/puffer/stylesheets/reset.css +0 -60
  104. data/spec/dummy/public/stylesheets/.gitkeep +0 -0
  105. data/spec/lib/render_fallback_spec.rb +0 -17
@@ -1,175 +0,0 @@
1
- (function() {
2
- // Technique from Juriy Zaytsev
3
- // http://thinkweb2.com/projects/prototype/detecting-event-support-without-browser-sniffing/
4
- function isEventSupported(eventName) {
5
- var el = document.createElement('div');
6
- eventName = 'on' + eventName;
7
- var isSupported = (eventName in el);
8
- if (!isSupported) {
9
- el.setAttribute(eventName, 'return;');
10
- isSupported = typeof el[eventName] == 'function';
11
- }
12
- el = null;
13
- return isSupported;
14
- }
15
-
16
- function isForm(element) {
17
- return Object.isElement(element) && element.nodeName.toUpperCase() == 'FORM'
18
- }
19
-
20
- function isInput(element) {
21
- if (Object.isElement(element)) {
22
- var name = element.nodeName.toUpperCase()
23
- return name == 'INPUT' || name == 'SELECT' || name == 'TEXTAREA'
24
- }
25
- else return false
26
- }
27
-
28
- var submitBubbles = isEventSupported('submit'),
29
- changeBubbles = isEventSupported('change')
30
-
31
- if (!submitBubbles || !changeBubbles) {
32
- // augment the Event.Handler class to observe custom events when needed
33
- Event.Handler.prototype.initialize = Event.Handler.prototype.initialize.wrap(
34
- function(init, element, eventName, selector, callback) {
35
- init(element, eventName, selector, callback)
36
- // is the handler being attached to an element that doesn't support this event?
37
- if ( (!submitBubbles && this.eventName == 'submit' && !isForm(this.element)) ||
38
- (!changeBubbles && this.eventName == 'change' && !isInput(this.element)) ) {
39
- // "submit" => "emulated:submit"
40
- this.eventName = 'emulated:' + this.eventName
41
- }
42
- }
43
- )
44
- }
45
-
46
- if (!submitBubbles) {
47
- // discover forms on the page by observing focus events which always bubble
48
- document.on('focusin', 'form', function(focusEvent, form) {
49
- // special handler for the real "submit" event (one-time operation)
50
- if (!form.retrieve('emulated:submit')) {
51
- form.on('submit', function(submitEvent) {
52
- var emulated = form.fire('emulated:submit', submitEvent, true)
53
- // if custom event received preventDefault, cancel the real one too
54
- if (emulated.returnValue === false) submitEvent.preventDefault()
55
- })
56
- form.store('emulated:submit', true)
57
- }
58
- })
59
- }
60
-
61
- if (!changeBubbles) {
62
- // discover form inputs on the page
63
- document.on('focusin', 'input, select, texarea', function(focusEvent, input) {
64
- // special handler for real "change" events
65
- if (!input.retrieve('emulated:change')) {
66
- input.on('change', function(changeEvent) {
67
- input.fire('emulated:change', changeEvent, true)
68
- })
69
- input.store('emulated:change', true)
70
- }
71
- })
72
- }
73
-
74
- function handleRemote(element) {
75
- var method, url, params;
76
-
77
- var event = element.fire("ajax:before");
78
- if (event.stopped) return false;
79
-
80
- if (element.tagName.toLowerCase() === 'form') {
81
- method = element.readAttribute('method') || 'post';
82
- url = element.readAttribute('action');
83
- params = element.serialize();
84
- } else {
85
- method = element.readAttribute('data-method') || 'get';
86
- url = element.readAttribute('href');
87
- params = {};
88
- }
89
-
90
- new Ajax.Request(url, {
91
- method: method,
92
- parameters: params,
93
- evalScripts: true,
94
-
95
- onComplete: function(request) { element.fire("ajax:complete", request); },
96
- onSuccess: function(request) { element.fire("ajax:success", request); },
97
- onFailure: function(request) { element.fire("ajax:failure", request); }
98
- });
99
-
100
- element.fire("ajax:after");
101
- }
102
-
103
- function handleMethod(element) {
104
- var method = element.readAttribute('data-method'),
105
- url = element.readAttribute('href'),
106
- csrf_param = $$('meta[name=csrf-param]')[0],
107
- csrf_token = $$('meta[name=csrf-token]')[0];
108
-
109
- var form = new Element('form', { method: "POST", action: url, style: "display: none;" });
110
- element.parentNode.insert(form);
111
-
112
- if (method !== 'post') {
113
- var field = new Element('input', { type: 'hidden', name: '_method', value: method });
114
- form.insert(field);
115
- }
116
-
117
- if (csrf_param) {
118
- var param = csrf_param.readAttribute('content'),
119
- token = csrf_token.readAttribute('content'),
120
- field = new Element('input', { type: 'hidden', name: param, value: token });
121
- form.insert(field);
122
- }
123
-
124
- form.submit();
125
- }
126
-
127
-
128
- document.on("click", "*[data-confirm]", function(event, element) {
129
- var message = element.readAttribute('data-confirm');
130
- if (!confirm(message)) event.stop();
131
- });
132
-
133
- document.on("click", "a[data-remote]", function(event, element) {
134
- if (event.stopped) return;
135
- handleRemote(element);
136
- event.stop();
137
- });
138
-
139
- document.on("click", "a[data-method]", function(event, element) {
140
- if (event.stopped) return;
141
- handleMethod(element);
142
- event.stop();
143
- });
144
-
145
- document.on("submit", function(event) {
146
- var element = event.findElement(),
147
- message = element.readAttribute('data-confirm');
148
- if (message && !confirm(message)) {
149
- event.stop();
150
- return false;
151
- }
152
-
153
- var inputs = element.select("input[type=submit][data-disable-with]");
154
- inputs.each(function(input) {
155
- input.disabled = true;
156
- input.writeAttribute('data-original-value', input.value);
157
- input.value = input.readAttribute('data-disable-with');
158
- });
159
-
160
- var element = event.findElement("form[data-remote]");
161
- if (element) {
162
- handleRemote(element);
163
- event.stop();
164
- }
165
- });
166
-
167
- document.on("ajax:after", "form", function(event, element) {
168
- var inputs = element.select("input[type=submit][disabled=true][data-disable-with]");
169
- inputs.each(function(input) {
170
- input.value = input.readAttribute('data-original-value');
171
- input.removeAttribute('data-original-value');
172
- input.disabled = false;
173
- });
174
- });
175
- })();
@@ -1,10 +0,0 @@
1
- var association_done = function(event) {
2
- current = this.first('li.current');
3
- this.input.next('input[type=hidden]').value(current.get('data-id'));
4
- this.input.value(current.find('.title').first().html().stripTags()).disable();
5
- }
6
-
7
- '.association_clear'.on('click', function(event) {
8
- this.prev('input[type=text]').value('').enable();
9
- this.next('input[type=hidden]').value('');
10
- });
@@ -1,57 +0,0 @@
1
- (function(window, document, RightJS) {
2
-
3
- var $ = RightJS.$,
4
- $$ = RightJS.$$,
5
- $E = RightJS.$E,
6
- Xhr = RightJS.Xhr;
7
-
8
- var cancel = function(element) {
9
- var message = element.get('data-confirm');
10
- return(message && !confirm(message));
11
- }
12
-
13
- var xhr_events = function(element, options) {
14
- return Object.merge({
15
- onCreate: function() { element.fire('ajax:loading', this); },
16
- onComplete: function() { element.fire('ajax:complete', this); },
17
- onSuccess: function() { element.fire('ajax:success', this); },
18
- onFailure: function() { element.fire('ajax:failure', this); }
19
- }, options);
20
- };
21
-
22
- 'form[data-remote]'.on('submit', function(event) {
23
- event.stop();
24
- this.send();
25
- });
26
-
27
- 'a[data-confirm], a[data-method], a[data-remote]'.on('click', function(event) {
28
- if (cancel(this)) { event.stop(); return; }
29
-
30
- var method = this.get('data-method') || 'get',
31
- remote = !!this.get('data-remote'),
32
- url = this.get('href');
33
-
34
- if (method != 'get' || remote) { event.stop(); }
35
-
36
- if (remote) {
37
- Xhr.load(url, xhr_events(this, {
38
- method: method,
39
- spinner: this.get('data-spinner')
40
- }));
41
- }
42
-
43
- if (method != 'get') {
44
- var param = $$('meta[name=csrf-param]')[0].get('content'),
45
- token = $$('meta[name=csrf-token]')[0].get('content'),
46
- form = $E('form', {action: url, method: 'post'});
47
-
48
- if (param && token) {
49
- form.insert('<input type="hidden" name="' + param + '" value="' + token + '" />');
50
- }
51
-
52
- form.insert('<input type="hidden" name="_method" value="' + method + '"/>')
53
- .insertTo(document.body).submit();
54
- }
55
- });
56
-
57
- })(window, document, RightJS);
@@ -1,621 +0,0 @@
1
- /**
2
- * RightJS-UI: Autocompleter
3
- * http://rightjs.org/ui/autocompleter
4
- *
5
- * Copyright (C) 2010 Nikolay Nemshilov
6
- */
7
- var Autocompleter = RightJS.Autocompleter = (function(document, RightJS) {
8
- /**
9
- * This module defines the basic widgets constructor
10
- * it creates an abstract proxy with the common functionality
11
- * which then we reuse and override in the actual widgets
12
- *
13
- * Copyright (C) 2010-2011 Nikolay Nemshilov
14
- */
15
-
16
- /**
17
- * Autocompleter initializer
18
- *
19
- * Copyright (C) 2010 Nikolay Nemshilov
20
- */
21
- var R = RightJS,
22
- $ = RightJS.$,
23
- $w = RightJS.$w,
24
- $E = RightJS.$E,
25
- Xhr = RightJS.Xhr,
26
- RegExp = RightJS.RegExp,
27
- isArray = RightJS.isArray;
28
-
29
-
30
-
31
-
32
-
33
-
34
-
35
-
36
- /**
37
- * The widget units constructor
38
- *
39
- * @param String tag-name or Object methods
40
- * @param Object methods
41
- * @return Widget wrapper
42
- */
43
- function Widget(tag_name, methods) {
44
- if (!methods) {
45
- methods = tag_name;
46
- tag_name = 'DIV';
47
- }
48
-
49
- /**
50
- * An Abstract Widget Unit
51
- *
52
- * Copyright (C) 2010 Nikolay Nemshilov
53
- */
54
- var AbstractWidget = new RightJS.Class(RightJS.Element.Wrappers[tag_name] || RightJS.Element, {
55
- /**
56
- * The common constructor
57
- *
58
- * @param Object options
59
- * @param String optional tag name
60
- * @return void
61
- */
62
- initialize: function(key, options) {
63
- this.key = key;
64
- var args = [{'class': 'rui-' + key}];
65
-
66
- // those two have different constructors
67
- if (!(this instanceof RightJS.Input || this instanceof RightJS.Form)) {
68
- args.unshift(tag_name);
69
- }
70
- this.$super.apply(this, args);
71
-
72
- if (RightJS.isString(options)) {
73
- options = RightJS.$(options);
74
- }
75
-
76
- // if the options is another element then
77
- // try to dynamically rewrap it with our widget
78
- if (options instanceof RightJS.Element) {
79
- this._ = options._;
80
- if ('$listeners' in options) {
81
- options.$listeners = options.$listeners;
82
- }
83
- options = {};
84
- }
85
- this.setOptions(options, this);
86
-
87
- return (RightJS.Wrapper.Cache[RightJS.$uid(this._)] = this);
88
- },
89
-
90
- // protected
91
-
92
- /**
93
- * Catches the options
94
- *
95
- * @param Object user-options
96
- * @param Element element with contextual options
97
- * @return void
98
- */
99
- setOptions: function(options, element) {
100
- element = element || this;
101
- RightJS.Options.setOptions.call(this,
102
- RightJS.Object.merge(options, eval("("+(
103
- element.get('data-'+ this.key) || '{}'
104
- )+")"))
105
- );
106
- return this;
107
- }
108
- });
109
-
110
- /**
111
- * Creating the actual widget class
112
- *
113
- */
114
- var Klass = new RightJS.Class(AbstractWidget, methods);
115
-
116
- // creating the widget related shortcuts
117
- RightJS.Observer.createShortcuts(Klass.prototype, Klass.EVENTS || []);
118
-
119
- return Klass;
120
- }
121
-
122
-
123
- /**
124
- * A shared module to create textual spinners
125
- *
126
- * Copyright (C) 2010-2011 Nikolay Nemshilov
127
- */
128
- var Spinner = new RightJS.Class(RightJS.Element, {
129
- /**
130
- * Constructor
131
- *
132
- * @param Number optional spinner size (4 by default)
133
- * @return void
134
- */
135
- initialize: function(size) {
136
- this.$super('div', {'class': 'rui-spinner'});
137
- this.dots = [];
138
-
139
- for (var i=0; i < (size || 4); i++) {
140
- this.dots.push(new RightJS.Element('div'));
141
- }
142
-
143
- this.dots[0].addClass('glowing');
144
- this.insert(this.dots);
145
- RightJS(this.shift).bind(this).periodical(300);
146
- },
147
-
148
- /**
149
- * Shifts the spinner elements
150
- *
151
- * @return void
152
- */
153
- shift: function() {
154
- if (this.visible()) {
155
- var dot = this.dots.pop();
156
- this.dots.unshift(dot);
157
- this.insert(dot, 'top');
158
- }
159
- }
160
- });
161
-
162
-
163
- /**
164
- * A shared module that toggles a widget visibility status
165
- * in a uniformed way according to the options settings
166
- *
167
- * Copyright (C) 2010-2011 Nikolay Nemshilov
168
- */
169
- var Toggler = {
170
- /**
171
- * Shows the element
172
- *
173
- * @param String fx-name
174
- * @param Object fx-options
175
- * @return Element this
176
- */
177
- show: function(fx_name, fx_options) {
178
- this.constructor.current = this;
179
- return Toggler_toggle(this, 'show', fx_name, fx_options);
180
- },
181
-
182
- /**
183
- * Hides the element
184
- *
185
- * @param String fx-name
186
- * @param Object fx-options
187
- * @return Element this
188
- */
189
- hide: function(fx_name, fx_options) {
190
- this.constructor.current = null;
191
- return Toggler_toggle(this, 'show', fx_name, fx_options);
192
- },
193
-
194
- /**
195
- * Toggles the widget at the given element
196
- *
197
- * @param Element the related element
198
- * @param String position right/bottom (bottom is the default)
199
- * @param Boolean marker if the element should be resized to the element size
200
- * @return Widget this
201
- */
202
- showAt: function(element, where, resize) {
203
- this.hide(null).shownAt = element = RightJS.$(element);
204
-
205
- // moves this element at the given one
206
- Toggler_re_position.call(this, element, where, resize);
207
-
208
- return this.show();
209
- },
210
-
211
- /**
212
- * Toggles the widget at the given element
213
- *
214
- * @param Element the related element
215
- * @param String position top/left/right/bottom (bottom is the default)
216
- * @param Boolean marker if the element should be resized to the element size
217
- * @return Widget this
218
- */
219
- toggleAt: function(element, where, resize) {
220
- return this.hidden() ? this.showAt(element, where, resize) : this.hide();
221
- }
222
- };
223
-
224
-
225
- /**
226
- * toggles the element's state according to the current settings
227
- *
228
- * @param event String 'show' or 'hide' the event name
229
- * @param String an optional fx-name
230
- * @param Object an optional fx-options hash
231
- * @return void
232
- */
233
- function Toggler_toggle(element, event, fx_name, fx_options) {
234
- if (RightJS.Fx) {
235
- if (fx_name === undefined) {
236
- fx_name = element.options.fxName;
237
-
238
- if (fx_options === undefined) {
239
- fx_options = {
240
- duration: element.options.fxDuration,
241
- onFinish: RightJS(element.fire).bind(element, event)
242
- };
243
-
244
- // hide on double time
245
- if (event === 'hide') {
246
- fx_options.duration = (RightJS.Fx.Durations[fx_options.duration] ||
247
- fx_options.duration) / 2;
248
- }
249
- }
250
- }
251
- }
252
-
253
- // manually trigger the event if no fx were specified
254
- if (!RightJS.Fx || !fx_name) { element.fire(event); }
255
-
256
- return element.$super(fx_name, fx_options);
257
- }
258
-
259
- /**
260
- * Relatively positions the current element
261
- * against the specified one
262
- *
263
- * NOTE: this function is called in a context
264
- * of another element
265
- *
266
- * @param Element the target element
267
- * @param String position 'right' or 'bottom'
268
- * @param Boolean if `true` then the element size will be adjusted
269
- * @return void
270
- */
271
- function Toggler_re_position(element, where, resize) {
272
- var anchor = this.reAnchor || (this.reAnchor =
273
- new RightJS.Element('div', {'class': 'rui-re-anchor'}))
274
- .insert(this),
275
-
276
- pos = anchor.insertTo(element, 'after').position(),
277
- dims = element.dimensions(), target = this,
278
-
279
- border_top = parseInt(element.getStyle('borderTopWidth')),
280
- border_left = parseInt(element.getStyle('borderLeftWidth')),
281
- border_right = parseInt(element.getStyle('borderRightWidth')),
282
- border_bottom = parseInt(element.getStyle('borderBottomWidth')),
283
-
284
- top = dims.top - pos.y + border_top,
285
- left = dims.left - pos.x + border_left,
286
- width = dims.width - border_left - border_right,
287
- height = dims.height - border_top - border_bottom;
288
-
289
- // making the element to appear so we could read it's sizes
290
- target.setStyle('visibility:hidden').show(null);
291
-
292
- if (where === 'right') {
293
- left += width - target.size().x;
294
- } else { // bottom
295
- top += height;
296
- }
297
-
298
- target.moveTo(left, top);
299
-
300
- if (resize) {
301
- if (where === 'left' || where === 'right') {
302
- target.setHeight(height);
303
- } else {
304
- target.setWidth(width);
305
- }
306
- }
307
-
308
- // rolling the invisibility back
309
- target.setStyle('visibility:visible').hide(null);
310
- }
311
-
312
- /**
313
- * The RightJS UI Autocompleter unit base class
314
- *
315
- * Copyright (C) 2009-2011 Nikolay Nemshilov
316
- */
317
- var Autocompleter = new Widget('UL', {
318
- include: Toggler,
319
-
320
- extend: {
321
- version: '2.2.0',
322
-
323
- EVENTS: $w('show hide update load select done'),
324
-
325
- Options: {
326
- url: document.location.href,
327
- param: 'search',
328
- method: 'get',
329
-
330
- minLength: 1, // the minimal length when it starts work
331
- threshold: 200, // the typing pause threshold
332
-
333
- cache: true, // use the results cache
334
- local: null, // an optional local search results list
335
-
336
- fxName: 'slide', // list appearance fx name
337
- fxDuration: 'short', // list appearance fx duration
338
-
339
- spinner: 'native', // spinner element reference
340
-
341
- cssRule: 'input[data-autocompleter]' // the auto-initialization css-rule
342
- }
343
- },
344
-
345
- /**
346
- * basic constructor
347
- *
348
- * @param mixed the input element reference, a string id or the element instance
349
- * @param Object options
350
- */
351
- initialize: function(input, options) {
352
- this.input = $(input); // KEEP IT before the super call
353
-
354
- this
355
- .$super('autocompleter', options)
356
- .addClass('rui-dd-menu')
357
- .onMousedown(this.clicked);
358
-
359
- this.input.autocompleter = this;
360
- },
361
-
362
- /**
363
- * Destructor
364
- *
365
- * @return Autocompleter this
366
- */
367
- destroy: function() {
368
- delete(this.input.autocompleter);
369
- return this;
370
- },
371
-
372
- /**
373
- * picks the next item on the list
374
- *
375
- * @return Autocompleter this
376
- */
377
- prev: function() {
378
- return this.pick('prev');
379
- },
380
-
381
- /**
382
- * picks the next item on the list
383
- *
384
- * @return Autocompleter this
385
- */
386
- next: function() {
387
- return this.pick('next');
388
- },
389
-
390
- /**
391
- * triggers the done event, sets up the value and closes the list
392
- *
393
- * @return Autocompleter this
394
- */
395
- done: function(current) {
396
- current = current || this.first('li.current');
397
-
398
- if (current) {
399
- current.radioClass('current');
400
- this.input.setValue(R(current.html()).stripTags());
401
- this.fire('done');
402
- }
403
-
404
- return this.hide();
405
- },
406
-
407
- // protected
408
-
409
- // preprocessing the urls a bit
410
- setOptions: function(options) {
411
- this.$super(options, this.input);
412
-
413
- options = this.options;
414
-
415
- // building the correct url template with a placeholder
416
- if (!R(options.url).includes('%{search}')) {
417
- options.url += (R(options.url).includes('?') ? '&' : '?') + options.param + '=%{search}';
418
- }
419
- },
420
-
421
- // works with the 'prev' and 'next' methods
422
- pick: function(which_one) {
423
- var items = this.children(),
424
- current = items.first('hasClass', 'current'),
425
- index = items.indexOf(current);
426
-
427
- if (which_one == 'prev') {
428
- current = index < 1 ? items.last() : items[index < 0 ? 0 : (index-1)];
429
- } else if (which_one == 'next') {
430
- current = index < 0 || index == (items.length - 1) ?
431
- items.first() : items[index + 1];
432
- }
433
-
434
- return this.fire('select', {item: current.radioClass('current')});
435
- },
436
-
437
- // handles mouse clicks on the list element
438
- clicked: function(event) {
439
- this.done(event.stop().find('li'));
440
- },
441
-
442
- // handles the key-press events
443
- keypressed: function(event) {
444
- if (this.input.value().length >= this.options.minLength) {
445
- if (this.timeout) {
446
- this.timeout.cancel();
447
- }
448
- this.timeout = R(this.trigger).bind(this).delay(this.options.threshold);
449
- } else {
450
- return this.hide();
451
- }
452
- },
453
-
454
- // triggers the actual action
455
- trigger: function() {
456
- this.timeout = null;
457
-
458
- this.cache = this.cache || {};
459
- var search = this.input.value(), options = this.options;
460
-
461
- if (search.length < options.minLength) { return this.hide(); }
462
-
463
- if (this.cache[search]) {
464
- this.suggest(this.cache[search], search);
465
- } else if (isArray(options.local)) {
466
- this.suggest(this.findLocal(search), search);
467
- } else {
468
- this.request = Xhr.load(options.url.replace('%{search}', encodeURIComponent(search)), {
469
- method: options.method,
470
- spinner: this.getSpinner(),
471
- onComplete: R(function(response) {
472
- this.fire('load').suggest(response.text, search);
473
- }).bind(this)
474
- });
475
- }
476
- },
477
-
478
- // updates the suggestions list
479
- suggest: function(result_text, search) {
480
- // saving the result in cache
481
- if (this.options.cache) {
482
- this.cache[search] = result_text;
483
- }
484
-
485
- if (!R(result_text).blank()) {
486
- this.update(result_text.replace(/<ul[^>]*>|<\/ul>/im, ''));
487
- this.fire('update');
488
- if (!this._connected || this.hidden()) {
489
- this.showAt(this.input, 'bottom', 'resize');
490
- this._connected = true;
491
- }
492
- } else {
493
- this.hide();
494
- }
495
-
496
- return this;
497
- },
498
-
499
- // performs the locals search
500
- findLocal: function(search) {
501
- var regexp = new RegExp("("+RegExp.escape(search)+")", 'ig');
502
-
503
- return R(this.options.local).map(function(option) {
504
- if (option.match(regexp)) {
505
- return '<li>'+ option.replace(regexp, '<strong>$1</strong>') +'</li>';
506
- }
507
- }).compact().join('');
508
- },
509
-
510
- // builds a native textual spinner if necessary
511
- getSpinner: function() {
512
- var options = this.options, spinner = options.spinner;
513
-
514
- if (spinner == 'native') {
515
- spinner = options.spinner = new Spinner(3).insertTo(this);
516
- spinner.addClass('rui-autocompleter-spinner');
517
- }
518
-
519
- // positioning the native spinner
520
- if (spinner instanceof Spinner) {
521
- Toggler_re_position.call(spinner, this.input, 'right', 'resize');
522
- }
523
-
524
- return spinner;
525
- }
526
- });
527
-
528
-
529
- /**
530
- * The document events hooking
531
- *
532
- * Copyright (C) 2009-2010 Nikolay Nemshilov
533
- */
534
- $(document).on({
535
- /**
536
- * Initializes autocompleters on-focus
537
- *
538
- * @param Event focus
539
- * @return void
540
- */
541
- focus: function(event) {
542
- var target = event.target;
543
-
544
- if (target && (target instanceof RightJS.Element) && (target.autocompleter || target.match(Autocompleter.Options.cssRule))) {
545
- if (!target.autocompleter) {
546
- new Autocompleter(target);
547
- }
548
- }
549
- },
550
-
551
- /**
552
- * Hides autocompleters on-blur
553
- *
554
- * @param Event blur
555
- * @return void
556
- */
557
- blur: function(event) {
558
- var autocompleter = event.target ? event.target.autocompleter : null;
559
-
560
- if (autocompleter && autocompleter.visible()) {
561
- autocompleter.hide();
562
- }
563
- },
564
-
565
- /**
566
- * Catching the basic keyboard events
567
- * to navigate through the autocompletion list
568
- *
569
- * @param Event keydown
570
- * @return void
571
- */
572
- keydown: function(event) {
573
- var autocompleter = event.target ? event.target.autocompleter : null;
574
-
575
- if (autocompleter && autocompleter.visible()) {
576
- var method_name = ({
577
- 27: 'hide', // Esc
578
- 38: 'prev', // Up
579
- 40: 'next', // Down
580
- 13: 'done' // Enter
581
- })[event.keyCode];
582
-
583
- if (method_name) {
584
- event.stop();
585
- autocompleter[method_name]();
586
- }
587
- }
588
- },
589
-
590
- /**
591
- * Catches the input fields keyup events
592
- * and tries to make the autocompleter to show some suggestions
593
- *
594
- * @param Event keyup
595
- * @return void
596
- */
597
- keyup: function(event) {
598
- var autocompleter = event.target ? event.target.autocompleter : null;
599
-
600
- if (autocompleter && !R([9, 27, 37, 38, 39, 40, 13]).include(event.keyCode)) {
601
- autocompleter.keypressed(event);
602
- }
603
- }
604
- });
605
- (function() {
606
- var style = document.createElement('style'),
607
- rules = document.createTextNode(" *.rui-dd-menu, *.rui-dd-menu li{margin:0;padding:0;border:none;background:none;list-style:none;font-weight:normal;float:none} *.rui-dd-menu{display:none;position:absolute;z-index:9999;background:white;border:1px solid #BBB;border-radius:.2em;-moz-border-radius:.2em;-webkit-border-radius:.2em;box-shadow:#DDD .2em .2em .4em;-moz-box-shadow:#DDD .2em .2em .4em;-webkit-box-shadow:#DDD .2em .2em .4em} *.rui-dd-menu li{padding:.2em .4em;border-top:none;border-bottom:none;cursor:pointer} *.rui-dd-menu li.current{background:#DDD} *.rui-dd-menu li:hover{background:#EEE}dl.rui-dd-menu dt{padding:.3em .5em;cursor:default;font-weight:bold;font-style:italic;color:#444;background:#EEE}dl.rui-dd-menu dd li{padding-left:1.5em}div.rui-spinner,div.rui-spinner div{margin:0;padding:0;border:none;background:none;list-style:none;font-weight:normal;float:none;display:inline-block; *display:inline; *zoom:1;border-radius:.12em;-moz-border-radius:.12em;-webkit-border-radius:.12em}div.rui-spinner{text-align:center;white-space:nowrap;background:#EEE;border:1px solid #DDD;height:1.2em;padding:0 .2em}div.rui-spinner div{width:.4em;height:70%;background:#BBB;margin-left:1px}div.rui-spinner div:first-child{margin-left:0}div.rui-spinner div.glowing{background:#777}div.rui-re-anchor{margin:0;padding:0;background:none;border:none;float:none;display:inline;position:absolute;z-index:9999}.rui-autocompleter{border-top-color:#DDD !important;border-top-left-radius:0 !important;border-top-right-radius:0 !important;-moz-border-radius-topleft:0 !important;-moz-border-radius-topright:0 !important;-webkit-border-top-left-radius:0 !important;-webkit-border-top-right-radius:0 !important}.rui-autocompleter-spinner{border:none !important;background:none !important;position:absolute;z-index:9999}.rui-autocompleter-spinner div{margin-top:.2em !important; *margin-top:0.1em !important}");
608
-
609
- style.type = 'text/css';
610
-
611
- if(style.styleSheet) {
612
- style.styleSheet.cssText = rules.nodeValue;
613
- } else {
614
- style.appendChild(rules);
615
- }
616
-
617
- document.getElementsByTagName('head')[0].appendChild(style);
618
- })();
619
-
620
- return Autocompleter;
621
- })(document, RightJS);