cf4f97c00521bc21e8ae5f9ed642b4b99dfe9e27
[Packages/TYPO3.CMS.git] / t3lib / jsfunc.inline.js
1 /*<![CDATA[*/
2
3 /***************************************************************
4 * Inline-Relational-Record Editing
5 *
6 * $Id$
7 *
8 *
9 *
10 * Copyright notice
11 *
12 * (c) 2006-2007 Oliver Hader <oh@inpublica.de>
13 * All rights reserved
14 *
15 * This script is part of the TYPO3 project. The TYPO3 project is
16 * free software; you can redistribute it and/or modify
17 * it under the terms of the GNU General Public License as published by
18 * the Free Software Foundation; either version 2 of the License, or
19 * (at your option) any later version.
20 *
21 * The GNU General Public License can be found at
22 * http://www.gnu.org/copyleft/gpl.html.
23 *
24 * This script is distributed in the hope that it will be useful,
25 * but WITHOUT ANY WARRANTY; without even the implied warranty of
26 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
27 * GNU General Public License for more details.
28 *
29 * This copyright notice MUST APPEAR in all copies of the script!
30 ***************************************************************/
31
32 var inline = {
33 prependFormFieldNames: 'data',
34 noTitleString: '[No title]',
35 lockedAjaxMethod: {},
36 data: {},
37
38 addToDataArray: function(object) {
39 $H(object).each(function(pair) {
40 inline.data[pair.key] = $H(inline.data[pair.key]).merge(pair.value).toObject();
41 });
42 },
43 setPrependFormFieldNames: function(value) { this.prependFormFieldNames = value; },
44 setNoTitleString: function(value) { this.noTitleString = value; },
45
46 expandCollapseRecord: function(objectId, expandSingle) {
47 var currentUid = this.parseFormElementName('none', objectId, 1);
48 var objectPrefix = this.parseFormElementName('full', objectId, 0, 1);
49
50 var currentState = '';
51 var collapse = new Array();
52 var expand = new Array();
53
54 // if only a single record should be visibly for that set of records
55 // and the record clicked itself is no visible, collapse all others
56 if (expandSingle && !Element.visible(objectId+'_fields'))
57 collapse = this.collapseAllRecords(objectId, objectPrefix, currentUid);
58
59 Element.toggle(objectId+'_fields');
60 currentState = Element.visible(objectId+'_fields') ? 1 : 0
61
62 if (this.isNewRecord(objectId))
63 this.updateExpandedCollapsedStateLocally(objectId, currentState);
64 else if (currentState)
65 expand.push(currentUid);
66 else if (!currentState)
67 collapse.push(currentUid);
68
69 this.setExpandedCollapsedState(objectId, expand.join(','), collapse.join(','));
70
71 return false;
72 },
73
74 collapseAllRecords: function(objectId, objectPrefix, callingUid) {
75 // get the form field, where all records are stored
76 var objectName = this.prependFormFieldNames+this.parseFormElementName('parts', objectId, 3, 2);
77 var formObj = document.getElementsByName(objectName);
78 var collapse = [];
79
80 if (formObj.length) {
81 // the uid of the calling object (last part in objectId)
82 var recObjectId = '';
83
84 var records = formObj[0].value.split(',');
85 for (var i=0; i<records.length; i++) {
86 recObjectId = objectPrefix+'['+records[i]+']';
87 if (records[i] != callingUid && Element.visible(recObjectId+'_fields')) {
88 Element.hide(recObjectId+'_fields');
89 if (this.isNewRecord(recObjectId)) this.updateExpandedCollapsedStateLocally(recObjectId, 0);
90 else collapse.push(records[i]);
91 }
92 }
93 }
94
95 return collapse;
96 },
97
98 updateExpandedCollapsedStateLocally: function(objectId, value) {
99 var ucName = 'uc'+this.parseFormElementName('parts', objectId, 3, 2);
100 var ucFormObj = document.getElementsByName(ucName);
101 if (ucFormObj.length) ucFormObj[0].value = value;
102 },
103
104 createNewRecord: function(objectId,prevRecordUid) {
105 if (this.isBelowMax(objectId)) {
106 if (prevRecordUid) {
107 objectId += '['+prevRecordUid+']';
108 }
109 this.makeAjaxCall('createNewRecord', [this.getNumberOfRTE(), objectId], true);
110 } else {
111 alert('There are no more relations possible at this moment!');
112 }
113 return false;
114 },
115
116 setExpandedCollapsedState: function(objectId, expand, collapse) {
117 this.makeAjaxCall('setExpandedCollapsedState', [objectId, expand, collapse]);
118 },
119
120 makeAjaxCall: function(method, params, lock) {
121 var max, url='', urlParams='', options={};
122 if (method && params && params.length && this.lockAjaxMethod(method, lock)) {
123 url = 'alt_doc_ajax.php';
124 urlParams += '&ajax[0]='+method;
125 for (var i=0, max=params.length; i<max; i++) {
126 urlParams += '&ajax['+(i+1)+']='+params[i];
127 }
128 options = {
129 method: 'post',
130 parameters: urlParams,
131 onSuccess: function(xhr) { inline.processAjaxResponse(method, xhr); },
132 onFailure: function(xhr) { inline.showAjaxFailure(method, xhr); }
133 };
134
135 new Ajax.Request(url, options);
136 }
137 },
138
139 lockAjaxMethod: function(method, lock) {
140 if (!lock || !inline.lockedAjaxMethod[method]) {
141 inline.lockedAjaxMethod[method] = true;
142 return true;
143 } else {
144 return false;
145 }
146 },
147
148 unlockAjaxMethod: function(method) {
149 inline.lockedAjaxMethod[method] = false;
150 },
151
152 processAjaxResponse: function(method, xhr) {
153 inline.unlockAjaxMethod(method);
154 var json = eval('('+xhr.responseText+')');
155 for (var i in json.scriptCall) eval(json.scriptCall[i]);
156 },
157
158 showAjaxFailure: function(method, xhr) {
159 inline.unlockAjaxMethod(method);
160 alert('Error: '+xhr.status+"\n"+xhr.statusText);
161 },
162
163 // foreign_selector: used by selector box (type='select')
164 importNewRecord: function(objectId) {
165 var selector = $(objectId+'_selector');
166 if (selector.selectedIndex != -1) {
167 var selectedValue = selector.options[selector.selectedIndex].value;
168 if (!this.data.unique || !this.data.unique[objectId]) {
169 selector.options[selector.selectedIndex].selected = false;
170 }
171 this.makeAjaxCall('createNewRecord', [this.getNumberOfRTE(), objectId, selectedValue], true);
172 }
173 return false;
174 },
175
176 // foreign_selector: used by element browser (type='group/db')
177 importElement: function(objectId, table, uid, type) {
178 window.setTimeout(
179 function() {
180 inline.makeAjaxCall('createNewRecord', [this.getNumberOfRTE(), objectId, uid], true);
181 },
182 10
183 );
184 },
185
186 // Check uniqueness for element browser:
187 checkUniqueElement: function(objectId, table, uid, type) {
188 if (this.checkUniqueUsed(objectId, uid, table)) {
189 return {passed: false,message: 'There is already a relation to the selected element!'};
190 } else {
191 return {passed: true};
192 }
193 },
194
195 // Checks if a record was used and should be unique:
196 checkUniqueUsed: function(objectId, uid, table) {
197 if (this.data.unique && this.data.unique[objectId]) {
198 var unique = this.data.unique[objectId];
199 var values = $H(unique.used).values();
200
201 // for select: only the uid is stored
202 if (unique['type'] == 'select') {
203 if (values.indexOf(uid) != -1) return true;
204
205 // for group/db: table and uid is stored in a assoc array
206 } else if (unique.type == 'groupdb') {
207 for (var i=values.length-1; i>=0; i--) {
208 // if the pair table:uid is already used:
209 if (values[i].table==table && values[i].uid==uid) return true;
210 }
211 }
212 }
213 return false;
214 },
215
216 setUniqueElement: function(objectId, table, uid, type, elName) {
217 var recordUid = this.parseFormElementName('none', elName, 1, 1);
218 // alert(objectId+'/'+table+'/'+uid+'/'+recordUid);
219 this.setUnique(objectId, recordUid, uid);
220 },
221
222 // this function is applied to a newly inserted record by AJAX
223 // it removes the used select items, that should be unique
224 setUnique: function(objectId, recordUid, selectedValue) {
225 if (this.data.unique && this.data.unique[objectId]) {
226 var unique = this.data.unique[objectId];
227
228 if (unique.type == 'select') {
229 // remove used items from each select-field of the child records
230 if (!(unique.selector && unique.max == -1)) {
231 var elName = this.parseFormElementName('full', objectId, 1)+'['+recordUid+']['+unique.field+']';
232 var formName = this.prependFormFieldNames+this.parseFormElementName('parts', objectId, 3, 1);
233
234 var fieldObj = document.getElementsByName(elName);
235 var values = $H(unique.used).values();
236
237 if (fieldObj.length) {
238 // remove all items from the new select-item which are already used in other children
239 for (var i=0; i<values.length; i++) this.removeSelectOption(fieldObj[0], values[i]);
240 // set the selected item automatically to the first of the remaining items if no selector is used
241 if (!unique.selector) {
242 selectedValue = fieldObj[0].options[0].value;
243 fieldObj[0].options[0].selected = true;
244 this.updateUnique(fieldObj[0], objectId, formName, recordUid);
245 this.handleChangedField(fieldObj[0], objectId+'['+recordUid+']');
246 }
247 if (typeof this.data.unique[objectId].used.length != 'undefined') {
248 this.data.unique[objectId].used = {};
249 }
250 this.data.unique[objectId].used[recordUid] = selectedValue;
251 }
252 }
253 } else if (unique.type == 'groupdb') {
254 // add the new record to the used items:
255 this.data.unique[objectId].used[recordUid] = {'table':unique.elTable, 'uid':selectedValue};
256 }
257
258 // remove used items from a selector-box
259 if (unique.selector == 'select' && selectedValue) {
260 var selector = $(objectId+'_selector');
261 this.removeSelectOption(selector, selectedValue);
262 this.data.unique[objectId]['used'][recordUid] = selectedValue;
263 }
264 }
265 },
266
267 domAddNewRecord: function(method, insertObject, objectPrefix, htmlData) {
268 if (this.isBelowMax(objectPrefix)) {
269 if (method == 'bottom')
270 new Insertion.Bottom(insertObject, htmlData);
271 else if (method == 'after')
272 new Insertion.After(insertObject, htmlData);
273 }
274 },
275
276 changeSorting: function(objectId, direction) {
277 var objectName = this.prependFormFieldNames+this.parseFormElementName('parts', objectId, 3, 2);
278 var objectPrefix = this.parseFormElementName('full', objectId, 0, 1);
279 var formObj = document.getElementsByName(objectName);
280
281 if (formObj.length) {
282 // the uid of the calling object (last part in objectId)
283 var callingUid = this.parseFormElementName('none', objectId, 1);
284 var records = formObj[0].value.split(',');
285 var current = records.indexOf(callingUid);
286 var changed = false;
287
288 // move up
289 if (direction > 0 && current > 0) {
290 records[current] = records[current-1];
291 records[current-1] = callingUid;
292 changed = true;
293
294 // move down
295 } else if (direction < 0 && current < records.length-1) {
296 records[current] = records[current+1];
297 records[current+1] = callingUid;
298 changed = true;
299 }
300
301 if (changed) {
302 formObj[0].value = records.join(',');
303 var cAdj = direction > 0 ? 1 : 0; // adjustment
304 $(objectId+'_div').parentNode.insertBefore(
305 $(objectPrefix+'['+records[current-cAdj]+']_div'),
306 $(objectPrefix+'['+records[current+1-cAdj]+']_div')
307 );
308 this.redrawSortingButtons(objectPrefix, records);
309 }
310 }
311
312 return false;
313 },
314
315 dragAndDropSorting: function(element) {
316 var objectId = element.getAttribute('id').replace(/_records$/, '');
317 var objectName = inline.prependFormFieldNames+inline.parseFormElementName('parts', objectId, 3);
318 var formObj = document.getElementsByName(objectName);
319
320 if (formObj.length) {
321 var checked = new Array();
322 var order = Sortable.sequence(element);
323 var records = formObj[0].value.split(',');
324
325 // check if ordered uid is really part of the records
326 // virtually deleted items might still be there but ordering shouldn't saved at all on them
327 for (var i=0; i<order.length; i++) {
328 if (records.indexOf(order[i]) != -1) {
329 checked.push(order[i]);
330 }
331 }
332
333 formObj[0].value = checked.join(',');
334
335 if (inline.data.config && inline.data.config[objectId]) {
336 var table = inline.data.config[objectId].table;
337 inline.redrawSortingButtons(objectId+'['+table+']', checked);
338 }
339 }
340 },
341
342 createDragAndDropSorting: function(objectId) {
343 Sortable.create(
344 objectId,
345 {
346 format: /^[^_\-](?:[A-Za-z0-9\[\]\-\_]*)\[(.*)\]_div$/,
347 onUpdate: inline.dragAndDropSorting,
348 tag: 'div',
349 handle: 'sortableHandle',
350 overlap: 'vertical',
351 constraint: 'vertical'
352 }
353 );
354 },
355
356 destroyDragAndDropSorting: function(objectId) {
357 Sortable.destroy(objectId);
358 },
359
360 redrawSortingButtons: function(objectPrefix, records) {
361 var i;
362 var headerObj;
363 var sortingObj = new Array();
364
365 // if no records were passed, fetch them from form field
366 if (typeof records == 'undefined') {
367 records = new Array();
368 var objectName = this.prependFormFieldNames+this.parseFormElementName('parts', objectPrefix, 3, 1);
369 var formObj = document.getElementsByName(objectName);
370 if (formObj.length) records = formObj[0].value.split(',');
371 }
372
373 for (i=0; i<records.length; i++) {
374 if (!records[i].length) continue;
375
376 headerObj = $(objectPrefix+'['+records[i]+']_header');
377 sortingObj[0] = headerObj.getElementsByClassName('sortingUp');
378 sortingObj[1] = headerObj.getElementsByClassName('sortingDown');
379
380 if (sortingObj[0].length)
381 sortingObj[0][0].style.visibility = i == 0 ? 'hidden' : 'visible';
382 if (sortingObj[1].length)
383 sortingObj[1][0].style.visibility = i == records.length-1 ? 'hidden' : 'visible';
384 }
385 },
386
387 memorizeAddRecord: function(objectPrefix, newUid, afterUid, selectedValue) {
388 if (this.isBelowMax(objectPrefix)) {
389 var objectName = this.prependFormFieldNames+this.parseFormElementName('parts', objectPrefix, 3, 1);
390 var formObj = document.getElementsByName(objectName);
391
392 if (formObj.length) {
393 var records = new Array();
394 if (formObj[0].value.length) records = formObj[0].value.split(',');
395
396 if (afterUid) {
397 var newRecords = new Array();
398 for (var i=0; i<records.length; i++) {
399 if (records[i].length) newRecords.push(records[i]);
400 if (afterUid == records[i]) newRecords.push(newUid);
401 }
402 records = newRecords;
403 } else {
404 records.push(newUid);
405 }
406 formObj[0].value = records.join(',');
407 }
408
409 this.redrawSortingButtons(objectPrefix, records);
410
411 if (this.data.unique && this.data.unique[objectPrefix]) {
412 var unique = this.data.unique[objectPrefix];
413 this.setUnique(objectPrefix, newUid, selectedValue);
414 }
415 }
416
417 // if we reached the maximum off possible records after this action, hide the new buttons
418 if (!this.isBelowMax(objectPrefix)) {
419 this.hideElementsWithClassName('inlineNewButton', this.parseFormElementName('full', objectPrefix, 0 , 1));
420 }
421
422 if (TBE_EDITOR) TBE_EDITOR.fieldChanged_fName(objectName, formObj);
423 },
424
425 memorizeRemoveRecord: function(objectName, removeUid) {
426 var formObj = document.getElementsByName(objectName);
427 if (formObj.length) {
428 var parts = new Array();
429 if (formObj[0].value.length) {
430 parts = formObj[0].value.split(',');
431 parts = parts.without(removeUid);
432 formObj[0].value = parts.join(',');
433 if (TBE_EDITOR) TBE_EDITOR.fieldChanged_fName(objectName, formObj);
434 return parts.length;
435 }
436 }
437 return false;
438 },
439
440 updateUnique: function(srcElement, objectPrefix, formName, recordUid) {
441 if (this.data.unique && this.data.unique[objectPrefix]) {
442 var unique = this.data.unique[objectPrefix];
443 var oldValue = unique.used[recordUid];
444
445 if (unique.selector == 'select') {
446 var selector = $(objectPrefix+'_selector');
447 this.removeSelectOption(selector, srcElement.value);
448 if (typeof oldValue != 'undefined') this.readdSelectOption(selector, oldValue, unique);
449 }
450
451 if (!(unique.selector && unique.max == -1)) {
452 var formObj = document.getElementsByName(formName);
453 if (unique && formObj.length) {
454 var records = formObj[0].value.split(',');
455 var recordObj;
456 for (var i=0; i<records.length; i++) {
457 recordObj = document.getElementsByName(this.prependFormFieldNames+'['+unique.table+']['+records[i]+']['+unique.field+']');
458 if (recordObj.length && recordObj[0] != srcElement) {
459 this.removeSelectOption(recordObj[0], srcElement.value);
460 if (typeof oldValue != 'undefined') this.readdSelectOption(recordObj[0], oldValue, unique);
461 }
462 }
463 this.data.unique[objectPrefix].used[recordUid] = srcElement.value;
464 }
465 }
466 }
467 },
468
469 revertUnique: function(objectPrefix, elName, recordUid) {
470 if (this.data.unique && this.data.unique[objectPrefix]) {
471 var unique = this.data.unique[objectPrefix];
472 var fieldObj = elName ? document.getElementsByName(elName+'['+unique.field+']') : null;
473
474 if (unique.type == 'select') {
475 if (fieldObj && fieldObj.length) {
476 delete(this.data.unique[objectPrefix].used[recordUid])
477
478 if (unique.selector == 'select') {
479 if (!isNaN(fieldObj[0].value)) {
480 var selector = $(objectPrefix+'_selector');
481 this.readdSelectOption(selector, fieldObj[0].value, unique);
482 }
483 }
484
485 if (!(unique.selector && unique.max == -1)) {
486 var formName = this.prependFormFieldNames+this.parseFormElementName('parts', objectPrefix, 3, 1);
487 var formObj = document.getElementsByName(formName);
488 if (formObj.length) {
489 var records = formObj[0].value.split(',');
490 var recordObj;
491 // walk through all inline records on that level and get the select field
492 for (var i=0; i<records.length; i++) {
493 recordObj = document.getElementsByName(this.prependFormFieldNames+'['+unique.table+']['+records[i]+']['+unique.field+']');
494 if (recordObj.length) this.readdSelectOption(recordObj[0], fieldObj[0].value, unique);
495 }
496 }
497 }
498 }
499 } else if (unique.type == 'groupdb') {
500 // alert(objectPrefix+'/'+recordUid);
501 delete(this.data.unique[objectPrefix].used[recordUid])
502 }
503 }
504 },
505
506 enableDisableRecord: function(objectId) {
507 var elName = this.parseFormElementName('full', objectId, 2);
508 var imageObj = $(objectId+'_disabled');
509 var valueObj = document.getElementsByName(elName+'[hidden]');
510 var formObj = document.getElementsByName(elName+'[hidden]_0');
511 var imagePath = '';
512
513 if (valueObj && formObj) {
514 formObj[0].click();
515 imagePath = this.parsePath(imageObj.src);
516 imageObj.src = imagePath+(valueObj[0].value > 0 ? 'button_unhide.gif' : 'button_hide.gif');
517 }
518
519 return false;
520 },
521
522 deleteRecord: function(objectId) {
523 var i, j, inlineRecords, records, childObjectId, childTable;
524 var objectPrefix = this.parseFormElementName('full', objectId, 0 , 1);
525 var elName = this.parseFormElementName('full', objectId, 2);
526 var shortName = this.parseFormElementName('parts', objectId, 2);
527 var recordUid = this.parseFormElementName('none', objectId, 1);
528 var beforeDeleteIsBelowMax = this.isBelowMax(objectPrefix);
529
530 // revert the unique settings if available
531 this.revertUnique(objectPrefix, elName, recordUid);
532
533 // if the record is new and was never saved before, just remove it from DOM
534 if (this.isNewRecord(objectId)) {
535 new Effect.Fade(objectId+'_div', { afterFinish: function() { Element.remove(objectId+'_div'); } });
536 // if the record already exists in storage, mark it to be deleted on clicking the save button
537 } else {
538 document.getElementsByName('cmd'+shortName+'[delete]')[0].disabled = false;
539 new Effect.Fade(objectId+'_div');
540 }
541
542 // Remove from TBE_EDITOR (required fields, required range, etc.):
543 if (TBE_EDITOR && TBE_EDITOR.removeElement) {
544 inlineRecords = document.getElementsByClassName('inlineRecord', objectId+'_div');
545 // Remove nested child records from TBE_EDITOR required/range checks:
546 for (i=inlineRecords.length-1; i>=0; i--) {
547 if (inlineRecords[i].value.length) {
548 records = inlineRecords[i].value.split(',');
549 childObjectId = this.data.map[inlineRecords[i].name];
550 childTable = this.data.config[childObjectId].table;
551 for (j=records.length-1; j>=0; j--) {
552 TBE_EDITOR.removeElement(this.prependFormFieldNames+'['+childTable+']['+records[j]+']');
553 }
554 }
555 }
556 TBE_EDITOR.removeElement(this.prependFormFieldNames+shortName);
557 }
558
559 var recordCount = this.memorizeRemoveRecord(
560 this.prependFormFieldNames+this.parseFormElementName('parts', objectId, 3, 2),
561 recordUid
562 );
563
564 if (recordCount <= 1) {
565 this.destroyDragAndDropSorting(this.parseFormElementName('full', objectId, 0 , 2)+'_records');
566 }
567 this.redrawSortingButtons(objectPrefix);
568
569 // if the NEW-button was hidden and now we can add again new children, show the button
570 if (!beforeDeleteIsBelowMax && this.isBelowMax(objectPrefix))
571 this.showElementsWithClassName('inlineNewButton', this.parseFormElementName('full', objectPrefix, 0 , 1));
572
573 return false;
574 },
575
576 parsePath: function(path) {
577 var backSlash = path.lastIndexOf('\\');
578 var normalSlash = path.lastIndexOf('/');
579
580 if (backSlash > 0)
581 path = path.substring(0,backSlash+1);
582 else if (normalSlash > 0)
583 path = path.substring(0,normalSlash+1);
584 else
585 path = '';
586
587 return path;
588 },
589
590 parseFormElementName: function(wrap, objectId, rightCount, skipRight) {
591 // remove left and right side "data[...|...]" -> '...|...'
592 objectId = objectId.substr(0, objectId.lastIndexOf(']')).substr(objectId.indexOf('[')+1);
593
594 if (!wrap) wrap = 'full';
595 if (!skipRight) skipRight = 0;
596
597 var elReturn;
598 var elParts = new Array();
599 var idParts = objectId.split('][');
600 for (var i=0; i<skipRight; i++) idParts.pop();
601
602 if (rightCount > 0) {
603 for (var i=0; i<rightCount; i++) elParts.unshift(idParts.pop());
604 } else {
605 for (var i=0; i<-rightCount; i++) idParts.shift();
606 elParts = idParts;
607 }
608
609 if (wrap == 'full') {
610 elReturn = this.prependFormFieldNames+'['+elParts.join('][')+']';
611 } else if (wrap == 'parts') {
612 elReturn = '['+elParts.join('][')+']';
613 } else if (wrap == 'none') {
614 elReturn = elParts.length > 1 ? elParts : elParts.join('');
615 }
616
617 return elReturn;
618 },
619
620 handleChangedField: function(formField, objectId) {
621 var formObj;
622 if (typeof formField == 'object') {
623 formObj = formField;
624 } else {
625 formObj = document.getElementsByName(formField);
626 if (formObj.length) formObj = formObj[0];
627 }
628
629 if (formObj != undefined) {
630 var value;
631 if (formObj.nodeName == 'SELECT') value = formObj.options[formObj.selectedIndex].text;
632 else value = formObj.value;
633 $(objectId+'_label').innerHTML = value.length ? value : this.noTitleString;
634 }
635 return true;
636 },
637
638 arrayAssocCount: function(object) {
639 var count = 0;
640 if (typeof object.length != 'undefined') {
641 count = object.length;
642 } else {
643 for (var i in object) count++;
644 }
645 return count;
646 },
647
648 isBelowMax: function(objectPrefix) {
649 var isBelowMax = true;
650 var objectName = this.prependFormFieldNames+this.parseFormElementName('parts', objectPrefix, 3, 1);
651 var formObj = document.getElementsByName(objectName);
652
653 if (this.data.config && this.data.config[objectPrefix] && formObj.length) {
654 var recordCount = formObj[0].value ? formObj[0].value.split(',').length : 0;
655 if (recordCount >= this.data.config[objectPrefix].max) isBelowMax = false;
656 }
657 if (isBelowMax && this.data.unique && this.data.unique[objectPrefix]) {
658 var unique = this.data.unique[objectPrefix];
659 if (this.arrayAssocCount(unique.used) >= unique.max && unique.max >= 0) isBelowMax = false;
660 }
661 return isBelowMax;
662 },
663
664 getOptionsHash: function(selectObj) {
665 var optionsHash = {};
666 for (var i=0; i<selectObj.options.length; i++) optionsHash[selectObj.options[i].value] = i;
667 return optionsHash;
668 },
669
670 removeSelectOption: function(selectObj, value) {
671 var optionsHash = this.getOptionsHash(selectObj);
672 if (optionsHash[value] != undefined) selectObj.options[optionsHash[value]] = null;
673 },
674
675 readdSelectOption: function(selectObj, value, unique) {
676 var index = null;
677 var optionsHash = this.getOptionsHash(selectObj);
678 var possibleValues = $H(unique.possible).keys();
679
680 for (var possibleValue in unique.possible) {
681 if (possibleValue == value) break;
682 if (optionsHash[possibleValue] != undefined) index = optionsHash[possibleValue];
683 }
684
685 if (index == null) index = 0;
686 else if (index < selectObj.options.length) index++;
687 // recreate the <option> tag
688 var readdOption = document.createElement('option');
689 readdOption.text = unique.possible[value];
690 readdOption.value = value;
691 // add the <option> at the right position
692 selectObj.add(readdOption, document.all ? index : selectObj.options[index]);
693 },
694
695 hideElementsWithClassName: function(className, parentElement) {
696 this.setVisibilityOfElementsWithClassName('hide', className, parentElement);
697 },
698
699 showElementsWithClassName: function(className, parentElement) {
700 this.setVisibilityOfElementsWithClassName('show', className, parentElement);
701 },
702
703 setVisibilityOfElementsWithClassName: function(action, className, parentElement) {
704 var domObjects = document.getElementsByClassName(className, parentElement);
705 for (var i=0; i<domObjects.length; i++) {
706 if (action == 'hide')
707 new Effect.Fade(domObjects[i]);
708 else if (action = 'show')
709 new Effect.Appear(domObjects[i]);
710 }
711 },
712
713 fadeOutFadeIn: function(objectId) {
714 var optIn = { duration:0.5, transition:Effect.Transitions.linear, from:0.50, to:1.00 };
715 var optOut = { duration:0.5, transition:Effect.Transitions.linear, from:1.00, to:0.50 };
716 optOut.afterFinish = function() { new Effect.Opacity(objectId, optIn); };
717 new Effect.Opacity(objectId, optOut);
718 },
719
720 isNewRecord: function(objectId) {
721 return $(objectId+'_div') && $(objectId+'_div').hasClassName('inlineIsNewRecord')
722 ? true
723 : false;
724 },
725
726 // Find and fix nested of inline and tab levels if a new element was created dynamically (it doesn't know about its nesting):
727 findContinuedNestedLevel: function(nested, objectId) {
728 if (this.data.nested && this.data.nested[objectId]) {
729 // Remove the first element from the new nested stack, it's just a hint:
730 nested.shift();
731 nested = this.data.nested[objectId].concat(nested);
732 return nested;
733 } else {
734 return nested;
735 }
736 },
737
738 getNumberOfRTE: function() {
739 var number = 0;
740 if (typeof RTEarea != 'undefined' && RTEarea.length > 0) {
741 number = RTEarea.length-1;
742 }
743 return number;
744 }
745 }
746
747 Object.extend(Array.prototype, {
748 diff: function(current) {
749 var diff = new Array();
750 if (this.length == current.length) {
751 for (var i=0; i<this.length; i++) {
752 if (this[i] !== current[i]) diff.push(i);
753 }
754 }
755 return diff;
756 }
757 });
758
759 /*]]>*/