Revision 1070d60b
Factorisation de l'utilisation des bibliothèques JS
git-svn-id: https://vigilo-dev.si.c-s.fr/svn@6851 b22e2e97-25c9-44ff-b637-2e5ceca36478
vigigraph/public/js/libs/Autocompleter/Autocompleter.Local.js | ||
---|---|---|
1 |
/** |
|
2 |
* Autocompleter.Local |
|
3 |
* |
|
4 |
* http://digitarald.de/project/autocompleter/ |
|
5 |
* |
|
6 |
* @version 1.1.2 |
|
7 |
* |
|
8 |
* @license MIT-style license |
|
9 |
* @author Harald Kirschner <mail [at] digitarald.de> |
|
10 |
* @copyright Author |
|
11 |
*/ |
|
12 |
|
|
13 |
Autocompleter.Local = new Class({ |
|
14 |
|
|
15 |
Extends: Autocompleter, |
|
16 |
|
|
17 |
options: { |
|
18 |
minLength: 0, |
|
19 |
delay: 200 |
|
20 |
}, |
|
21 |
|
|
22 |
initialize: function(element, tokens, options) { |
|
23 |
this.parent(element, options); |
|
24 |
this.tokens = tokens; |
|
25 |
}, |
|
26 |
|
|
27 |
query: function() { |
|
28 |
this.update(this.filter()); |
|
29 |
} |
|
30 |
|
|
31 |
}); |
vigigraph/public/js/libs/Autocompleter/Autocompleter.Request.js | ||
---|---|---|
1 |
/** |
|
2 |
* Autocompleter.Request |
|
3 |
* |
|
4 |
* http://digitarald.de/project/autocompleter/ |
|
5 |
* |
|
6 |
* @version 1.1.2 |
|
7 |
* |
|
8 |
* @license MIT-style license |
|
9 |
* @author Harald Kirschner <mail [at] digitarald.de> |
|
10 |
* @copyright Author |
|
11 |
*/ |
|
12 |
|
|
13 |
Autocompleter.Request = new Class({ |
|
14 |
|
|
15 |
Extends: Autocompleter, |
|
16 |
|
|
17 |
options: {/* |
|
18 |
indicator: null, |
|
19 |
indicatorClass: null, |
|
20 |
onRequest: $empty, |
|
21 |
onComplete: $empty,*/ |
|
22 |
postData: {}, |
|
23 |
ajaxOptions: {}, |
|
24 |
postVar: 'value' |
|
25 |
|
|
26 |
}, |
|
27 |
|
|
28 |
query: function(){ |
|
29 |
var data = $unlink(this.options.postData) || {}; |
|
30 |
data[this.options.postVar] = this.queryValue; |
|
31 |
var indicator = $(this.options.indicator); |
|
32 |
if (indicator) indicator.setStyle('display', ''); |
|
33 |
var cls = this.options.indicatorClass; |
|
34 |
if (cls) this.element.addClass(cls); |
|
35 |
this.fireEvent('onRequest', [this.element, this.request, data, this.queryValue]); |
|
36 |
this.request.send({'data': data}); |
|
37 |
}, |
|
38 |
|
|
39 |
/** |
|
40 |
* queryResponse - abstract |
|
41 |
* |
|
42 |
* Inherated classes have to extend this function and use this.parent() |
|
43 |
*/ |
|
44 |
queryResponse: function() { |
|
45 |
var indicator = $(this.options.indicator); |
|
46 |
if (indicator) indicator.setStyle('display', 'none'); |
|
47 |
var cls = this.options.indicatorClass; |
|
48 |
if (cls) this.element.removeClass(cls); |
|
49 |
return this.fireEvent('onComplete', [this.element, this.request]); |
|
50 |
} |
|
51 |
|
|
52 |
}); |
|
53 |
|
|
54 |
Autocompleter.Request.JSON = new Class({ |
|
55 |
|
|
56 |
Extends: Autocompleter.Request, |
|
57 |
|
|
58 |
initialize: function(el, url, options) { |
|
59 |
this.parent(el, options); |
|
60 |
this.request = new Request.JSON($merge({ |
|
61 |
'url': url, |
|
62 |
'link': 'cancel' |
|
63 |
}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this)); |
|
64 |
}, |
|
65 |
|
|
66 |
queryResponse: function(response) { |
|
67 |
this.parent(); |
|
68 |
this.update(response); |
|
69 |
} |
|
70 |
|
|
71 |
}); |
|
72 |
|
|
73 |
Autocompleter.Request.HTML = new Class({ |
|
74 |
|
|
75 |
Extends: Autocompleter.Request, |
|
76 |
|
|
77 |
initialize: function(el, url, options) { |
|
78 |
this.parent(el, options); |
|
79 |
this.request = new Request.HTML($merge({ |
|
80 |
'url': url, |
|
81 |
'link': 'cancel', |
|
82 |
'update': this.choices |
|
83 |
}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this)); |
|
84 |
}, |
|
85 |
|
|
86 |
queryResponse: function(tree, elements) { |
|
87 |
this.parent(); |
|
88 |
if (!elements || !elements.length) { |
|
89 |
this.hideChoices(); |
|
90 |
} else { |
|
91 |
this.choices.getChildren(this.options.choicesMatch).each(this.options.injectChoice || function(choice) { |
|
92 |
var value = choice.innerHTML; |
|
93 |
choice.inputValue = value; |
|
94 |
this.addChoiceEvents(choice.set('html', this.markQueryValue(value))); |
|
95 |
}, this); |
|
96 |
this.showChoices(); |
|
97 |
} |
|
98 |
|
|
99 |
} |
|
100 |
|
|
101 |
}); |
|
102 |
|
|
103 |
/* compatibility */ |
|
104 |
|
|
105 |
Autocompleter.Ajax = { |
|
106 |
Base: Autocompleter.Request, |
|
107 |
Json: Autocompleter.Request.JSON, |
|
108 |
Xhtml: Autocompleter.Request.HTML |
|
109 |
}; |
vigigraph/public/js/libs/Autocompleter/Autocompleter.js | ||
---|---|---|
1 |
/** |
|
2 |
* Autocompleter |
|
3 |
* |
|
4 |
* http://digitarald.de/project/autocompleter/ |
|
5 |
* |
|
6 |
* @version 1.1.2 |
|
7 |
* |
|
8 |
* @license MIT-style license |
|
9 |
* @author Harald Kirschner <mail [at] digitarald.de> |
|
10 |
* @copyright Author |
|
11 |
*/ |
|
12 |
|
|
13 |
var Autocompleter = new Class({ |
|
14 |
|
|
15 |
Implements: [Options, Events], |
|
16 |
|
|
17 |
options: {/* |
|
18 |
onOver: $empty, |
|
19 |
onSelect: $empty, |
|
20 |
onSelection: $empty, |
|
21 |
onShow: $empty, |
|
22 |
onHide: $empty, |
|
23 |
onBlur: $empty, |
|
24 |
onFocus: $empty,*/ |
|
25 |
minLength: 1, |
|
26 |
markQuery: true, |
|
27 |
width: 'inherit', |
|
28 |
maxChoices: 10, |
|
29 |
injectChoice: null, |
|
30 |
customChoices: null, |
|
31 |
emptyChoices: null, |
|
32 |
visibleChoices: true, |
|
33 |
className: 'autocompleter-choices', |
|
34 |
zIndex: 42, |
|
35 |
delay: 400, |
|
36 |
observerOptions: {}, |
|
37 |
fxOptions: {}, |
|
38 |
|
|
39 |
autoSubmit: false, |
|
40 |
overflow: false, |
|
41 |
overflowMargin: 25, |
|
42 |
selectFirst: false, |
|
43 |
filter: null, |
|
44 |
filterCase: false, |
|
45 |
filterSubset: false, |
|
46 |
forceSelect: false, |
|
47 |
selectMode: true, |
|
48 |
choicesMatch: null, |
|
49 |
|
|
50 |
multiple: false, |
|
51 |
separator: ', ', |
|
52 |
separatorSplit: /\s*[,;]\s*/, |
|
53 |
autoTrim: false, |
|
54 |
allowDupes: false, |
|
55 |
|
|
56 |
cache: true, |
|
57 |
relative: false |
|
58 |
}, |
|
59 |
|
|
60 |
initialize: function(element, options) { |
|
61 |
this.element = $(element); |
|
62 |
this.setOptions(options); |
|
63 |
this.build(); |
|
64 |
this.observer = new Observer(this.element, this.prefetch.bind(this), $merge({ |
|
65 |
'delay': this.options.delay |
|
66 |
}, this.options.observerOptions)); |
|
67 |
this.queryValue = null; |
|
68 |
if (this.options.filter) this.filter = this.options.filter.bind(this); |
|
69 |
var mode = this.options.selectMode; |
|
70 |
this.typeAhead = (mode == 'type-ahead'); |
|
71 |
this.selectMode = (mode === true) ? 'selection' : mode; |
|
72 |
this.cached = []; |
|
73 |
}, |
|
74 |
|
|
75 |
/** |
|
76 |
* build - Initialize DOM |
|
77 |
* |
|
78 |
* Builds the html structure for choices and appends the events to the element. |
|
79 |
* Override this function to modify the html generation. |
|
80 |
*/ |
|
81 |
build: function() { |
|
82 |
if ($(this.options.customChoices)) { |
|
83 |
this.choices = this.options.customChoices; |
|
84 |
} else { |
|
85 |
this.choices = new Element('ul', { |
|
86 |
'class': this.options.className, |
|
87 |
'styles': { |
|
88 |
'zIndex': this.options.zIndex |
|
89 |
} |
|
90 |
}).inject(document.body); |
|
91 |
this.relative = false; |
|
92 |
if (this.options.relative) { |
|
93 |
this.choices.inject(this.element, 'after'); |
|
94 |
this.relative = this.element.getOffsetParent(); |
|
95 |
} |
|
96 |
this.fix = new OverlayFix(this.choices); |
|
97 |
} |
|
98 |
if (!this.options.separator.test(this.options.separatorSplit)) { |
|
99 |
this.options.separatorSplit = this.options.separator; |
|
100 |
} |
|
101 |
this.fx = (!this.options.fxOptions) ? null : new Fx.Tween(this.choices, $merge({ |
|
102 |
'property': 'opacity', |
|
103 |
'link': 'cancel', |
|
104 |
'duration': 200 |
|
105 |
}, this.options.fxOptions)).addEvent('onStart', Chain.prototype.clearChain).set(0); |
|
106 |
this.element.setProperty('autocomplete', 'off') |
|
107 |
.addEvent((Browser.Engine.trident || Browser.Engine.webkit) ? 'keydown' : 'keypress', this.onCommand.bind(this)) |
|
108 |
.addEvent('click', this.onCommand.bind(this, [false])) |
|
109 |
.addEvent('focus', this.toggleFocus.create({bind: this, arguments: true, delay: 100})) |
|
110 |
.addEvent('blur', this.toggleFocus.create({bind: this, arguments: false, delay: 100})); |
|
111 |
}, |
|
112 |
|
|
113 |
destroy: function() { |
|
114 |
if (this.fix) this.fix.destroy(); |
|
115 |
this.choices = this.selected = this.choices.destroy(); |
|
116 |
}, |
|
117 |
|
|
118 |
toggleFocus: function(state) { |
|
119 |
this.focussed = state; |
|
120 |
if (!state) this.hideChoices(true); |
|
121 |
this.fireEvent((state) ? 'onFocus' : 'onBlur', [this.element]); |
|
122 |
}, |
|
123 |
|
|
124 |
onCommand: function(e) { |
|
125 |
if (!e && this.focussed) return this.prefetch(); |
|
126 |
if (e && e.key && !e.shift) { |
|
127 |
switch (e.key) { |
|
128 |
case 'enter': |
|
129 |
if (this.element.value != this.opted) return true; |
|
130 |
if (this.selected && this.visible) { |
|
131 |
this.choiceSelect(this.selected); |
|
132 |
return !!(this.options.autoSubmit); |
|
133 |
} |
|
134 |
break; |
|
135 |
case 'up': case 'down': |
|
136 |
if (!this.prefetch() && this.queryValue !== null) { |
|
137 |
var up = (e.key == 'up'); |
|
138 |
this.choiceOver((this.selected || this.choices)[ |
|
139 |
(this.selected) ? ((up) ? 'getPrevious' : 'getNext') : ((up) ? 'getLast' : 'getFirst') |
|
140 |
](this.options.choicesMatch), true); |
|
141 |
} |
|
142 |
return false; |
|
143 |
case 'esc': case 'tab': |
|
144 |
this.hideChoices(true); |
|
145 |
break; |
|
146 |
} |
|
147 |
} |
|
148 |
return true; |
|
149 |
}, |
|
150 |
|
|
151 |
setSelection: function(finish) { |
|
152 |
var input = this.selected.inputValue, value = input; |
|
153 |
var start = this.queryValue.length, end = input.length; |
|
154 |
if (input.substr(0, start).toLowerCase() != this.queryValue.toLowerCase()) start = 0; |
|
155 |
if (this.options.multiple) { |
|
156 |
var split = this.options.separatorSplit; |
|
157 |
value = this.element.value; |
|
158 |
start += this.queryIndex; |
|
159 |
end += this.queryIndex; |
|
160 |
var old = value.substr(this.queryIndex).split(split, 1)[0]; |
|
161 |
value = value.substr(0, this.queryIndex) + input + value.substr(this.queryIndex + old.length); |
|
162 |
if (finish) { |
|
163 |
var tokens = value.split(this.options.separatorSplit).filter(function(entry) { |
|
164 |
return this.test(entry); |
|
165 |
}, /[^\s,]+/); |
|
166 |
if (!this.options.allowDupes) tokens = [].combine(tokens); |
|
167 |
var sep = this.options.separator; |
|
168 |
value = tokens.join(sep) + sep; |
|
169 |
end = value.length; |
|
170 |
} |
|
171 |
} |
|
172 |
this.observer.setValue(value); |
|
173 |
this.opted = value; |
|
174 |
if (finish || this.selectMode == 'pick') start = end; |
|
175 |
this.element.selectRange(start, end); |
|
176 |
this.fireEvent('onSelection', [this.element, this.selected, value, input]); |
|
177 |
}, |
|
178 |
|
|
179 |
showChoices: function() { |
|
180 |
var match = this.options.choicesMatch, first = this.choices.getFirst(match); |
|
181 |
this.selected = this.selectedValue = null; |
|
182 |
if (this.fix) { |
|
183 |
var pos = this.element.getCoordinates(this.relative), width = this.options.width || 'auto'; |
|
184 |
this.choices.setStyles({ |
|
185 |
'left': pos.left, |
|
186 |
'top': pos.bottom, |
|
187 |
'width': (width === true || width == 'inherit') ? pos.width : width |
|
188 |
}); |
|
189 |
} |
|
190 |
if (!first) return; |
|
191 |
if (!this.visible) { |
|
192 |
this.visible = true; |
|
193 |
this.choices.setStyle('display', ''); |
|
194 |
if (this.fx) this.fx.start(1); |
|
195 |
this.fireEvent('onShow', [this.element, this.choices]); |
|
196 |
} |
|
197 |
if (this.options.selectFirst || this.typeAhead || first.inputValue == this.queryValue) this.choiceOver(first, this.typeAhead); |
|
198 |
var items = this.choices.getChildren(match), max = this.options.maxChoices; |
|
199 |
var styles = {'overflowY': 'hidden', 'height': ''}; |
|
200 |
this.overflown = false; |
|
201 |
if (items.length > max) { |
|
202 |
var item = items[max - 1]; |
|
203 |
styles.overflowY = 'scroll'; |
|
204 |
styles.height = item.getCoordinates(this.choices).bottom; |
|
205 |
this.overflown = true; |
|
206 |
}; |
|
207 |
this.choices.setStyles(styles); |
|
208 |
this.fix.show(); |
|
209 |
if (this.options.visibleChoices) { |
|
210 |
var scroll = document.getScroll(), |
|
211 |
size = document.getSize(), |
|
212 |
coords = this.choices.getCoordinates(); |
|
213 |
if (coords.right > scroll.x + size.x) scroll.x = coords.right - size.x; |
|
214 |
if (coords.bottom > scroll.y + size.y) scroll.y = coords.bottom - size.y; |
|
215 |
window.scrollTo(Math.min(scroll.x, coords.left), Math.min(scroll.y, coords.top)); |
|
216 |
} |
|
217 |
}, |
|
218 |
|
|
219 |
hideChoices: function(clear) { |
|
220 |
if (clear) { |
|
221 |
var value = this.element.value; |
|
222 |
if (this.options.forceSelect) value = this.opted; |
|
223 |
if (this.options.autoTrim) { |
|
224 |
value = value.split(this.options.separatorSplit).filter($arguments(0)).join(this.options.separator); |
|
225 |
} |
|
226 |
this.observer.setValue(value); |
|
227 |
} |
|
228 |
if (!this.visible) return; |
|
229 |
this.visible = false; |
|
230 |
if (this.selected) this.selected.removeClass('autocompleter-selected'); |
|
231 |
this.observer.clear(); |
|
232 |
var hide = function(){ |
|
233 |
this.choices.setStyle('display', 'none'); |
|
234 |
this.fix.hide(); |
|
235 |
}.bind(this); |
|
236 |
if (this.fx) this.fx.start(0).chain(hide); |
|
237 |
else hide(); |
|
238 |
this.fireEvent('onHide', [this.element, this.choices]); |
|
239 |
}, |
|
240 |
|
|
241 |
prefetch: function() { |
|
242 |
var value = this.element.value, query = value; |
|
243 |
if (this.options.multiple) { |
|
244 |
var split = this.options.separatorSplit; |
|
245 |
var values = value.split(split); |
|
246 |
var index = this.element.getSelectedRange().start; |
|
247 |
var toIndex = value.substr(0, index).split(split); |
|
248 |
var last = toIndex.length - 1; |
|
249 |
index -= toIndex[last].length; |
|
250 |
query = values[last]; |
|
251 |
} |
|
252 |
if (query.length < this.options.minLength) { |
|
253 |
this.hideChoices(); |
|
254 |
} else { |
|
255 |
if (query === this.queryValue || (this.visible && query == this.selectedValue)) { |
|
256 |
if (this.visible) return false; |
|
257 |
this.showChoices(); |
|
258 |
} else { |
|
259 |
this.queryValue = query; |
|
260 |
this.queryIndex = index; |
|
261 |
if (!this.fetchCached()) this.query(); |
|
262 |
} |
|
263 |
} |
|
264 |
return true; |
|
265 |
}, |
|
266 |
|
|
267 |
fetchCached: function() { |
|
268 |
return false; |
|
269 |
if (!this.options.cache |
|
270 |
|| !this.cached |
|
271 |
|| !this.cached.length |
|
272 |
|| this.cached.length >= this.options.maxChoices |
|
273 |
|| this.queryValue) return false; |
|
274 |
this.update(this.filter(this.cached)); |
|
275 |
return true; |
|
276 |
}, |
|
277 |
|
|
278 |
update: function(tokens) { |
|
279 |
this.choices.empty(); |
|
280 |
this.cached = tokens; |
|
281 |
var type = tokens && $type(tokens); |
|
282 |
if (!type || (type == 'array' && !tokens.length) || (type == 'hash' && !tokens.getLength())) { |
|
283 |
(this.options.emptyChoices || this.hideChoices).call(this); |
|
284 |
} else { |
|
285 |
if (this.options.maxChoices < tokens.length && !this.options.overflow) tokens.length = this.options.maxChoices; |
|
286 |
tokens.each(this.options.injectChoice || function(token){ |
|
287 |
var choice = new Element('li', {'html': this.markQueryValue(token)}); |
|
288 |
choice.inputValue = token; |
|
289 |
this.addChoiceEvents(choice).inject(this.choices); |
|
290 |
}, this); |
|
291 |
this.showChoices(); |
|
292 |
} |
|
293 |
}, |
|
294 |
|
|
295 |
choiceOver: function(choice, selection) { |
|
296 |
if (!choice || choice == this.selected) return; |
|
297 |
if (this.selected) this.selected.removeClass('autocompleter-selected'); |
|
298 |
this.selected = choice.addClass('autocompleter-selected'); |
|
299 |
this.fireEvent('onSelect', [this.element, this.selected, selection]); |
|
300 |
if (!this.selectMode) this.opted = this.element.value; |
|
301 |
if (!selection) return; |
|
302 |
this.selectedValue = this.selected.inputValue; |
|
303 |
if (this.overflown) { |
|
304 |
var coords = this.selected.getCoordinates(this.choices), margin = this.options.overflowMargin, |
|
305 |
top = this.choices.scrollTop, height = this.choices.offsetHeight, bottom = top + height; |
|
306 |
if (coords.top - margin < top && top) this.choices.scrollTop = Math.max(coords.top - margin, 0); |
|
307 |
else if (coords.bottom + margin > bottom) this.choices.scrollTop = Math.min(coords.bottom - height + margin, bottom); |
|
308 |
} |
|
309 |
if (this.selectMode) this.setSelection(); |
|
310 |
}, |
|
311 |
|
|
312 |
choiceSelect: function(choice) { |
|
313 |
if (choice) this.choiceOver(choice); |
|
314 |
this.setSelection(true); |
|
315 |
this.queryValue = false; |
|
316 |
this.hideChoices(); |
|
317 |
}, |
|
318 |
|
|
319 |
filter: function(tokens) { |
|
320 |
return (tokens || this.tokens).filter(function(token) { |
|
321 |
return this.test(token); |
|
322 |
}, new RegExp(((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp(), (this.options.filterCase) ? '' : 'i')); |
|
323 |
}, |
|
324 |
|
|
325 |
/** |
|
326 |
* markQueryValue |
|
327 |
* |
|
328 |
* Marks the queried word in the given string with <span class="autocompleter-queried">*</span> |
|
329 |
* Call this i.e. from your custom parseChoices, same for addChoiceEvents |
|
330 |
* |
|
331 |
* @param {String} Text |
|
332 |
* @return {String} Text |
|
333 |
*/ |
|
334 |
markQueryValue: function(str) { |
|
335 |
return (!this.options.markQuery || !this.queryValue) ? str |
|
336 |
: str.replace(new RegExp('(' + ((this.options.filterSubset) ? '' : '^') + this.queryValue.escapeRegExp() + ')', (this.options.filterCase) ? '' : 'i'), '<span class="autocompleter-queried">$1</span>'); |
|
337 |
}, |
|
338 |
|
|
339 |
/** |
|
340 |
* addChoiceEvents |
|
341 |
* |
|
342 |
* Appends the needed event handlers for a choice-entry to the given element. |
|
343 |
* |
|
344 |
* @param {Element} Choice entry |
|
345 |
* @return {Element} Choice entry |
|
346 |
*/ |
|
347 |
addChoiceEvents: function(el) { |
|
348 |
return el.addEvents({ |
|
349 |
'mouseover': this.choiceOver.bind(this, [el]), |
|
350 |
'click': this.choiceSelect.bind(this, [el]) |
|
351 |
}); |
|
352 |
} |
|
353 |
}); |
|
354 |
|
|
355 |
var OverlayFix = new Class({ |
|
356 |
|
|
357 |
initialize: function(el) { |
|
358 |
if (Browser.Engine.trident) { |
|
359 |
this.element = $(el); |
|
360 |
this.relative = this.element.getOffsetParent(); |
|
361 |
this.fix = new Element('iframe', { |
|
362 |
'frameborder': '0', |
|
363 |
'scrolling': 'no', |
|
364 |
'src': 'javascript:false;', |
|
365 |
'styles': { |
|
366 |
'position': 'absolute', |
|
367 |
'border': 'none', |
|
368 |
'display': 'none', |
|
369 |
'filter': 'progid:DXImageTransform.Microsoft.Alpha(opacity=0)' |
|
370 |
} |
|
371 |
}).inject(this.element, 'after'); |
|
372 |
} |
|
373 |
}, |
|
374 |
|
|
375 |
show: function() { |
|
376 |
if (this.fix) { |
|
377 |
var coords = this.element.getCoordinates(this.relative); |
|
378 |
delete coords.right; |
|
379 |
delete coords.bottom; |
|
380 |
this.fix.setStyles($extend(coords, { |
|
381 |
'display': '', |
|
382 |
'zIndex': (this.element.getStyle('zIndex') || 1) - 1 |
|
383 |
})); |
|
384 |
} |
|
385 |
return this; |
|
386 |
}, |
|
387 |
|
|
388 |
hide: function() { |
|
389 |
if (this.fix) this.fix.setStyle('display', 'none'); |
|
390 |
return this; |
|
391 |
}, |
|
392 |
|
|
393 |
destroy: function() { |
|
394 |
if (this.fix) this.fix = this.fix.destroy(); |
|
395 |
} |
|
396 |
|
|
397 |
}); |
|
398 |
|
|
399 |
Element.implement({ |
|
400 |
|
|
401 |
getSelectedRange: function() { |
|
402 |
if (!Browser.Engine.trident) return {start: this.selectionStart, end: this.selectionEnd}; |
|
403 |
var pos = {start: 0, end: 0}; |
|
404 |
var range = this.getDocument().selection.createRange(); |
|
405 |
if (!range || range.parentElement() != this) return pos; |
|
406 |
var dup = range.duplicate(); |
|
407 |
if (this.type == 'text') { |
|
408 |
pos.start = 0 - dup.moveStart('character', -100000); |
|
409 |
pos.end = pos.start + range.text.length; |
|
410 |
} else { |
|
411 |
var value = this.value; |
|
412 |
var offset = value.length - value.match(/[\n\r]*$/)[0].length; |
|
413 |
dup.moveToElementText(this); |
|
414 |
dup.setEndPoint('StartToEnd', range); |
|
415 |
pos.end = offset - dup.text.length; |
|
416 |
dup.setEndPoint('StartToStart', range); |
|
417 |
pos.start = offset - dup.text.length; |
|
418 |
} |
|
419 |
return pos; |
|
420 |
}, |
|
421 |
|
|
422 |
selectRange: function(start, end) { |
|
423 |
if (Browser.Engine.trident) { |
|
424 |
var diff = this.value.substr(start, end - start).replace(/\r/g, '').length; |
|
425 |
start = this.value.substr(0, start).replace(/\r/g, '').length; |
|
426 |
var range = this.createTextRange(); |
|
427 |
range.collapse(true); |
|
428 |
range.moveEnd('character', start + diff); |
|
429 |
range.moveStart('character', start); |
|
430 |
range.select(); |
|
431 |
} else { |
|
432 |
this.focus(); |
|
433 |
this.setSelectionRange(start, end); |
|
434 |
} |
|
435 |
return this; |
|
436 |
} |
|
437 |
|
|
438 |
}); |
|
439 |
|
|
440 |
/* compatibility */ |
|
441 |
|
|
442 |
Autocompleter.Base = Autocompleter; |
vigigraph/public/js/libs/Autocompleter/Observer.js | ||
---|---|---|
1 |
/** |
|
2 |
* Observer - Observe formelements for changes |
|
3 |
* |
|
4 |
* - Additional code from clientside.cnet.com |
|
5 |
* |
|
6 |
* @version 1.1 |
|
7 |
* |
|
8 |
* @license MIT-style license |
|
9 |
* @author Harald Kirschner <mail [at] digitarald.de> |
|
10 |
* @copyright Author |
|
11 |
*/ |
|
12 |
var Observer = new Class({ |
|
13 |
|
|
14 |
Implements: [Options, Events], |
|
15 |
|
|
16 |
options: { |
|
17 |
periodical: false, |
|
18 |
delay: 1000 |
|
19 |
}, |
|
20 |
|
|
21 |
initialize: function(el, onFired, options){ |
|
22 |
this.element = $(el) || $$(el); |
|
23 |
this.addEvent('onFired', onFired); |
|
24 |
this.setOptions(options); |
|
25 |
this.bound = this.changed.bind(this); |
|
26 |
this.resume(); |
|
27 |
}, |
|
28 |
|
|
29 |
changed: function() { |
|
30 |
var value = this.element.get('value'); |
|
31 |
if ($equals(this.value, value)) return; |
|
32 |
this.clear(); |
|
33 |
this.value = value; |
|
34 |
this.timeout = this.onFired.delay(this.options.delay, this); |
|
35 |
}, |
|
36 |
|
|
37 |
setValue: function(value) { |
|
38 |
this.value = value; |
|
39 |
this.element.set('value', value); |
|
40 |
return this.clear(); |
|
41 |
}, |
|
42 |
|
|
43 |
onFired: function() { |
|
44 |
this.fireEvent('onFired', [this.value, this.element]); |
|
45 |
}, |
|
46 |
|
|
47 |
clear: function() { |
|
48 |
$clear(this.timeout || null); |
|
49 |
return this; |
|
50 |
}, |
|
51 |
|
|
52 |
pause: function(){ |
|
53 |
if (this.timer) $clear(this.timer); |
|
54 |
else this.element.removeEvent('keyup', this.bound); |
|
55 |
return this.clear(); |
|
56 |
}, |
|
57 |
|
|
58 |
resume: function(){ |
|
59 |
this.value = this.element.get('value'); |
|
60 |
if (this.options.periodical) this.timer = this.changed.periodical(this.options.periodical, this); |
|
61 |
else this.element.addEvent('keyup', this.bound); |
|
62 |
return this; |
|
63 |
} |
|
64 |
|
|
65 |
}); |
|
66 |
|
|
67 |
var $equals = function(obj1, obj2) { |
|
68 |
return (obj1 == obj2 || JSON.encode(obj1) == JSON.encode(obj2)); |
|
69 |
}; |
vigigraph/public/js/libs/Autocompleter/vigilo.js | ||
---|---|---|
1 |
Autocompleter.Request.VigiloJSON = new Class({ |
|
2 |
|
|
3 |
Extends: Autocompleter.Request, |
|
4 |
|
|
5 |
options: { |
|
6 |
resVar: 'results' |
|
7 |
}, |
|
8 |
|
|
9 |
initialize: function(el, url, options) { |
|
10 |
this.parent(el, options); |
|
11 |
this.request = new Request.JSON($merge({ |
|
12 |
'url': url, |
|
13 |
'link': 'cancel' |
|
14 |
}, this.options.ajaxOptions)).addEvent('onComplete', this.queryResponse.bind(this)); |
|
15 |
}, |
|
16 |
|
|
17 |
queryResponse: function(response) { |
|
18 |
this.parent(); |
|
19 |
this.update(response[this.options.resVar]); |
|
20 |
} |
|
21 |
|
|
22 |
}); |
vigigraph/public/js/libs/babel.js | ||
---|---|---|
1 |
/** |
|
2 |
* Babel JavaScript Support |
|
3 |
* |
|
4 |
* Copyright (C) 2008 Edgewall Software |
|
5 |
* All rights reserved. |
|
6 |
* |
|
7 |
* This software is licensed as described in the file COPYING, which |
|
8 |
* you should have received as part of this distribution. The terms |
|
9 |
* are also available at http://babel.edgewall.org/wiki/License. |
|
10 |
* |
|
11 |
* This software consists of voluntary contributions made by many |
|
12 |
* individuals. For the exact contribution history, see the revision |
|
13 |
* history and logs, available at http://babel.edgewall.org/log/. |
|
14 |
*/ |
|
15 |
|
|
16 |
/** |
|
17 |
* A simple module that provides a gettext like translation interface. |
|
18 |
* The catalog passed to load() must be a object conforming to this |
|
19 |
* interface:: |
|
20 |
* |
|
21 |
* { |
|
22 |
* messages: an object of {msgid: translations} items where |
|
23 |
* translations is an array of messages or a single |
|
24 |
* string if the message is not pluralizable. |
|
25 |
* plural_expr: the plural expression for the language. |
|
26 |
* locale: the identifier for this locale. |
|
27 |
* domain: the name of the domain. |
|
28 |
* } |
|
29 |
* |
|
30 |
* Missing elements in the object are ignored. |
|
31 |
* |
|
32 |
* Typical usage:: |
|
33 |
* |
|
34 |
* var translations = babel.Translations.load(...).install(); |
|
35 |
*/ |
|
36 |
var babel = new function() { |
|
37 |
|
|
38 |
var defaultPluralExpr = function(n) { return n == 1 ? 0 : 1; }; |
|
39 |
var formatRegex = /%?%(?:\(([^\)]+)\))?([disr])/g; |
|
40 |
|
|
41 |
/** |
|
42 |
* A translations object implementing the gettext interface |
|
43 |
*/ |
|
44 |
var Translations = this.Translations = function(locale, domain) { |
|
45 |
this.messages = {}; |
|
46 |
this.locale = locale || 'unknown'; |
|
47 |
this.domain = domain || 'messages'; |
|
48 |
this.pluralexpr = defaultPluralExpr; |
|
49 |
}; |
|
50 |
|
|
51 |
/** |
|
52 |
* Create a new translations object from the catalog and return it. |
|
53 |
* See the babel-module comment for more details. |
|
54 |
*/ |
|
55 |
Translations.load = function(catalog) { |
|
56 |
var rv = new Translations(); |
|
57 |
rv.load(catalog); |
|
58 |
return rv; |
|
59 |
}; |
|
60 |
|
|
61 |
Translations.prototype = { |
|
62 |
/** |
|
63 |
* translate a single string. |
|
64 |
*/ |
|
65 |
gettext: function(string) { |
|
66 |
var translated = this.messages[string]; |
|
67 |
if (typeof translated == 'undefined') |
|
68 |
return string; |
|
69 |
return (typeof translated == 'string') ? translated : translated[0]; |
|
70 |
}, |
|
71 |
|
|
72 |
/** |
|
73 |
* translate a pluralizable string |
|
74 |
*/ |
|
75 |
ngettext: function(singular, plural, n) { |
|
76 |
var translated = this.messages[singular]; |
|
77 |
if (typeof translated == 'undefined') |
|
78 |
return (n == 1) ? singular : plural; |
|
79 |
return translated[this.pluralexpr(n)]; |
|
80 |
}, |
|
81 |
|
|
82 |
/** |
|
83 |
* Install this translation document wide. After this call, there are |
|
84 |
* three new methods on the window object: _, gettext and ngettext |
|
85 |
*/ |
|
86 |
install: function() { |
|
87 |
var self = this; |
|
88 |
window._ = window.gettext = function(string) { |
|
89 |
return self.gettext(string); |
|
90 |
}; |
|
91 |
window.ngettext = function(singular, plural, n) { |
|
92 |
return self.ngettext(singular, plural, n); |
|
93 |
}; |
|
94 |
return this; |
|
95 |
}, |
|
96 |
|
|
97 |
/** |
|
98 |
* Works like Translations.load but updates the instance rather |
|
99 |
* then creating a new one. |
|
100 |
*/ |
|
101 |
load: function(catalog) { |
|
102 |
if (catalog.messages) |
|
103 |
this.update(catalog.messages) |
|
104 |
if (catalog.plural_expr) |
|
105 |
this.setPluralExpr(catalog.plural_expr); |
|
106 |
if (catalog.locale) |
|
107 |
this.locale = catalog.locale; |
|
108 |
if (catalog.domain) |
|
109 |
this.domain = catalog.domain; |
|
110 |
return this; |
|
111 |
}, |
|
112 |
|
|
113 |
/** |
|
114 |
* Updates the translations with the object of messages. |
|
115 |
*/ |
|
116 |
update: function(mapping) { |
|
117 |
for (var key in mapping) |
|
118 |
if (mapping.hasOwnProperty(key)) |
|
119 |
this.messages[key] = mapping[key]; |
|
120 |
return this; |
|
121 |
}, |
|
122 |
|
|
123 |
/** |
|
124 |
* Sets the plural expression |
|
125 |
*/ |
|
126 |
setPluralExpr: function(expr) { |
|
127 |
this.pluralexpr = new Function('n', 'return +(' + expr + ')'); |
|
128 |
return this; |
|
129 |
} |
|
130 |
}; |
|
131 |
|
|
132 |
/** |
|
133 |
* A python inspired string formatting function. Supports named and |
|
134 |
* positional placeholders and "s", "d" and "i" as type characters |
|
135 |
* without any formatting specifications. |
|
136 |
* |
|
137 |
* Examples:: |
|
138 |
* |
|
139 |
* babel.format(_('Hello %s'), name) |
|
140 |
* babel.format(_('Progress: %(percent)s%%'), {percent: 100}) |
|
141 |
*/ |
|
142 |
this.format = function() { |
|
143 |
var arg, string = arguments[0], idx = 0; |
|
144 |
if (arguments.length == 1) |
|
145 |
return string; |
|
146 |
else if (arguments.length == 2 && typeof arguments[1] == 'object') |
|
147 |
arg = arguments[1]; |
|
148 |
else { |
|
149 |
arg = []; |
|
150 |
for (var i = 1, n = arguments.length; i != n; ++i) |
|
151 |
arg[i - 1] = arguments[i]; |
|
152 |
} |
|
153 |
return string.replace(formatRegex, function(all, name, type) { |
|
154 |
if (all[0] == all[1]) return all.substring(1); |
|
155 |
var value = arg[name || idx++]; |
|
156 |
return (type == 'i' || type == 'd') ? +value : value; |
|
157 |
}); |
|
158 |
} |
|
159 |
|
|
160 |
}; |
vigigraph/public/js/libs/jxlib.js | ||
---|---|---|
1 |
/****************************************************************************** |
|
2 |
* MooTools 1.2.2 |
|
3 |
* Copyright (c) 2006-2007 [Valerio Proietti](http://mad4milk.net/). |
|
4 |
* MooTools is distributed under an MIT-style license. |
|
5 |
****************************************************************************** |
|
6 |
* reset.css - Copyright (c) 2006, Yahoo! Inc. All rights reserved. |
|
7 |
* Code licensed under the BSD License: http://developer.yahoo.net/yui/license.txt |
|
8 |
****************************************************************************** |
|
9 |
* Jx UI Library, 2.0.1 |
|
10 |
* Copyright (c) 2006-2008, DM Solutions Group Inc. All rights reserved. |
|
11 |
* |
|
12 |
* Permission is hereby granted, free of charge, to any person obtaining a |
|
13 |
* copy of this software and associated documentation files (the "Software"), |
|
14 |
* to deal in the Software without restriction, including without limitation |
|
15 |
* the rights to use, copy, modify, merge, publish, distribute, sublicense, |
|
16 |
* and/or sell copies of the Software, and to permit persons to whom the |
|
17 |
* Software is furnished to do so, subject to the following conditions: |
|
18 |
* |
|
19 |
* The above copyright notice and this permission notice shall be included |
|
20 |
* in all copies or substantial portions of the Software. |
|
21 |
* |
|
22 |
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
|
23 |
* IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
|
24 |
* FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL |
|
25 |
* THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
|
26 |
* LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
|
27 |
* FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
|
28 |
* DEALINGS IN THE SOFTWARE. |
|
29 |
*****************************************************************************/ |
|
30 |
// $Id: common.js 423 2009-05-12 12:37:56Z pagameba $ |
|
31 |
/** |
|
32 |
* Class: Jx |
|
33 |
* Jx is a global singleton object that contains the entire Jx library |
|
34 |
* within it. All Jx functions, attributes and classes are accessed |
|
35 |
* through the global Jx object. Jx should not create any other |
|
36 |
* global variables, if you discover that it does then please report |
|
37 |
* it as a bug |
|
38 |
* |
|
39 |
* License: |
|
40 |
* Copyright (c) 2008, DM Solutions Group Inc. |
|
41 |
* |
|
42 |
* This file is licensed under an MIT style license |
|
43 |
*/ |
|
44 |
|
|
45 |
/* firebug console supressor for IE/Safari/Opera */ |
|
46 |
window.addEvent('load', function() { |
|
47 |
if (!("console" in window) || !("firebug" in window.console)) { |
|
48 |
var names = ["log", "debug", "info", "warn", "error", "assert", "dir", "dirxml", |
|
49 |
"group", "groupEnd", "time", "timeEnd", "count", "trace", "profile", "profileEnd"]; |
|
50 |
|
|
51 |
window.console = {}; |
|
52 |
for (var i = 0; i < names.length; ++i) { |
|
53 |
window.console[names[i]] = function() {}; |
|
54 |
} |
|
55 |
} |
|
56 |
}); |
|
57 |
/* inspired by extjs, apparently removes css image flicker and related problems in IE 6 */ |
|
58 |
/* This is already done in mootools Source/Core/Browser.js KASI*/ |
|
59 |
/* |
|
60 |
(function() { |
|
61 |
var ua = navigator.userAgent.toLowerCase(); |
|
62 |
var isIE = ua.indexOf("msie") > -1, |
|
63 |
isIE7 = ua.indexOf("msie 7") > -1; |
|
64 |
if(isIE && !isIE7) { |
|
65 |
try { |
|
66 |
document.execCommand("BackgroundImageCache", false, true); |
|
67 |
} catch(e) {} |
|
68 |
} |
|
69 |
})(); |
|
70 |
*/ |
|
71 |
Class.Mutators.Family = function(self,name) { |
|
72 |
if ($defined(name)){ |
|
73 |
self.$family = {'name': name}; |
|
74 |
$[name] = $.object; |
|
75 |
return self; |
|
76 |
} |
|
77 |
else { |
|
78 |
this.implement('$family',{'name':self}); |
|
79 |
} |
|
80 |
}; |
|
81 |
|
|
82 |
/* Setup global namespace |
|
83 |
* If jxcore is loaded by jx.js, then the namespace and baseURL are |
|
84 |
* already established |
|
85 |
*/ |
|
86 |
if (typeof Jx == 'undefined') { |
|
87 |
var Jx = {}; |
|
88 |
(function() { |
|
89 |
var aScripts = document.getElementsByTagName('SCRIPT'); |
|
90 |
for (var i=0; i<aScripts.length; i++) { |
|
91 |
var s = aScripts[i].src; |
|
92 |
var matches = /(.*[jx|js|lib])\/jxlib(.*)/.exec(s); |
|
93 |
if (matches && matches[0]) { |
|
94 |
/** |
|
95 |
* Property: {String} baseURL |
|
96 |
* This is the URL that Jx was loaded from, it is |
|
97 |
* automatically calculated from the script tag |
|
98 |
* src property that included Jx. |
|
99 |
* |
|
100 |
* Note that this assumes that you are loading Jx |
|
101 |
* from a js/ or lib/ folder in parallel to the |
|
102 |
* images/ folder that contains the various images |
|
103 |
* needed by Jx components. If you have a different |
|
104 |
* folder structure, you can define Jx's base |
|
105 |
* by including the following before including |
|
106 |
* the jxlib javascript file: |
|
107 |
* |
|
108 |
* (code) |
|
109 |
* Jx = { |
|
110 |
* baseURL: 'some/path' |
|
111 |
* } |
|
112 |
* (end) |
|
113 |
*/ |
|
114 |
Jx.aPixel = document.createElement('img', {alt:'',title:''}); |
|
115 |
Jx.aPixel.src = matches[1]+'/a_pixel.png'; |
|
116 |
Jx.baseURL = Jx.aPixel.src.substring(0, |
|
117 |
Jx.aPixel.src.indexOf('a_pixel.png')); |
|
118 |
|
|
119 |
} |
|
120 |
} |
|
121 |
/** |
|
122 |
* Determine if we're running in Adobe AIR. If so, determine which sandbox we're in |
|
123 |
*/ |
|
124 |
var src = aScripts[0].src; |
|
125 |
if (src.contains('app:')){ |
|
126 |
Jx.isAir = true; |
|
127 |
} else { |
|
128 |
Jx.isAir = false; |
|
129 |
} |
|
130 |
})(); |
|
131 |
} |
|
132 |
|
|
133 |
/** |
|
134 |
* Method: applyPNGFilter |
|
135 |
* |
|
136 |
* Static method that applies the PNG Filter Hack for IE browsers |
|
137 |
* when showing 24bit PNG's. Used automatically for img tags with |
|
138 |
* a class of png24. |
|
139 |
* |
|
140 |
* The filter is applied using a nifty feature of IE that allows javascript to |
|
141 |
* be executed as part of a CSS style rule - this ensures that the hack only |
|
142 |
* gets applied on IE browsers. |
|
143 |
* |
|
144 |
* The CSS that triggers this hack is only in the ie6.css files of the various |
|
145 |
* themes. |
|
146 |
* |
|
147 |
* Parameters: |
|
148 |
* object {Object} the object (img) to which the filter needs to be applied. |
|
149 |
*/ |
|
150 |
Jx.applyPNGFilter = function(o) { |
|
151 |
var t=Jx.aPixel.src; |
|
152 |
if( o.src != t ) { |
|
153 |
var s=o.src; |
|
154 |
o.src = t; |
|
155 |
o.runtimeStyle.filter = "progid:DXImageTransform.Microsoft.AlphaImageLoader(src='"+s+"',sizingMethod='scale')"; |
|
156 |
} |
|
157 |
}; |
|
158 |
|
|
159 |
Jx.imgQueue = []; //The queue of images to be loaded |
|
160 |
Jx.imgLoaded = {}; //a hash table of images that have been loaded and cached |
|
161 |
Jx.imagesLoading = 0; //counter for number of concurrent image loads |
|
162 |
|
|
163 |
/** |
|
164 |
* Method: addToImgQueue |
|
165 |
* Request that an image be set to a DOM IMG element src attribute. This puts |
|
166 |
* the image into a queue and there are private methods to manage that queue |
|
167 |
* and limit image loading to 2 at a time. |
|
168 |
* |
|
169 |
* Parameters: |
|
170 |
* obj - {Object} an object containing an element and src |
|
171 |
* property, where element is the element to update and src |
|
172 |
* is the url to the image. |
|
173 |
*/ |
|
174 |
Jx.addToImgQueue = function(obj) { |
|
175 |
if (Jx.imgLoaded[obj.src]) { |
|
176 |
//if this image was already requested (i.e. it's in cache) just set it directly |
|
177 |
obj.element.src = obj.src; |
|
178 |
} else { |
|
179 |
//otherwise stick it in the queue |
|
180 |
Jx.imgQueue.push(obj); |
|
181 |
Jx.imgLoaded[obj.src] = true; |
|
182 |
} |
|
183 |
//start the queue management process |
|
184 |
Jx.checkImgQueue(); |
|
185 |
}; |
|
186 |
|
|
187 |
/** |
|
188 |
* Method: checkImgQueue |
|
189 |
* |
|
190 |
* An internal method that ensures no more than 2 images are loading at a time. |
|
191 |
*/ |
|
192 |
Jx.checkImgQueue = function() { |
|
193 |
while (Jx.imagesLoading < 2 && Jx.imgQueue.length > 0) { |
|
194 |
Jx.loadNextImg(); |
|
195 |
} |
|
196 |
}; |
|
197 |
|
|
198 |
/** |
|
199 |
* Method: loadNextImg |
|
200 |
* |
|
201 |
* An internal method actually populate the DOM element with the image source. |
|
202 |
*/ |
|
203 |
Jx.loadNextImg = function() { |
|
204 |
var obj = Jx.imgQueue.shift(); |
|
205 |
if (obj) { |
|
206 |
++Jx.imagesLoading; |
|
207 |
obj.element.onload = function(){--Jx.imagesLoading; Jx.checkImgQueue();}; |
|
208 |
obj.element.onerror = function(){--Jx.imagesLoading; Jx.checkImgQueue();}; |
|
209 |
obj.element.src = obj.src; |
|
210 |
} |
|
211 |
}; |
|
212 |
|
|
213 |
/** |
|
214 |
* Method: createIframeShim |
|
215 |
* Creates a new iframe element that is intended to fill a container |
|
216 |
* to mask out other operating system controls (scrollbars, inputs, |
|
217 |
* buttons, etc) when HTML elements are supposed to be above them. |
|
218 |
* |
|
219 |
* Returns: |
|
220 |
* an HTML iframe element that can be inserted into the DOM. |
|
221 |
*/ |
|
222 |
Jx.createIframeShim = function() { |
|
223 |
return new Element('iframe', { |
|
224 |
'class':'jxIframeShim', |
|
225 |
'scrolling':'no', |
|
226 |
'frameborder':0 |
|
227 |
}); |
|
228 |
}; |
|
229 |
/** |
|
230 |
* Method: getNumber |
|
231 |
* safely parse a number and return its integer value. A NaN value |
|
232 |
* returns 0. CSS size values are also parsed correctly. |
|
233 |
* |
|
234 |
* Parameters: |
|
235 |
* n - {Mixed} the string or object to parse. |
|
236 |
* |
|
237 |
* Returns: |
|
238 |
* {Integer} the integer value that the parameter represents |
|
239 |
*/ |
|
240 |
Jx.getNumber = function(n, def) { |
|
241 |
var result = n===null||isNaN(parseInt(n,10))?(def||0):parseInt(n,10); |
|
242 |
return result; |
|
243 |
} |
|
244 |
|
|
245 |
/** |
|
246 |
* Method: getPageDimensions |
|
247 |
* return the dimensions of the browser client area. |
|
248 |
* |
|
249 |
* Returns: |
|
250 |
* {Object} an object containing a width and height property |
|
251 |
* that represent the width and height of the browser client area. |
|
252 |
*/ |
|
253 |
Jx.getPageDimensions = function() { |
|
254 |
return {width: window.getWidth(), height: window.getHeight()}; |
|
255 |
} |
|
256 |
|
|
257 |
/** |
|
258 |
* Class: Element |
|
259 |
* |
|
260 |
* Element is a global object provided by the mootools library. The |
|
261 |
* functions documented here are extensions to the Element object provided |
|
262 |
* by Jx to make cross-browser compatibility easier to achieve. Most of the |
|
263 |
* methods are measurement related. |
|
264 |
* |
|
265 |
* While the code in these methods has been converted to use MooTools methods, |
|
266 |
* there may be better MooTools methods to use to accomplish these things. |
|
267 |
* Ultimately, it would be nice to eliminate most or all of these and find the |
|
268 |
* MooTools equivalent or convince MooTools to add them. |
|
269 |
*/ |
|
270 |
Element.implement({ |
|
271 |
/** |
|
272 |
* Method: getBoxSizing |
|
273 |
* return the box sizing of an element, one of 'content-box' or |
|
274 |
*'border-box'. |
|
275 |
* |
|
276 |
* Parameters: |
|
277 |
* elem - {Object} the element to get the box sizing of. |
|
278 |
* |
|
279 |
* Returns: |
|
280 |
* {String} the box sizing of the element. |
|
281 |
*/ |
|
282 |
getBoxSizing : function() { |
|
283 |
var result = 'content-box'; |
|
284 |
if (Browser.Engine.trident || Browser.Engine.presto) { |
|
285 |
var cm = document["compatMode"]; |
|
286 |
if (cm == "BackCompat" || cm == "QuirksMode") { |
|
287 |
result = 'border-box'; |
|
288 |
} else { |
|
289 |
result = 'content-box'; |
|
290 |
} |
|
291 |
} else { |
|
292 |
if (arguments.length === 0) { |
|
293 |
node = document.documentElement; |
|
294 |
} |
|
295 |
var sizing = this.getStyle("-moz-box-sizing"); |
|
296 |
if (!sizing) { |
|
297 |
sizing = this.getStyle("box-sizing"); |
|
298 |
} |
|
299 |
result = (sizing ? sizing : 'content-box'); |
|
300 |
} |
|
301 |
return result; |
|
302 |
}, |
|
303 |
/** |
|
304 |
* Method: getContentBoxSize |
|
305 |
* return the size of the content area of an element. This is the size of |
|
306 |
* the element less margins, padding, and borders. |
|
307 |
* |
|
308 |
* Parameters: |
|
309 |
* elem - {Object} the element to get the content size of. |
|
310 |
* |
|
311 |
* Returns: |
|
312 |
* {Object} an object with two properties, width and height, that |
|
313 |
* are the size of the content area of the measured element. |
|
314 |
*/ |
|
315 |
getContentBoxSize : function() { |
|
316 |
var w = this.offsetWidth; |
|
317 |
var h = this.offsetHeight; |
|
318 |
var padding = this.getPaddingSize(); |
|
319 |
var border = this.getBorderSize(); |
|
320 |
w = w - padding.left - padding.right - border.left - border.right; |
|
321 |
h = h - padding.bottom - padding.top - border.bottom - border.top; |
|
322 |
return {width: w, height: h}; |
|
323 |
}, |
|
324 |
/** |
|
325 |
* Method: getBorderBoxSize |
|
326 |
* return the size of the border area of an element. This is the size of |
|
327 |
* the element less margins. |
|
328 |
* |
|
329 |
* Parameters: |
|
330 |
* elem - {Object} the element to get the border sizing of. |
|
331 |
* |
|
332 |
* Returns: |
|
333 |
* {Object} an object with two properties, width and height, that |
|
334 |
* are the size of the border area of the measured element. |
|
335 |
*/ |
|
336 |
getBorderBoxSize: function() { |
|
337 |
var w = this.offsetWidth; |
|
338 |
var h = this.offsetHeight; |
|
339 |
return {width: w, height: h}; |
|
340 |
}, |
|
341 |
|
|
342 |
/** |
|
343 |
* Method: getMarginBoxSize |
|
344 |
* return the size of the margin area of an element. This is the size of |
|
345 |
* the element plus margins. |
|
346 |
* |
|
347 |
* Parameters: |
|
348 |
* elem - {Object} the element to get the margin sizing of. |
|
349 |
* |
|
350 |
* Returns: |
|
351 |
* {Object} an object with two properties, width and height, that |
|
352 |
* are the size of the margin area of the measured element. |
|
353 |
*/ |
|
354 |
getMarginBoxSize: function() { |
|
355 |
var margins = this.getMarginSize(); |
|
356 |
var w = this.offsetWidth + margins.left + margins.right; |
|
357 |
var h = this.offsetHeight + margins.top + margins.bottom; |
|
358 |
return {width: w, height: h}; |
|
359 |
}, |
|
360 |
|
|
361 |
/** |
|
362 |
* Method: setContentBoxSize |
|
363 |
* set either or both of the width and height of an element to |
|
364 |
* the provided size. This function ensures that the content |
|
365 |
* area of the element is the requested size and the resulting |
|
366 |
* size of the element may be larger depending on padding and |
|
367 |
* borders. |
|
368 |
* |
|
369 |
* Parameters: |
|
370 |
* elem - {Object} the element to set the content area of. |
|
371 |
* size - {Object} an object with a width and/or height property that is the size to set |
|
372 |
* the content area of the element to. |
|
373 |
*/ |
|
374 |
setContentBoxSize : function(size) { |
|
375 |
if (this.getBoxSizing() == 'border-box') { |
|
376 |
var padding = this.getPaddingSize(); |
|
377 |
var border = this.getBorderSize(); |
|
378 |
if (typeof size.width != 'undefined') { |
|
379 |
var width = (size.width + padding.left + padding.right + border.left + border.right); |
|
380 |
if (width < 0) { |
|
381 |
width = 0; |
|
382 |
} |
|
383 |
this.style.width = width + 'px'; |
|
384 |
} |
|
385 |
if (typeof size.height != 'undefined') { |
|
386 |
var height = (size.height + padding.top + padding.bottom + border.top + border.bottom); |
|
387 |
if (height < 0) { |
|
388 |
height = 0; |
|
389 |
} |
|
390 |
this.style.height = height + 'px'; |
|
391 |
} |
|
392 |
} else { |
|
393 |
if (typeof size.width != 'undefined') { |
|
394 |
this.style.width = size.width + 'px'; |
|
395 |
} |
|
396 |
if (typeof size.height != 'undefined') { |
|
397 |
this.style.height = size.height + 'px'; |
|
398 |
} |
|
399 |
} |
|
400 |
}, |
|
401 |
/** |
|
402 |
* Method: setBorderBoxSize |
|
403 |
* set either or both of the width and height of an element to |
|
404 |
* the provided size. This function ensures that the border |
|
405 |
* size of the element is the requested size and the resulting |
|
406 |
* content areaof the element may be larger depending on padding and |
|
407 |
* borders. |
|
408 |
* |
|
409 |
* Parameters: |
|
410 |
* elem - {Object} the element to set the border size of. |
|
411 |
* size - {Object} an object with a width and/or height property that is the size to set |
|
412 |
* the content area of the element to. |
|
413 |
*/ |
|
414 |
setBorderBoxSize : function(size) { |
|
415 |
if (this.getBoxSizing() == 'content-box') { |
|
416 |
var padding = this.getPaddingSize(); |
|
417 |
var border = this.getBorderSize(); |
|
418 |
var margin = this.getMarginSize(); |
|
419 |
if (typeof size.width != 'undefined') { |
|
420 |
var width = (size.width - padding.left - padding.right - border.left - border.right - margin.left - margin.right); |
|
421 |
if (width < 0) { |
|
422 |
width = 0; |
|
423 |
} |
|
424 |
this.style.width = width + 'px'; |
|
425 |
} |
|
426 |
if (typeof size.height != 'undefined') { |
|
427 |
var height = (size.height - padding.top - padding.bottom - border.top - border.bottom - margin.top - margin.bottom); |
|
428 |
if (height < 0) { |
|
429 |
height = 0; |
|
430 |
} |
|
431 |
this.style.height = height + 'px'; |
|
432 |
} |
|
433 |
} else { |
|
434 |
if (typeof size.width != 'undefined' && size.width >= 0) { |
|
435 |
this.style.width = size.width + 'px'; |
|
436 |
} |
|
437 |
if (typeof size.height != 'undefined' && size.height >= 0) { |
|
438 |
this.style.height = size.height + 'px'; |
|
439 |
} |
|
440 |
} |
|
441 |
}, |
|
442 |
/** |
|
443 |
* Method: getPaddingSize |
|
444 |
* returns the padding for each edge of an element |
|
445 |
* |
|
446 |
* Parameters: |
|
447 |
* elem - {Object} The element to get the padding for. |
|
448 |
* |
|
449 |
* Returns: |
|
450 |
* {Object} an object with properties left, top, right and bottom |
|
451 |
* that contain the associated padding values. |
|
452 |
*/ |
|
453 |
getPaddingSize : function () { |
|
454 |
var l = Jx.getNumber(this.getStyle('padding-left')); |
|
455 |
var t = Jx.getNumber(this.getStyle('padding-top')); |
|
456 |
var r = Jx.getNumber(this.getStyle('padding-right')); |
|
457 |
var b = Jx.getNumber(this.getStyle('padding-bottom')); |
|
458 |
return {left:l, top:t, right: r, bottom: b}; |
|
459 |
}, |
|
460 |
/** |
|
461 |
* Method: getBorderSize |
|
462 |
* returns the border size for each edge of an element |
|
463 |
* |
|
464 |
* Parameters: |
|
465 |
* elem - {Object} The element to get the borders for. |
|
466 |
* |
|
467 |
* Returns: |
|
468 |
* {Object} an object with properties left, top, right and bottom |
|
469 |
* that contain the associated border values. |
|
470 |
*/ |
|
471 |
getBorderSize : function() { |
|
472 |
var l = Jx.getNumber(this.getStyle('border-left-width')); |
|
473 |
var t = Jx.getNumber(this.getStyle('border-top-width')); |
|
474 |
var r = Jx.getNumber(this.getStyle('border-right-width')); |
|
475 |
var b = Jx.getNumber(this.getStyle('border-bottom-width')); |
|
476 |
return {left:l, top:t, right: r, bottom: b}; |
|
477 |
}, |
|
478 |
/** |
|
479 |
* Method: getMarginSize |
|
480 |
* returns the margin size for each edge of an element |
|
481 |
* |
|
482 |
* Parameters: |
|
483 |
* elem - {Object} The element to get the margins for. |
|
484 |
* |
|
485 |
* Returns: |
|
486 |
*: {Object} an object with properties left, top, right and bottom |
|
487 |
* that contain the associated margin values. |
|
488 |
*/ |
|
489 |
getMarginSize : function() { |
|
490 |
var l = Jx.getNumber(this.getStyle('margin-left')); |
|
491 |
var t = Jx.getNumber(this.getStyle('margin-top')); |
|
492 |
var r = Jx.getNumber(this.getStyle('margin-right')); |
|
493 |
var b = Jx.getNumber(this.getStyle('margin-bottom')); |
|
494 |
return {left:l, top:t, right: r, bottom: b}; |
|
495 |
}, |
|
496 |
|
|
497 |
/** |
|
498 |
* Method: descendantOf |
|
499 |
* determines if the element is a descendent of the reference node. |
|
500 |
* |
|
501 |
* Parameters: |
|
502 |
* node - {HTMLElement} the reference node |
|
503 |
* |
|
504 |
* Returns: |
|
505 |
* {Boolean} true if the element is a descendent, false otherwise. |
|
506 |
*/ |
|
507 |
descendantOf: function(node) { |
|
508 |
var parent = $(this.parentNode); |
|
509 |
while (parent != node && parent && parent.parentNode && parent.parentNode != parent) { |
|
510 |
parent = $(parent.parentNode); |
|
511 |
} |
|
512 |
return parent == node; |
|
513 |
}, |
|
514 |
|
|
515 |
/** |
|
516 |
* Method: findElement |
|
517 |
* search the parentage of the element to find an element of the given |
|
518 |
* tag name. |
|
519 |
* |
|
520 |
* Parameters: |
|
521 |
* type - {String} the tag name of the element type to search for |
|
522 |
* |
|
523 |
* Returns: |
|
524 |
* {HTMLElement} the first node (this one or first parent) with the |
|
525 |
* requested tag name or false if none are found. |
|
526 |
*/ |
|
527 |
findElement: function(type) { |
|
528 |
var o = this; |
|
529 |
var tagName = o.tagName; |
|
530 |
while (o.tagName != type && o && o.parentNode && o.parentNode != o) { |
|
531 |
o = $(o.parentNode); |
|
532 |
} |
|
533 |
return o.tagName == type ? o : false; |
|
534 |
} |
|
535 |
} ); |
|
536 |
|
|
537 |
/** |
|
538 |
* Class: Jx.ContentLoader |
|
539 |
* |
|
540 |
* ContentLoader is a mix-in class that provides a consistent |
|
541 |
* mechanism for other Jx controls to load content in one of |
|
542 |
* four different ways: |
|
543 |
* |
|
544 |
* o using an existing element, by id |
|
545 |
* |
|
546 |
* o using an existing element, by object reference |
|
547 |
* |
|
548 |
* o using an HTML string |
|
549 |
* |
|
550 |
* o using a URL to get the content remotely |
|
551 |
* |
|
552 |
* Use the Implements syntax in your Class to add Jx.ContentLoader |
|
553 |
* to your class. |
|
554 |
* |
|
555 |
* Option: content |
|
556 |
* content may be an HTML element reference, the id of an HTML element |
|
557 |
* already in the DOM, or an HTML string that becomes the inner HTML of |
|
558 |
* the element. |
|
559 |
* |
|
560 |
* Option: contentURL |
|
561 |
* the URL to load content from |
|
562 |
*/ |
|
563 |
Jx.ContentLoader = new Class ({ |
|
564 |
/** |
|
565 |
* Property: contentIsLoaded |
|
566 |
* |
|
567 |
* tracks the load state of the content, specifically useful |
|
568 |
* in the case of remote content. |
|
569 |
*/ |
|
570 |
contentIsLoaded: false, |
|
571 |
/** |
|
572 |
* Method: loadContent |
|
573 |
* |
|
574 |
* triggers loading of content based on options set for the current |
|
575 |
* object. |
|
576 |
* |
|
577 |
* Parameters: |
|
578 |
* element - {Object} the element to insert the content into |
|
579 |
* |
|
580 |
* Events: |
|
581 |
* |
|
582 |
* ContentLoader adds the following events to an object. You can |
|
583 |
* register for these events using the addEvent method or by providing |
|
584 |
* callback functions via the on{EventName} properties in the options |
|
585 |
* object |
|
586 |
* |
|
587 |
* contentLoaded - called when the content has been loaded. If the |
|
588 |
* content is not asynchronous then this is called before loadContent |
|
589 |
* returns. |
|
590 |
* contentLoadFailed - called if the content fails to load, primarily |
|
591 |
* useful when using the contentURL method of loading content. |
|
592 |
*/ |
|
593 |
loadContent: function(element) { |
|
594 |
element = $(element); |
|
595 |
if (this.options.content) { |
|
596 |
var c; |
|
597 |
if (this.options.content.domObj) { |
|
598 |
c = $(this.options.content.domObj); |
|
599 |
} else { |
|
600 |
c = $(this.options.content); |
|
601 |
} |
|
602 |
if (c) { |
|
603 |
if (this.options.content.addTo) { |
|
604 |
this.options.content.addTo(element); |
|
605 |
} else { |
|
606 |
element.appendChild(c); |
|
607 |
} |
|
608 |
this.contentIsLoaded = true; |
|
609 |
} else { |
|
610 |
element.innerHTML = this.options.content; |
|
611 |
this.contentIsLoaded = true; |
Also available in: Unified diff