|
1 |
|
2 function Namespace(name) { |
|
3 this.__name__ = name; |
|
4 } |
|
5 |
|
6 cw = new Namespace('cw'); |
|
7 |
|
8 jQuery.extend(cw, { |
|
9 cubes: new Namespace('cubes'), |
|
10 /* provide a removeEventListener / detachEvent definition to |
|
11 * to bypass a jQuery 1.4.2 bug when unbind() is called on a |
|
12 * plain JS object and not a DOM node. |
|
13 * see http://dev.jquery.com/ticket/6184 for more details |
|
14 */ |
|
15 removeEventListener: function() {}, |
|
16 detachEvent: function() {}, |
|
17 |
|
18 log: function log() { |
|
19 if (typeof window !== "undefined" && window.console && window.console.log) { |
|
20 // NOTE console.log requires "console" to be the console to be "this" |
|
21 window.console.log.apply(console, arguments); |
|
22 } |
|
23 }, |
|
24 |
|
25 //removed: getElementsByTagAndClassName, replaceChildNodes, toggleElementClass |
|
26 // partial, merge, isNotEmpty, update, |
|
27 // String.in_, String.join, list, getattr, attrgetter, methodcaller, |
|
28 // min, max, dict, concat |
|
29 jqNode: function (node) { |
|
30 /** |
|
31 * .. function:: jqNode(node) |
|
32 * |
|
33 * safe version of jQuery('#nodeid') because we use ':' in nodeids |
|
34 * which messes with jQuery selection mechanism |
|
35 */ |
|
36 if (typeof node === 'string') { |
|
37 node = document.getElementById(node); |
|
38 } |
|
39 if (node) { |
|
40 return $(node); |
|
41 } |
|
42 return null; |
|
43 }, |
|
44 |
|
45 // escapes string selectors (e.g. "foo.[subject]:42" -> "foo\.\[subject\]\:42" |
|
46 escape: function(selector) { |
|
47 if (typeof selector === 'string') { |
|
48 return selector.replace( /(:|\.|\[|\])/g, "\\$1" ); |
|
49 } |
|
50 // cw.log('non string selector', selector); |
|
51 return ''; |
|
52 }, |
|
53 |
|
54 getNode: function (node) { |
|
55 if (typeof node === 'string') { |
|
56 return document.getElementById(node); |
|
57 } |
|
58 return node; |
|
59 }, |
|
60 |
|
61 evalJSON: function (json) { // trust source |
|
62 try { |
|
63 return eval("(" + json + ")"); |
|
64 } catch(e) { |
|
65 cw.log(e); |
|
66 cw.log('The faulty json source was', json); |
|
67 throw (e); |
|
68 } |
|
69 }, |
|
70 |
|
71 urlEncode: function (str) { |
|
72 if (typeof encodeURIComponent !== "undefined") { |
|
73 return encodeURIComponent(str).replace(/\'/g, '%27'); |
|
74 } else { |
|
75 return escape(str).replace(/\+/g, '%2B').replace(/\"/g, '%22'). |
|
76 rval.replace(/\'/g, '%27'); |
|
77 } |
|
78 }, |
|
79 |
|
80 swapDOM: function (dest, src) { |
|
81 dest = cw.getNode(dest); |
|
82 var parent = dest.parentNode; |
|
83 if (src) { |
|
84 src = cw.getNode(src); |
|
85 parent.replaceChild(src, dest); |
|
86 } else { |
|
87 parent.removeChild(dest); |
|
88 } |
|
89 return src; |
|
90 }, |
|
91 |
|
92 sortValueExtraction: function (node) { |
|
93 var $node = $(node); |
|
94 var sortvalue = $node.attr('cubicweb:sortvalue'); |
|
95 // No metadata found, use cell content as sort key |
|
96 if (typeof sortvalue === 'undefined') { |
|
97 return $node.text(); |
|
98 } |
|
99 return cw.evalJSON(sortvalue); |
|
100 }, |
|
101 |
|
102 }); |
|
103 |
|
104 |
|
105 cw.utils = new Namespace('cw.utils'); |
|
106 jQuery.extend(cw.utils, { |
|
107 |
|
108 deprecatedFunction: function (msg, newfunc) { |
|
109 return function () { |
|
110 cw.log(msg); |
|
111 return newfunc.apply(this, arguments); |
|
112 }; |
|
113 }, |
|
114 |
|
115 createDomFunction: function (tag) { |
|
116 function builddom(params, children) { |
|
117 var node = document.createElement(tag); |
|
118 for (key in params) { |
|
119 var value = params[key]; |
|
120 if (key.substring(0, 2) === 'on') { |
|
121 // this is an event handler definition |
|
122 if (typeof value === 'string') { |
|
123 // litteral definition |
|
124 value = new Function(value); |
|
125 } |
|
126 node[key] = value; |
|
127 } else { // normal node attribute |
|
128 jQuery(node).attr(key, params[key]); |
|
129 } |
|
130 } |
|
131 if (children) { |
|
132 if (!cw.utils.isArrayLike(children)) { |
|
133 children = [children]; |
|
134 for (var i = 2; i < arguments.length; i++) { |
|
135 var arg = arguments[i]; |
|
136 if (cw.utils.isArray(arg)) { |
|
137 jQuery.merge(children, arg); |
|
138 } else { |
|
139 children.push(arg); |
|
140 } |
|
141 } |
|
142 } |
|
143 for (var i = 0; i < children.length; i++) { |
|
144 var child = children[i]; |
|
145 if (typeof child === "string" || typeof child === "number") { |
|
146 child = document.createTextNode(child); |
|
147 } |
|
148 node.appendChild(child); |
|
149 } |
|
150 } |
|
151 return node; |
|
152 } |
|
153 return builddom; |
|
154 }, |
|
155 |
|
156 /** |
|
157 * .. function:: toISOTimestamp(date) |
|
158 * |
|
159 */ |
|
160 toISOTimestamp: function (date) { |
|
161 if (date == null) { |
|
162 return null; |
|
163 } |
|
164 |
|
165 function _padTwo(n) { |
|
166 return (n > 9) ? n : "0" + n; |
|
167 } |
|
168 var isoTime = [_padTwo(date.getHours()), _padTwo(date.getMinutes()), |
|
169 _padTwo(date.getSeconds())].join(':'); |
|
170 var isoDate = [date.getFullYear(), _padTwo(date.getMonth() + 1), |
|
171 _padTwo(date.getDate())].join("-"); |
|
172 return isoDate + " " + isoTime; |
|
173 }, |
|
174 |
|
175 /** |
|
176 * .. function:: nodeWalkDepthFirst(node, visitor) |
|
177 * |
|
178 * depth-first implementation of the nodeWalk function found |
|
179 * in `MochiKit.Base <http://mochikit.com/doc/html/MochiKit/Base.html#fn-nodewalk>`_ |
|
180 */ |
|
181 nodeWalkDepthFirst: function (node, visitor) { |
|
182 var children = visitor(node); |
|
183 if (children) { |
|
184 for (var i = 0; i < children.length; i++) { |
|
185 cw.utils.nodeWalkDepthFirst(children[i], visitor); |
|
186 } |
|
187 } |
|
188 }, |
|
189 |
|
190 isArray: function (it) { // taken from dojo |
|
191 return it && (it instanceof Array || typeof it === "array"); |
|
192 }, |
|
193 |
|
194 isString: function (it) { // taken from dojo |
|
195 return !!arguments.length && it != null && (typeof it === "string" || it instanceof String); |
|
196 }, |
|
197 |
|
198 isArrayLike: function (it) { // taken from dojo |
|
199 return (it && it !== undefined && |
|
200 // keep out built-in constructors (Number, String, ...) |
|
201 // which have length properties |
|
202 !cw.utils.isString(it) && !jQuery.isFunction(it) && |
|
203 !(it.tagName && it.tagName.toLowerCase() == 'form') && |
|
204 (cw.utils.isArray(it) || isFinite(it.length))); |
|
205 }, |
|
206 |
|
207 /** |
|
208 * .. function:: formContents(elem) |
|
209 * |
|
210 * cannot use jQuery.serializeArray() directly because of FCKeditor |
|
211 */ |
|
212 formContents: function (elem) { |
|
213 var $elem, array, names, values; |
|
214 $elem = cw.jqNode(elem); |
|
215 array = $elem.serializeArray(); |
|
216 |
|
217 if (typeof FCKeditor !== 'undefined') { |
|
218 $elem.find('textarea').each(function (idx, textarea) { |
|
219 var fck = FCKeditorAPI.GetInstance(textarea.id); |
|
220 if (fck) { |
|
221 array = jQuery.map(array, function (dict) { |
|
222 if (dict.name === textarea.name) { |
|
223 // filter out the textarea's - likely empty - value ... |
|
224 return null; |
|
225 } |
|
226 return dict; |
|
227 }); |
|
228 // ... so we can put the HTML coming from FCKeditor instead. |
|
229 array.push({ |
|
230 name: textarea.name, |
|
231 value: fck.GetHTML() |
|
232 }); |
|
233 } |
|
234 }); |
|
235 } |
|
236 |
|
237 names = []; |
|
238 values = []; |
|
239 jQuery.each(array, function (idx, dict) { |
|
240 names.push(dict.name); |
|
241 values.push(dict.value); |
|
242 }); |
|
243 return [names, values]; |
|
244 }, |
|
245 |
|
246 /** |
|
247 * .. function:: sliceList(lst, start, stop, step) |
|
248 * |
|
249 * returns a subslice of `lst` using `start`/`stop`/`step` |
|
250 * start, stop might be negative |
|
251 * |
|
252 * >>> sliceList(['a', 'b', 'c', 'd', 'e', 'f'], 2) |
|
253 * ['c', 'd', 'e', 'f'] |
|
254 * >>> sliceList(['a', 'b', 'c', 'd', 'e', 'f'], 2, -2) |
|
255 * ['c', 'd'] |
|
256 * >>> sliceList(['a', 'b', 'c', 'd', 'e', 'f'], -3) |
|
257 * ['d', 'e', 'f'] |
|
258 */ |
|
259 sliceList: function (lst, start, stop, step) { |
|
260 start = start || 0; |
|
261 stop = stop || lst.length; |
|
262 step = step || 1; |
|
263 if (stop < 0) { |
|
264 stop = Math.max(lst.length + stop, 0); |
|
265 } |
|
266 if (start < 0) { |
|
267 start = Math.min(lst.length + start, lst.length); |
|
268 } |
|
269 var result = []; |
|
270 for (var i = start; i < stop; i += step) { |
|
271 result.push(lst[i]); |
|
272 } |
|
273 return result; |
|
274 }, |
|
275 |
|
276 /** |
|
277 * returns the last element of an array-like object or undefined if empty |
|
278 */ |
|
279 lastOf: function(array) { |
|
280 if (array.length) { |
|
281 return array[array.length-1]; |
|
282 } else { |
|
283 return undefined; |
|
284 } |
|
285 }, |
|
286 |
|
287 |
|
288 /** |
|
289 * .. function:: extend(array1, array2) |
|
290 * |
|
291 * equivalent of python ``+=`` statement on lists (array1 += array2) |
|
292 */ |
|
293 extend: function(array1, array2) { |
|
294 array1.push.apply(array1, array2); |
|
295 return array1; // return array1 for convenience |
|
296 }, |
|
297 |
|
298 /** |
|
299 * .. function:: difference(lst1, lst2) |
|
300 * |
|
301 * returns a list containing all elements in `lst1` that are not |
|
302 * in `lst2`. |
|
303 */ |
|
304 difference: function(lst1, lst2) { |
|
305 return jQuery.grep(lst1, function(elt, i) { |
|
306 return jQuery.inArray(elt, lst2) == -1; |
|
307 }); |
|
308 }, |
|
309 /** |
|
310 * .. function:: domid(string) |
|
311 * |
|
312 * return a valid DOM id from a string (should also be usable in jQuery |
|
313 * search expression...). This is the javascript implementation of |
|
314 * :func:`cubicweb.uilib.domid`. |
|
315 */ |
|
316 domid: function (string) { |
|
317 var newstring = string.replace(".", "_").replace("-", "_"); |
|
318 while (newstring != string) { |
|
319 string = newstring; |
|
320 newstring = newstring.replace(".", "_").replace("-", "_"); |
|
321 } |
|
322 return newstring; // XXX |
|
323 }, |
|
324 |
|
325 /** |
|
326 * .. function:: strFuncCall(fname, *args) |
|
327 * |
|
328 * return a string suitable to call the `fname` javascript function with the |
|
329 * given arguments (which should be correctly typed).. This is providing |
|
330 * javascript implementation equivalent to :func:`cubicweb.uilib.js`. |
|
331 */ |
|
332 strFuncCall: function(fname /* ...*/) { |
|
333 return (fname + '(' + |
|
334 $.map(cw.utils.sliceList(arguments, 1), JSON.stringify).join(',') |
|
335 + ')' |
|
336 ); |
|
337 }, |
|
338 |
|
339 callAjaxFuncThenReload: function callAjaxFuncThenReload (/*...*/) { |
|
340 var d = asyncRemoteExec.apply(null, arguments); |
|
341 d.addCallback(function(msg) { |
|
342 window.location.reload(); |
|
343 if (msg) |
|
344 updateMessage(msg); |
|
345 }); |
|
346 } |
|
347 }); |
|
348 |
|
349 /** DOM factories ************************************************************/ |
|
350 A = cw.utils.createDomFunction('a'); |
|
351 BUTTON = cw.utils.createDomFunction('button'); |
|
352 BR = cw.utils.createDomFunction('br'); |
|
353 CANVAS = cw.utils.createDomFunction('canvas'); |
|
354 DD = cw.utils.createDomFunction('dd'); |
|
355 DIV = cw.utils.createDomFunction('div'); |
|
356 DL = cw.utils.createDomFunction('dl'); |
|
357 DT = cw.utils.createDomFunction('dt'); |
|
358 FIELDSET = cw.utils.createDomFunction('fieldset'); |
|
359 FORM = cw.utils.createDomFunction('form'); |
|
360 H1 = cw.utils.createDomFunction('H1'); |
|
361 H2 = cw.utils.createDomFunction('H2'); |
|
362 H3 = cw.utils.createDomFunction('H3'); |
|
363 H4 = cw.utils.createDomFunction('H4'); |
|
364 H5 = cw.utils.createDomFunction('H5'); |
|
365 H6 = cw.utils.createDomFunction('H6'); |
|
366 HR = cw.utils.createDomFunction('hr'); |
|
367 IMG = cw.utils.createDomFunction('img'); |
|
368 INPUT = cw.utils.createDomFunction('input'); |
|
369 LABEL = cw.utils.createDomFunction('label'); |
|
370 LEGEND = cw.utils.createDomFunction('legend'); |
|
371 LI = cw.utils.createDomFunction('li'); |
|
372 OL = cw.utils.createDomFunction('ol'); |
|
373 OPTGROUP = cw.utils.createDomFunction('optgroup'); |
|
374 OPTION = cw.utils.createDomFunction('option'); |
|
375 P = cw.utils.createDomFunction('p'); |
|
376 PRE = cw.utils.createDomFunction('pre'); |
|
377 SELECT = cw.utils.createDomFunction('select'); |
|
378 SPAN = cw.utils.createDomFunction('span'); |
|
379 STRONG = cw.utils.createDomFunction('strong'); |
|
380 TABLE = cw.utils.createDomFunction('table'); |
|
381 TBODY = cw.utils.createDomFunction('tbody'); |
|
382 TD = cw.utils.createDomFunction('td'); |
|
383 TEXTAREA = cw.utils.createDomFunction('textarea'); |
|
384 TFOOT = cw.utils.createDomFunction('tfoot'); |
|
385 TH = cw.utils.createDomFunction('th'); |
|
386 THEAD = cw.utils.createDomFunction('thead'); |
|
387 TR = cw.utils.createDomFunction('tr'); |
|
388 TT = cw.utils.createDomFunction('tt'); |
|
389 UL = cw.utils.createDomFunction('ul'); |
|
390 |
|
391 // cubicweb specific |
|
392 //IFRAME = cw.utils.createDomFunction('iframe'); |
|
393 |
|
394 |
|
395 function IFRAME(params) { |
|
396 if ('name' in params) { |
|
397 try { |
|
398 var node = document.createElement('<iframe name="' + params['name'] + '">'); |
|
399 } catch (ex) { |
|
400 var node = document.createElement('iframe'); |
|
401 node.id = node.name = params.name; |
|
402 } |
|
403 } |
|
404 else { |
|
405 var node = document.createElement('iframe'); |
|
406 } |
|
407 for (key in params) { |
|
408 if (key !== 'name') { |
|
409 var value = params[key]; |
|
410 if (key.substring(0, 2) === 'on') { |
|
411 // this is an event handler definition |
|
412 if (typeof value === 'string') { |
|
413 // litteral definition |
|
414 value = new Function(value); |
|
415 } |
|
416 node[key] = value; |
|
417 } else { // normal node attribute |
|
418 node.setAttribute(key, params[key]); |
|
419 } |
|
420 } |
|
421 } |
|
422 return node; |
|
423 } |
|
424 |
|
425 // cubes: tag, keyword and apycot seem to use this, including require/provide |
|
426 // backward compat |
|
427 CubicWeb = cw; |
|
428 |
|
429 jQuery.extend(cw, { |
|
430 require: cw.utils.deprecatedFunction( |
|
431 '[3.9] CubicWeb.require() is not used anymore', |
|
432 function(module) {}), |
|
433 provide: cw.utils.deprecatedFunction( |
|
434 '[3.9] CubicWeb.provide() is not used anymore', |
|
435 function(module) {}) |
|
436 }); |
|
437 |
|
438 jQuery(document).ready(function() { |
|
439 $(cw).trigger('server-response', [false, document]); |
|
440 }); |