Merge commit 'a4cb4d96face514924387d34746b3148848ac092' into zope-2.13
[Plinn.git] / skins / ajax_scripts / input_completion.js
1 // © Benoît PIN 2008
2 // http://plinn.org
3 // Licence GPL
4 //
5 //
6 // Form completion utils
7
8 // public names
9 var TextInputCompletion;
10
11 (function(){
12
13 UID_ATTEMPT = 8;
14
15 TextInputCompletion = function(input, url) {
16 this.url = url;
17 this.input = input;
18 this.previousValue = this.input.value;
19
20 var thisManager = this;
21 addListener(this.input, 'keyup', function(evt) { thisManager._inputComplete(evt); });
22 addListener(this.input, 'blur', function(evt) {thisManager._inputQuit(evt);});
23 this.input.cancelNextSubmit = true;
24
25 var uid;
26 for (var i=0 ; i<UID_ATTEMPT ;i++) {
27 uid = Math.random().toString().slice(2);
28 uid = 'completions' + uid;
29 if (!document.getElementById(uid))
30 break;
31 }
32
33 var completions = document.createElement('div');
34 completions.id = uid;
35 completions.style.position = 'relative';
36 completions.style.top = getObjectHeight(input) + 'px';
37
38 var parent = input.parentNode;
39 parent.insertBefore(completions, input);
40
41 this.completions = completions;
42 addListener(this.completions, 'click',
43 function(evt){thisManager.selectCompletion(getEventObject(evt));}
44 );
45 this.selectedCompletion = null;
46 }
47
48
49 TextInputCompletion.prototype._inputComplete = function(evt) {
50 var currentValue = this.input.value;
51 if (currentValue == this.previousValue)
52 this.selectCompletion(getEventObject(evt));
53 else {
54 var url = this.url + '?value=' + encodeURIComponent(currentValue);
55 url = url + '&uid=' + this.completions.id;
56 var thisManager = this;
57 var fi = new FragmentImporter(url, function(){thisManager.completeIfOneResult() })
58 fi.load();
59 }
60 };
61
62 TextInputCompletion.prototype._inputQuit = function(evt) {
63 if (this.selectedCompletion) {
64 try {
65 this.copyCompletion(this.selectedCompletion);
66 }
67 catch(e){}
68 }
69 this.selectedCompletion = null;
70 thisCompleter = this
71 setTimeout(function(){thisCompleter.completions.innerHTML='';}, 200);
72 };
73
74 TextInputCompletion.prototype.selectCompletion = function(evt) {
75 var res = this.completions.getElementsByTagName('li');
76 if (!res) return;
77
78 if (evt.type == 'keyup') {
79 var newSelection = false;
80 switch(evt.keyCode) {
81 case 40: // down key
82 if (!this.selectedCompletion) {
83 this.selectedCompletion = res[0];
84 newSelection = true;
85 }
86 else if (this.selectedCompletion.nextSibling) {
87 this.selectedCompletion.className = '';
88 this.selectedCompletion = this.selectedCompletion.nextSibling;
89 newSelection = true;
90 }
91 break;
92 case 38: // up key
93 if (this.selectedCompletion && this.selectedCompletion.previousSibling) {
94 this.selectedCompletion.className = '';
95 this.selectedCompletion = this.selectedCompletion.previousSibling;
96 newSelection = true;
97 }
98 break;
99 case 13: // enter key
100 if (this.selectedCompletion) {
101 this.copyCompletion(this.selectedCompletion);
102 this.completions.innerHTML = '';
103 this.input.cancelNextSubmit = true;
104 return;
105 }
106 break
107 }
108 if (newSelection) {
109 this.selectedCompletion.className = 'selected';
110 this.copyCompletion(this.selectedCompletion);
111 }
112 }
113 else if (evt.type=='click') {
114 this.selectedCompletion = getTargetedObject(evt);
115 this.copyCompletion(this.selectedCompletion);
116 }
117 }
118
119 TextInputCompletion.prototype.copyCompletion = function(completion) {
120 this.input.value = this.previousValue = completion.firstChild.nodeValue;
121 }
122
123 TextInputCompletion.prototype.completeIfOneResult = function() {
124 this.selectedCompletion = null;
125 var currentValue = this.input.value;
126
127 if (this.previousValue.length < currentValue.length) {
128 var res = this.completions.getElementsByTagName('li');
129 if (res.length == 1) {
130 var completion = res[0];
131 this.copyCompletion(completion);
132 this.completions.innerHTML = '';
133 }
134 }
135
136 this.previousValue = currentValue;
137 };
138
139 })();