javascripts/right-autocompleter-src.js in right-rails-0.4.4 vs javascripts/right-autocompleter-src.js in right-rails-0.5.0
- old
+ new
@@ -1,18 +1,18 @@
/**
* The autocompletion feature implemented with RightJS
*
* Home page: http://rightjs.org/ui/autocompleter
*
- * @copyright (C) 2009 Nikolay V. Nemshilov aka St.
+ * @copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
if (!RightJS) { throw "Gimme RightJS. Please." };
/**
* The RightJS UI Autocompleter unit base class
*
- * Copyright (C) Nikolay V. Nemshilov aka St.
+ * Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
var Autocompleter = new Class(Observer, {
extend: {
EVENTS: $w('show hide update load select done'),
@@ -25,63 +25,53 @@
threshold: 200, // the typing pause threshold
cache: true, // the use the results cache
local: null, // an optional local search results list
- fxName: 'slide',
- fxDuration: 'short',
+ fxName: 'slide', // list appearance fx name
+ fxDuration: 'short', // list appearance fx duration
- spinner: 'native',
+ spinner: 'native', // spinner element reference
- relName: 'autocompleter'
+ cssRule: '[rel^=autocompleter]'
},
- // scans the document for autocompletion fields
- rescan: function(scope) {
- var key = Autocompleter.Options.relName;
- var reg = new RegExp('^'+key+'+\\[(.*?)\\]$');
-
- ($(scope)||document).select('input[rel^="'+key+'"]').each(function(input) {
- if (!input.autocompleter) {
- var data = input.get('data-'+key+'-options');
- var options = Object.merge(eval('('+data+')'));
- var match = input.get('rel').match(reg);
-
- if (match) {
- var url = match[1];
-
- // if looks like a list of local options
- if (url.match(/^['"].*?['"]$/)) {
- options.local = eval('['+url+']');
- } else if (!url.blank()) {
- options.url = url;
- }
- }
-
- new Autocompleter(input, options);
- }
- });
- }
+ current: null, // reference to the currently active options list
+ instances: {}, // the input <-> instance map
+
+ // finds/instances an autocompleter for the event
+ find: function(event) {
+ var input = event.target;
+ if (input.match(Autocompleter.Options.cssRule)) {
+ var uid = $uid(input);
+ if (!Autocompleter.instances[uid])
+ new Autocompleter(input);
+ }
+ },
+
+ // DEPRECATED scans the document for autocompletion fields
+ rescan: function(scope) { }
},
/**
* basic constructor
*
* @param mixed the input element reference, a string id or the element instance
* @param Object options
*/
initialize: function(input, options) {
+ this.input = $(input); // don't low it down!
this.$super(options);
// storing the callbacks so we could detach them later
this._watch = this.watch.bind(this);
this._hide = this.hide.bind(this);
- this.input = $(input).onKeyup(this._watch).onBlur(this._hide);
+ this.input.onKeyup(this._watch).onBlur(this._hide);
this.container = $E('div', {'class': 'autocompleter'}).insertTo(this.input, 'after');
- this.input.autocompleter = this;
+ this.input.autocompleter = Autocompleter.instances[$uid(input)] = this;
},
// kills the autocompleter
destroy: function() {
this.input.stopObserving('keyup', this._watch).stopObserving('blur', this._hide);
@@ -89,11 +79,11 @@
return this;
},
// catching up with some additonal options
setOptions: function(options) {
- this.$super(options);
+ this.$super(this.grabOptions(options));
// building the correct url template with a placeholder
if (!this.options.url.includes('%{search}')) {
this.options.url += (this.options.url.includes('?') ? '&' : '?') + this.options.param + '=%{search}';
}
@@ -149,10 +139,32 @@
return this.fire('done').hide();
},
// protected
+ // trying to extract the input element options
+ grabOptions: function(options) {
+ var input = this.input;
+ var options = options || eval('('+input.get('data-autocompleter-options')+')') || {};
+ var keys = Autocompleter.Options.cssRule.split('[').last().split(']')[0].split('^='),
+ key = keys[1], value = input.get(keys[0]), match;
+
+ // trying to extract options
+ if (value && (match = value.match(new RegExp('^'+ key +'+\\[(.*?)\\]$')))) {
+ match = match[1];
+
+ // deciding whether it's a list of local options or an url
+ if (match.match(/^['"].*?['"]$/)) {
+ options.local = eval('['+ match +']');
+ } else if (!match.blank()) {
+ options.url = match;
+ }
+ }
+
+ return options;
+ },
+
// works with the 'prev' and 'next' methods
select: function(what, fallback) {
var current = this.container.first('li.current');
if (current) {
current = current[what]('li') || current;
@@ -161,11 +173,11 @@
return this.fire('select', (current || fallback).radioClass('current'));
},
// receives the keyboard events out of the input element
watch: function(event) {
- // skip the overlaping key codes that are already watched in the hooker.js
+ // skip the overlaping key codes that are already watched in the document.js
if ([27,37,38,39,40,13].include(event.keyCode)) return;
if (this.input.value.length >= this.options.minLength) {
if (this.timeout) {
this.timeout.cancel();
@@ -271,19 +283,16 @@
});
/**
* The document events hooking
*
- * Copyright (C) Nikolay V. Nemshilov aka St.
+ * Copyright (C) 2009-2010 Nikolay V. Nemshilov
*/
document.on({
- ready: function() {
- Autocompleter.rescan();
- },
-
// the autocompletion list navigation
keydown: function(event) {
+ // if there is an active options list, hijacking the navigation buttons
if (Autocompleter.current) {
var name;
switch (event.keyCode) {
case 27: name = 'hide'; break;
@@ -296,9 +305,14 @@
if (name) {
Autocompleter.current[name]();
event.stop();
}
+ }
+
+ // otherwise trying to find/instanciate an autocompliter
+ else {
+ Autocompleter.find(event);
}
}
});
document.write("<style type=\"text/css\">div.autocompleter{display:none;position:absolute;z-index:100000000;border:none;margin:0;padding:0;background:white;-moz-box-shadow:#BBB .2em .2em .4em;-webkit-box-shadow:#BBB .2em .2em .4em;overflow:hidden}div.autocompleter ul{list-style:none;margin:0;padding:0;border:none;background:none;*border-bottom:1px solid #CCC}div.autocompleter ul li{list-style:none;font-weight:normal;margin:0;padding:.2em .4em;border:1px solid #CCC;border-top:none;border-bottom:none;background:none;cursor:pointer}div.autocompleter ul li:first-child{border-top:1px solid #CCC}div.autocompleter ul li:last-child{border-bottom:1px solid #CCC;*border-bottom:none}div.autocompleter ul li.current{background:#DDD}div.autocompleter-spinner{position:absolute;z-index:100000000;text-align:center;font-size:140%;font-family:Georgia;background:#DDD;color:#666;display:none;width:1em;margin:0;padding:0}div.autocompleter-spinner div.dot-1{margin-left:-4px}div.autocompleter-spinner div.dot-2{}div.autocompleter-spinner div.dot-3{margin-left:4px}</style>");
\ No newline at end of file