ba42bbe77e7b69aa561ec610da465bffe470e69c
3 /***************************************************************
4 * Inline-Relational-Record Editing
12 * (c) 2006-2009 Oliver Hader <oh@inpublica.de>
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.
21 * The GNU General Public License can be found at
22 * http://www.gnu.org/copyleft/gpl.html.
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.
29 * This copyright notice MUST APPEAR in all copies of the script!
30 ***************************************************************/
33 structureSeparator
: '-',
34 prependFormFieldNames
: 'data',
35 noTitleString
: '[No title]',
40 addToDataArray: function(object
) {
41 $H(object
).each(function(pair
) {
42 inline
.data
[pair
.key
] = $H(inline
.data
[pair
.key
]).merge(pair
.value
).toObject();
45 setPrependFormFieldNames: function(value
) { this.prependFormFieldNames
= value
; },
46 setNoTitleString: function(value
) { this.noTitleString
= value
; },
48 expandCollapseRecord: function(objectId
, expandSingle
) {
49 var currentUid
= this.parseObjectId('none', objectId
, 1);
50 var objectPrefix
= this.parseObjectId('full', objectId
, 0, 1);
52 var currentState
= '';
53 var collapse
= new Array();
54 var expand
= new Array();
56 // if only a single record should be visibly for that set of records
57 // and the record clicked itself is no visible, collapse all others
58 if (expandSingle
&& !Element
.visible(objectId
+'_fields'))
59 collapse
= this.collapseAllRecords(objectId
, objectPrefix
, currentUid
);
61 Element
.toggle(objectId
+'_fields');
62 currentState
= Element
.visible(objectId
+'_fields') ? 1 : 0
64 if (this.isNewRecord(objectId
))
65 this.updateExpandedCollapsedStateLocally(objectId
, currentState
);
66 else if (currentState
)
67 expand
.push(currentUid
);
68 else if (!currentState
)
69 collapse
.push(currentUid
);
71 this.setExpandedCollapsedState(objectId
, expand
.join(','), collapse
.join(','));
76 collapseAllRecords: function(objectId
, objectPrefix
, callingUid
) {
77 // get the form field, where all records are stored
78 var objectName
= this.prependFormFieldNames
+this.parseObjectId('parts', objectId
, 3, 2, true);
79 var formObj
= document
.getElementsByName(objectName
);
83 // the uid of the calling object (last part in objectId)
86 var records
= formObj
[0].value
.split(',');
87 for (var i
=0; i
<records
.length
; i
++) {
88 recObjectId
= objectPrefix
+ this.structureSeparator
+ records
[i
];
89 if (records
[i
] != callingUid
&& Element
.visible(recObjectId
+'_fields')) {
90 Element
.hide(recObjectId
+'_fields');
91 if (this.isNewRecord(recObjectId
)) this.updateExpandedCollapsedStateLocally(recObjectId
, 0);
92 else collapse
.push(records
[i
]);
100 updateExpandedCollapsedStateLocally: function(objectId
, value
) {
101 var ucName
= 'uc[inlineView]'+this.parseObjectId('parts', objectId
, 3, 2, true);
102 var ucFormObj
= document
.getElementsByName(ucName
);
103 if (ucFormObj
.length
) {
104 ucFormObj
[0].value
= value
;
108 createNewRecord: function(objectId
, recordUid
) {
109 if (this.isBelowMax(objectId
)) {
111 objectId
+= this.structureSeparator
+ recordUid
;
113 this.makeAjaxCall('createNewRecord', [this.getNumberOfRTE(), objectId
], true);
115 alert('There are no more relations possible at this moment!');
120 synchronizeLocalizeRecords: function(objectId
, type
) {
121 var parameters
= [this.getNumberOfRTE(), objectId
, type
];
122 this.makeAjaxCall('synchronizeLocalizeRecords', parameters
, true);
125 setExpandedCollapsedState: function(objectId
, expand
, collapse
) {
126 this.makeAjaxCall('setExpandedCollapsedState', [objectId
, expand
, collapse
]);
129 makeAjaxCall: function(method
, params
, lock
) {
130 var max
, url
='', urlParams
='', options
={};
131 if (method
&& params
&& params
.length
&& this.lockAjaxMethod(method
, lock
)) {
132 url
= TBE_EDITOR
.getBackendPath() + 'ajax.php';
133 urlParams
= '&ajaxID=t3lib_TCEforms_inline::'+method
;
134 for (var i
=0, max
=params
.length
; i
<max
; i
++) {
135 urlParams
+= '&ajax['+i
+']='+params
[i
];
139 parameters
: urlParams
,
140 onSuccess: function(xhr
) { inline
.processAjaxResponse(method
, xhr
); },
141 onFailure: function(xhr
) { inline
.showAjaxFailure(method
, xhr
); }
144 new Ajax
.Request(url
, options
);
148 lockAjaxMethod: function(method
, lock
) {
149 if (!lock
|| !inline
.lockedAjaxMethod
[method
]) {
150 inline
.lockedAjaxMethod
[method
] = true;
157 unlockAjaxMethod: function(method
) {
158 inline
.lockedAjaxMethod
[method
] = false;
161 processAjaxResponse: function(method
, xhr
, json
) {
162 var addTag
=null, restart
=false, processedCount
=0, element
=null, errorCatch
=[], sourcesWaiting
=[];
164 json
= eval('('+xhr
.responseText
+')');
166 // If there are elements the should be added to the <HEAD> tag (e.g. for RTEhtmlarea):
168 var head
= inline
.getDomHeadTag();
169 var headTags
= inline
.getDomHeadChildren(head
);
170 $A(json
.headData
).each(function(addTag
) {
172 if (addTag
&& (addTag
.innerHTML
|| !inline
.searchInDomTags(headTags
, addTag
))) {
173 if (addTag
.name
=='SCRIPT' && addTag
.innerHTML
&& processedCount
) {
177 if (addTag
.name
=='SCRIPT' && addTag
.innerHTML
) {
179 eval(addTag
.innerHTML
);
184 element
= inline
.createNewDomElement(addTag
);
185 // Set onload handler for external JS scripts:
186 if (addTag
.name
=='SCRIPT' && element
.src
) {
187 element
.onload
= inline
.sourceLoadedHandler(element
);
188 sourcesWaiting
.push(element
.src
);
190 head
.appendChild(element
);
193 json
.headData
.shift();
199 if (restart
|| processedCount
) {
200 window
.setTimeout(function() { inline
.reprocessAjaxResponse(method
, json
, sourcesWaiting
); }, 40);
203 inline
.unlockAjaxMethod(method
);
205 if (json
.scriptCall
&& json
.scriptCall
.length
) {
206 $A(json
.scriptCall
).each(function(value
) { eval(value
); });
211 // Check if dynamically added scripts are loaded and restart inline.processAjaxResponse():
212 reprocessAjaxResponse: function (method
, json
, sourcesWaiting
) {
213 var sourcesLoaded
= true;
214 if (sourcesWaiting
&& sourcesWaiting
.length
) {
215 $A(sourcesWaiting
).each(function(source
) {
216 if (!inline
.sourcesLoaded
[source
]) {
217 sourcesLoaded
= false;
223 $A(sourcesWaiting
).each(function(source
) {
224 delete(inline
.sourcesLoaded
[source
]);
226 window
.setTimeout(function() { inline
.processAjaxResponse(method
, null, json
); }, 80);
228 window
.setTimeout(function() { inline
.reprocessAjaxResponse(method
, json
, sourcesWaiting
); }, 40);
232 sourceLoadedHandler: function(element
) {
233 if (element
&& element
.src
) {
234 inline
.sourcesLoaded
[element
.src
] = true;
238 showAjaxFailure: function(method
, xhr
) {
239 inline
.unlockAjaxMethod(method
);
240 alert('Error: '+xhr
.status
+"\n"+xhr
.statusText
);
243 // foreign_selector: used by selector box (type='select')
244 importNewRecord: function(objectId
) {
245 var selector
= $(objectId
+'_selector');
246 if (selector
.selectedIndex
!= -1) {
247 var selectedValue
= selector
.options
[selector
.selectedIndex
].value
;
248 if (!this.data
.unique
|| !this.data
.unique
[objectId
]) {
249 selector
.options
[selector
.selectedIndex
].selected
= false;
251 this.makeAjaxCall('createNewRecord', [this.getNumberOfRTE(), objectId
, selectedValue
], true);
256 // foreign_selector: used by element browser (type='group/db')
257 importElement: function(objectId
, table
, uid
, type
) {
260 inline
.makeAjaxCall('createNewRecord', [this.getNumberOfRTE(), objectId
, uid
], true);
266 // Check uniqueness for element browser:
267 checkUniqueElement: function(objectId
, table
, uid
, type
) {
268 if (this.checkUniqueUsed(objectId
, uid
, table
)) {
269 return {passed
: false,message
: 'There is already a relation to the selected element!'};
271 return {passed
: true};
275 // Checks if a record was used and should be unique:
276 checkUniqueUsed: function(objectId
, uid
, table
) {
277 if (this.data
.unique
&& this.data
.unique
[objectId
]) {
278 var unique
= this.data
.unique
[objectId
];
279 var values
= $H(unique
.used
).values();
281 // for select: only the uid is stored
282 if (unique
['type'] == 'select') {
283 if (values
.indexOf(uid
) != -1) return true;
285 // for group/db: table and uid is stored in a assoc array
286 } else if (unique
.type
== 'groupdb') {
287 for (var i
=values
.length
-1; i
>=0; i
--) {
288 // if the pair table:uid is already used:
289 if (values
[i
].table
==table
&& values
[i
].uid
==uid
) return true;
296 setUniqueElement: function(objectId
, table
, uid
, type
, elName
) {
297 var recordUid
= this.parseFormElementName('none', elName
, 1, 1);
298 // alert(objectId+'/'+table+'/'+uid+'/'+recordUid);
299 this.setUnique(objectId
, recordUid
, uid
);
302 // this function is applied to a newly inserted record by AJAX
303 // it removes the used select items, that should be unique
304 setUnique: function(objectId
, recordUid
, selectedValue
) {
305 if (this.data
.unique
&& this.data
.unique
[objectId
]) {
306 var unique
= this.data
.unique
[objectId
];
308 if (unique
.type
== 'select') {
309 // remove used items from each select-field of the child records
310 if (!(unique
.selector
&& unique
.max
== -1)) {
311 var formName
= this.prependFormFieldNames
+this.parseObjectId('parts', objectId
, 3, 1, true);
313 var fieldObj
= document
.getElementsByName(elName
);
314 var values
= $H(unique
.used
).values();
316 if (fieldObj
.length
) {
317 // remove all items from the new select-item which are already used in other children
318 for (var i
=0; i
<values
.length
; i
++) this.removeSelectOption(fieldObj
[0], values
[i
]);
319 // set the selected item automatically to the first of the remaining items if no selector is used
320 if (!unique
.selector
) {
321 selectedValue
= fieldObj
[0].options
[0].value
;
322 fieldObj
[0].options
[0].selected
= true;
323 this.updateUnique(fieldObj
[0], objectId
, formName
, recordUid
);
324 this.handleChangedField(fieldObj
[0], objectId
+'['+recordUid
+']');
326 if (typeof this.data
.unique
[objectId
].used
.length
!= 'undefined') {
327 this.data
.unique
[objectId
].used
= {};
329 this.data
.unique
[objectId
].used
[recordUid
] = selectedValue
;
332 } else if (unique
.type
== 'groupdb') {
333 // add the new record to the used items:
334 this.data
.unique
[objectId
].used
[recordUid
] = {'table':unique
.elTable
, 'uid':selectedValue
};
337 // remove used items from a selector-box
338 if (unique
.selector
== 'select' && selectedValue
) {
339 var selector
= $(objectId
+'_selector');
340 this.removeSelectOption(selector
, selectedValue
);
341 this.data
.unique
[objectId
]['used'][recordUid
] = selectedValue
;
346 domAddNewRecord: function(method
, insertObject
, objectPrefix
, htmlData
) {
347 if (this.isBelowMax(objectPrefix
)) {
348 if (method
== 'bottom')
349 new Insertion
.Bottom(insertObject
, htmlData
);
350 else if (method
== 'after')
351 new Insertion
.After(insertObject
, htmlData
);
355 // Get script and link elements from head tag:
356 getDomHeadChildren: function(head
) {
358 $$('head script', 'head link').each(function(tag
) { headTags
.push(tag
); });
362 getDomHeadTag: function() {
363 if (document
&& document
.head
) {
364 return document
.head
;
366 var head
= $$('head');
374 // Search whether elements exist in a given haystack:
375 searchInDomTags: function(haystack
, needle
) {
377 $A(haystack
).each(function(element
) {
378 if (element
.nodeName
.toUpperCase()==needle
.name
) {
379 var attributesCount
= $H(needle
.attributes
).keys().length
;
380 var attributesFound
= 0;
381 $H(needle
.attributes
).each(function(attribute
) {
382 if (element
.getAttribute
&& element
.getAttribute(attribute
.key
)==attribute
.value
) {
386 if (attributesFound
==attributesCount
) {
395 // Create a new DOM element:
396 createNewDomElement: function(addTag
) {
397 var element
= document
.createElement(addTag
.name
);
398 if (addTag
.attributes
) {
399 $H(addTag
.attributes
).each(function(attribute
) {
400 element
[attribute
.key
] = attribute
.value
;
406 changeSorting: function(objectId
, direction
) {
407 var objectName
= this.prependFormFieldNames
+this.parseObjectId('parts', objectId
, 3, 2, true);
408 var objectPrefix
= this.parseObjectId('full', objectId
, 0, 1);
409 var formObj
= document
.getElementsByName(objectName
);
411 if (formObj
.length
) {
412 // the uid of the calling object (last part in objectId)
413 var callingUid
= this.parseObjectId('none', objectId
, 1);
414 var records
= formObj
[0].value
.split(',');
415 var current
= records
.indexOf(callingUid
);
419 if (direction
> 0 && current
> 0) {
420 records
[current
] = records
[current
-1];
421 records
[current
-1] = callingUid
;
425 } else if (direction
< 0 && current
< records
.length
-1) {
426 records
[current
] = records
[current
+1];
427 records
[current
+1] = callingUid
;
432 formObj
[0].value
= records
.join(',');
433 var cAdj
= direction
> 0 ? 1 : 0; // adjustment
434 $(objectId
+'_div').parentNode
.insertBefore(
435 $(objectPrefix
+ this.structureSeparator
+ records
[current
-cAdj
] + '_div'),
436 $(objectPrefix
+ this.structureSeparator
+ records
[current
+1-cAdj
] + '_div')
438 this.redrawSortingButtons(objectPrefix
, records
);
445 dragAndDropSorting: function(element
) {
446 var objectId
= element
.getAttribute('id').replace(/_records$/, '');
447 var objectName
= inline
.prependFormFieldNames
+inline
.parseObjectId('parts', objectId
, 3, 0, true);
448 var formObj
= document
.getElementsByName(objectName
);
450 if (formObj
.length
) {
451 var checked
= new Array();
452 var order
= Sortable
.sequence(element
);
453 var records
= formObj
[0].value
.split(',');
455 // check if ordered uid is really part of the records
456 // virtually deleted items might still be there but ordering shouldn't saved at all on them
457 for (var i
=0; i
<order
.length
; i
++) {
458 if (records
.indexOf(order
[i
]) != -1) {
459 checked
.push(order
[i
]);
463 formObj
[0].value
= checked
.join(',');
465 if (inline
.data
.config
&& inline
.data
.config
[objectId
]) {
466 var table
= inline
.data
.config
[objectId
].table
;
467 inline
.redrawSortingButtons(objectId
+ inline
.structureSeparator
+ table
, checked
);
472 createDragAndDropSorting: function(objectId
) {
473 Position
.includeScrollOffsets
= true;
477 format
: /^[^_\-](?:[A-Za-z0-9\-\_]*)-(.*)_div$/,
478 onUpdate
: inline
.dragAndDropSorting
,
480 handle
: 'sortableHandle',
482 constraint
: 'vertical'
487 destroyDragAndDropSorting: function(objectId
) {
488 Sortable
.destroy(objectId
);
491 redrawSortingButtons: function(objectPrefix
, records
) {
494 var sortingObj
= new Array();
496 // if no records were passed, fetch them from form field
497 if (typeof records
== 'undefined') {
498 records
= new Array();
499 var objectName
= this.prependFormFieldNames
+this.parseObjectId('parts', objectPrefix
, 3, 1, true);
500 var formObj
= document
.getElementsByName(objectName
);
501 if (formObj
.length
) records
= formObj
[0].value
.split(',');
504 for (i
=0; i
<records
.length
; i
++) {
505 if (!records
[i
].length
) continue;
507 headerObj
= $(objectPrefix
+ this.structureSeparator
+ records
[i
] + '_header');
508 sortingObj
[0] = Element
.select(headerObj
, '.sortingUp');
509 sortingObj
[1] = Element
.select(headerObj
, '.sortingDown');
511 if (sortingObj
[0].length
) {
512 sortingObj
[0][0].style
.visibility
= (i
== 0 ? 'hidden' : 'visible');
514 if (sortingObj
[1].length
) {
515 sortingObj
[1][0].style
.visibility
= (i
== records
.length
-1 ? 'hidden' : 'visible');
520 memorizeAddRecord: function(objectPrefix
, newUid
, afterUid
, selectedValue
) {
521 if (this.isBelowMax(objectPrefix
)) {
522 var objectName
= this.prependFormFieldNames
+this.parseObjectId('parts', objectPrefix
, 3, 1, true);
523 var formObj
= document
.getElementsByName(objectName
);
525 if (formObj
.length
) {
526 var records
= new Array();
527 if (formObj
[0].value
.length
) records
= formObj
[0].value
.split(',');
530 var newRecords
= new Array();
531 for (var i
=0; i
<records
.length
; i
++) {
532 if (records
[i
].length
) newRecords
.push(records
[i
]);
533 if (afterUid
== records
[i
]) newRecords
.push(newUid
);
535 records
= newRecords
;
537 records
.push(newUid
);
539 formObj
[0].value
= records
.join(',');
542 this.redrawSortingButtons(objectPrefix
, records
);
544 if (this.data
.unique
&& this.data
.unique
[objectPrefix
]) {
545 var unique
= this.data
.unique
[objectPrefix
];
546 this.setUnique(objectPrefix
, newUid
, selectedValue
);
550 // if we reached the maximum off possible records after this action, hide the new buttons
551 if (!this.isBelowMax(objectPrefix
)) {
552 var objectParent
= this.parseObjectId('full', objectPrefix
, 0 , 1);
553 var md5
= this.getObjectMD5(objectParent
);
554 this.hideElementsWithClassName('.inlineNewButton'+(md5
? '.'+md5
: ''), objectParent
);
557 if (TBE_EDITOR
) TBE_EDITOR
.fieldChanged_fName(objectName
, formObj
);
560 memorizeRemoveRecord: function(objectName
, removeUid
) {
561 var formObj
= document
.getElementsByName(objectName
);
562 if (formObj
.length
) {
563 var parts
= new Array();
564 if (formObj
[0].value
.length
) {
565 parts
= formObj
[0].value
.split(',');
566 parts
= parts
.without(removeUid
);
567 formObj
[0].value
= parts
.join(',');
568 if (TBE_EDITOR
) TBE_EDITOR
.fieldChanged_fName(objectName
, formObj
);
575 updateUnique: function(srcElement
, objectPrefix
, formName
, recordUid
) {
576 if (this.data
.unique
&& this.data
.unique
[objectPrefix
]) {
577 var unique
= this.data
.unique
[objectPrefix
];
578 var oldValue
= unique
.used
[recordUid
];
580 if (unique
.selector
== 'select') {
581 var selector
= $(objectPrefix
+'_selector');
582 this.removeSelectOption(selector
, srcElement
.value
);
583 if (typeof oldValue
!= 'undefined') this.readdSelectOption(selector
, oldValue
, unique
);
586 if (!(unique
.selector
&& unique
.max
== -1)) {
587 var formObj
= document
.getElementsByName(formName
);
588 if (unique
&& formObj
.length
) {
589 var records
= formObj
[0].value
.split(',');
591 for (var i
=0; i
<records
.length
; i
++) {
592 recordObj
= document
.getElementsByName(this.prependFormFieldNames
+'['+unique
.table
+']['+records
[i
]+']['+unique
.field
+']');
593 if (recordObj
.length
&& recordObj
[0] != srcElement
) {
594 this.removeSelectOption(recordObj
[0], srcElement
.value
);
595 if (typeof oldValue
!= 'undefined') this.readdSelectOption(recordObj
[0], oldValue
, unique
);
598 this.data
.unique
[objectPrefix
].used
[recordUid
] = srcElement
.value
;
604 revertUnique: function(objectPrefix
, elName
, recordUid
) {
605 if (this.data
.unique
&& this.data
.unique
[objectPrefix
]) {
606 var unique
= this.data
.unique
[objectPrefix
];
607 var fieldObj
= elName
? document
.getElementsByName(elName
+'['+unique
.field
+']') : null;
609 if (unique
.type
== 'select') {
610 if (fieldObj
&& fieldObj
.length
) {
611 delete(this.data
.unique
[objectPrefix
].used
[recordUid
])
613 if (unique
.selector
== 'select') {
614 if (!isNaN(fieldObj
[0].value
)) {
615 var selector
= $(objectPrefix
+'_selector');
616 this.readdSelectOption(selector
, fieldObj
[0].value
, unique
);
620 if (!(unique
.selector
&& unique
.max
== -1)) {
621 var formName
= this.prependFormFieldNames
+this.parseObjectId('parts', objectPrefix
, 3, 1, true);
622 var formObj
= document
.getElementsByName(formName
);
623 if (formObj
.length
) {
624 var records
= formObj
[0].value
.split(',');
626 // walk through all inline records on that level and get the select field
627 for (var i
=0; i
<records
.length
; i
++) {
628 recordObj
= document
.getElementsByName(this.prependFormFieldNames
+'['+unique
.table
+']['+records
[i
]+']['+unique
.field
+']');
629 if (recordObj
.length
) this.readdSelectOption(recordObj
[0], fieldObj
[0].value
, unique
);
634 } else if (unique
.type
== 'groupdb') {
635 // alert(objectPrefix+'/'+recordUid);
636 delete(this.data
.unique
[objectPrefix
].used
[recordUid
])
641 enableDisableRecord: function(objectId
) {
642 var elName
= this.parseObjectId('full', objectId
, 2, 0, true);
643 var imageObj
= $(objectId
+'_disabled');
644 var valueObj
= document
.getElementsByName(elName
+'[hidden]');
645 var formObj
= document
.getElementsByName(elName
+'[hidden]_0');
648 if (valueObj
&& formObj
) {
650 imagePath
= this.parsePath(imageObj
.src
);
651 imageObj
.src
= imagePath
+(valueObj
[0].value
> 0 ? 'button_unhide.gif' : 'button_hide.gif');
657 deleteRecord: function(objectId
, options
) {
658 var i
, j
, inlineRecords
, records
, childObjectId
, childTable
;
659 var objectPrefix
= this.parseObjectId('full', objectId
, 0 , 1);
660 var elName
= this.parseObjectId('full', objectId
, 2, 0, true);
661 var shortName
= this.parseObjectId('parts', objectId
, 2, 0, true);
662 var recordUid
= this.parseObjectId('none', objectId
, 1);
663 var beforeDeleteIsBelowMax
= this.isBelowMax(objectPrefix
);
665 // revert the unique settings if available
666 this.revertUnique(objectPrefix
, elName
, recordUid
);
668 // Remove from TBE_EDITOR (required fields, required range, etc.):
669 if (TBE_EDITOR
&& TBE_EDITOR
.removeElement
) {
670 var removeStack
= [];
671 inlineRecords
= Element
.select(objectId
+'_div', '.inlineRecord');
672 // Remove nested child records from TBE_EDITOR required/range checks:
673 for (i
=inlineRecords
.length
-1; i
>=0; i
--) {
674 if (inlineRecords
[i
].value
.length
) {
675 records
= inlineRecords
[i
].value
.split(',');
676 childObjectId
= this.data
.map
[inlineRecords
[i
].name
];
677 childTable
= this.data
.config
[childObjectId
].table
;
678 for (j
=records
.length
-1; j
>=0; j
--) {
679 removeStack
.push(this.prependFormFieldNames
+'['+childTable
+']['+records
[j
]+']');
683 removeStack
.push(this.prependFormFieldNames
+shortName
);
684 TBE_EDITOR
.removeElementArray(removeStack
);
687 // If the record is new and was never saved before, just remove it from DOM:
688 if (this.isNewRecord(objectId
) || options
&& options
.forceDirectRemoval
) {
689 this.fadeAndRemove(objectId
+'_div');
690 // If the record already exists in storage, mark it to be deleted on clicking the save button:
692 document
.getElementsByName('cmd'+shortName
+'[delete]')[0].disabled
= false;
693 new Effect
.Fade(objectId
+'_div');
696 var recordCount
= this.memorizeRemoveRecord(
697 this.prependFormFieldNames
+this.parseObjectId('parts', objectId
, 3, 2, true),
701 if (recordCount
<= 1) {
702 this.destroyDragAndDropSorting(this.parseObjectId('full', objectId
, 0 , 2)+'_records');
704 this.redrawSortingButtons(objectPrefix
);
706 // if the NEW-button was hidden and now we can add again new children, show the button
707 if (!beforeDeleteIsBelowMax
&& this.isBelowMax(objectPrefix
)) {
708 var objectParent
= this.parseObjectId('full', objectPrefix
, 0 , 1);
709 var md5
= this.getObjectMD5(objectParent
);
710 this.showElementsWithClassName('.inlineNewButton'+(md5
? '.'+md5
: ''), objectParent
);
715 parsePath: function(path
) {
716 var backSlash
= path
.lastIndexOf('\\');
717 var normalSlash
= path
.lastIndexOf('/');
720 path
= path
.substring(0,backSlash
+1);
721 else if (normalSlash
> 0)
722 path
= path
.substring(0,normalSlash
+1);
729 parseFormElementName: function(wrap
, formElementName
, rightCount
, skipRight
) {
730 var idParts
= this.splitFormElementName(formElementName
);
732 if (!wrap
) wrap
= 'full';
733 if (!skipRight
) skipRight
= 0;
735 var elParts
= new Array();
736 for (var i
=0; i
<skipRight
; i
++) idParts
.pop();
738 if (rightCount
> 0) {
739 for (var i
=0; i
<rightCount
; i
++) elParts
.unshift(idParts
.pop());
741 for (var i
=0; i
<-rightCount
; i
++) idParts
.shift();
745 var elReturn
= this.constructFormElementName(wrap
, elParts
);
750 splitFormElementName: function(formElementName
) {
751 // remove left and right side "data[...|...]" -> '...|...'
752 formElementName
= formElementName
.substr(0, formElementName
.lastIndexOf(']')).substr(formElementName
.indexOf('[')+1);
753 var parts
= objectId
.split('][');
758 splitObjectId: function(objectId
) {
759 objectId
= objectId
.substr(objectId
.indexOf(this.structureSeparator
)+1);
760 var parts
= objectId
.split(this.structureSeparator
);
765 constructFormElementName: function(wrap
, parts
) {
768 if (wrap
== 'full') {
769 elReturn
= this.prependFormFieldNames
+'['+parts
.join('][')+']';
770 } else if (wrap
== 'parts') {
771 elReturn
= '['+parts
.join('][')+']';
772 } else if (wrap
== 'none') {
773 elReturn
= parts
.length
> 1 ? parts
: parts
.join('');
779 constructObjectId: function(wrap
, parts
) {
782 if (wrap
== 'full') {
783 elReturn
= this.prependFormFieldNames
+this.structureSeparator
+parts
.join(this.structureSeparator
);
784 } else if (wrap
== 'parts') {
785 elReturn
= this.structureSeparator
+parts
.join(this.structureSeparator
);
786 } else if (wrap
== 'none') {
787 elReturn
= parts
.length
> 1 ? parts
: parts
.join('');
793 parseObjectId: function(wrap
, objectId
, rightCount
, skipRight
, returnAsFormElementName
) {
794 var idParts
= this.splitObjectId(objectId
);
796 if (!wrap
) wrap
= 'full';
797 if (!skipRight
) skipRight
= 0;
799 var elParts
= new Array();
800 for (var i
=0; i
<skipRight
; i
++) idParts
.pop();
802 if (rightCount
> 0) {
803 for (var i
=0; i
<rightCount
; i
++) elParts
.unshift(idParts
.pop());
805 for (var i
=0; i
<-rightCount
; i
++) idParts
.shift();
809 if (returnAsFormElementName
) {
810 var elReturn
= this.constructFormElementName(wrap
, elParts
);
812 var elReturn
= this.constructObjectId(wrap
, elParts
);
818 handleChangedField: function(formField
, objectId
) {
820 if (typeof formField
== 'object') {
823 formObj
= document
.getElementsByName(formField
);
824 if (formObj
.length
) formObj
= formObj
[0];
827 if (formObj
!= undefined) {
829 if (formObj
.nodeName
== 'SELECT') value
= formObj
.options
[formObj
.selectedIndex
].text
;
830 else value
= formObj
.value
;
831 $(objectId
+'_label').innerHTML
= value
.length
? value
: this.noTitleString
;
836 arrayAssocCount: function(object
) {
838 if (typeof object
.length
!= 'undefined') {
839 count
= object
.length
;
841 for (var i
in object
) count
++;
846 isBelowMax: function(objectPrefix
) {
847 var isBelowMax
= true;
848 var objectName
= this.prependFormFieldNames
+this.parseObjectId('parts', objectPrefix
, 3, 1, true);
849 var formObj
= document
.getElementsByName(objectName
);
851 if (this.data
.config
&& this.data
.config
[objectPrefix
] && formObj
.length
) {
852 var recordCount
= formObj
[0].value
? formObj
[0].value
.split(',').length
: 0;
853 if (recordCount
>= this.data
.config
[objectPrefix
].max
) isBelowMax
= false;
855 if (isBelowMax
&& this.data
.unique
&& this.data
.unique
[objectPrefix
]) {
856 var unique
= this.data
.unique
[objectPrefix
];
857 if (this.arrayAssocCount(unique
.used
) >= unique
.max
&& unique
.max
>= 0) isBelowMax
= false;
862 getOptionsHash: function(selectObj
) {
863 var optionsHash
= {};
864 for (var i
=0; i
<selectObj
.options
.length
; i
++) optionsHash
[selectObj
.options
[i
].value
] = i
;
868 removeSelectOption: function(selectObj
, value
) {
869 var optionsHash
= this.getOptionsHash(selectObj
);
870 if (optionsHash
[value
] != undefined) selectObj
.options
[optionsHash
[value
]] = null;
873 readdSelectOption: function(selectObj
, value
, unique
) {
875 var optionsHash
= this.getOptionsHash(selectObj
);
876 var possibleValues
= $H(unique
.possible
).keys();
878 for (var possibleValue
in unique
.possible
) {
879 if (possibleValue
== value
) break;
880 if (optionsHash
[possibleValue
] != undefined) index
= optionsHash
[possibleValue
];
883 if (index
== null) index
= 0;
884 else if (index
< selectObj
.options
.length
) index
++;
885 // recreate the <option> tag
886 var readdOption
= document
.createElement('option');
887 readdOption
.text
= unique
.possible
[value
];
888 readdOption
.value
= value
;
889 // add the <option> at the right position
890 selectObj
.add(readdOption
, document
.all
? index
: selectObj
.options
[index
]);
893 hideElementsWithClassName: function(selector
, parentElement
) {
894 this.setVisibilityOfElementsWithClassName('hide', selector
, parentElement
);
897 showElementsWithClassName: function(selector
, parentElement
) {
898 this.setVisibilityOfElementsWithClassName('show', selector
, parentElement
);
901 setVisibilityOfElementsWithClassName: function(action
, selector
, parentElement
) {
902 var domObjects
= Selector
.findChildElements($(parentElement
), [selector
]);
903 if (action
== 'hide') {
904 $A(domObjects
).each(function(domObject
) { new Effect
.Fade(domObject
); });
905 } else if (action
== 'show') {
906 $A(domObjects
).each(function(domObject
) { new Effect
.Appear(domObject
); });
910 fadeOutFadeIn: function(objectId
) {
911 var optIn
= { duration
:0.5, transition
:Effect
.Transitions
.linear
, from:0.50, to
:1.00 };
912 var optOut
= { duration
:0.5, transition
:Effect
.Transitions
.linear
, from:1.00, to
:0.50 };
913 optOut
.afterFinish = function() { new Effect
.Opacity(objectId
, optIn
); };
914 new Effect
.Opacity(objectId
, optOut
);
917 isNewRecord: function(objectId
) {
918 return $(objectId
+'_div') && $(objectId
+'_div').hasClassName('inlineIsNewRecord')
923 // Find and fix nested of inline and tab levels if a new element was created dynamically (it doesn't know about its nesting):
924 findContinuedNestedLevel: function(nested
, objectId
) {
925 if (this.data
.nested
&& this.data
.nested
[objectId
]) {
926 // Remove the first element from the new nested stack, it's just a hint:
928 nested
= this.data
.nested
[objectId
].concat(nested
);
935 getNumberOfRTE: function() {
937 if (typeof RTEarea
!= 'undefined' && RTEarea
.length
> 0) {
938 number
= RTEarea
.length
-1;
943 getObjectMD5: function(objectPrefix
) {
945 if (this.data
.config
&& this.data
.config
[objectPrefix
] && this.data
.config
[objectPrefix
].md5
) {
946 md5
= this.data
.config
[objectPrefix
].md5
;
951 fadeAndRemove: function(element
) {
953 new Effect
.Fade(element
, { afterFinish: function() { Element
.remove(element
); } });
958 Object
.extend(Array
.prototype, {
959 diff: function(current
) {
960 var diff
= new Array();
961 if (this.length
== current
.length
) {
962 for (var i
=0; i
<this.length
; i
++) {
963 if (this[i
] !== current
[i
]) diff
.push(i
);