]> CyberLeo.Net >> Repos - Github/sugarcrm.git/blob - modules/ModuleBuilder/javascript/studio2.js
Release 6.2.0
[Github/sugarcrm.git] / modules / ModuleBuilder / javascript / studio2.js
1 /*********************************************************************************
2  * SugarCRM Community Edition is a customer relationship management program developed by
3  * SugarCRM, Inc. Copyright (C) 2004-2011 SugarCRM Inc.
4  * 
5  * This program is free software; you can redistribute it and/or modify it under
6  * the terms of the GNU Affero General Public License version 3 as published by the
7  * Free Software Foundation with the addition of the following permission added
8  * to Section 15 as permitted in Section 7(a): FOR ANY PART OF THE COVERED WORK
9  * IN WHICH THE COPYRIGHT IS OWNED BY SUGARCRM, SUGARCRM DISCLAIMS THE WARRANTY
10  * OF NON INFRINGEMENT OF THIRD PARTY RIGHTS.
11  * 
12  * This program is distributed in the hope that it will be useful, but WITHOUT
13  * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
14  * FOR A PARTICULAR PURPOSE.  See the GNU Affero General Public License for more
15  * details.
16  * 
17  * You should have received a copy of the GNU Affero General Public License along with
18  * this program; if not, see http://www.gnu.org/licenses or write to the Free
19  * Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301 USA.
21  * 
22  * You can contact SugarCRM, Inc. headquarters at 10050 North Wolfe Road,
23  * SW2-130, Cupertino, CA 95014, USA. or at email address contact@sugarcrm.com.
24  * 
25  * The interactive user interfaces in modified source and object code versions
26  * of this program must display Appropriate Legal Notices, as required under
27  * Section 5 of the GNU Affero General Public License version 3.
28  * 
29  * In accordance with Section 7(b) of the GNU Affero General Public License version 3,
30  * these Appropriate Legal Notices must retain the display of the "Powered by
31  * SugarCRM" logo. If the display of the logo is not reasonably feasible for
32  * technical reasons, the Appropriate Legal Notices must display the words
33  * "Powered by SugarCRM".
34  ********************************************************************************/
35
36
37 if(typeof('console') == 'undefined'){
38         console = {
39                 log: function(message) {
40         
41                 }
42         }
43 }
44 var _debug_ = false;
45 var _write_ = function( message ){ if(_debug_){ console.log(message);} }
46
47
48
49 Studio2 = {
50
51         init: function() {
52                 var Dom = YAHOO.util.Dom,
53                         DDTarget = YAHOO.util.DDTarget,
54                         DDM = YAHOO.utilDragDropMgr;
55                 
56                 Studio2.maxColumns = parseInt(document.getElementById('maxColumns').value);
57                 Studio2.setStartId(parseInt(document.getElementById('idCount').value));
58                 Studio2.setStartId(1000);
59                 Studio2.fieldwidth = parseInt(document.getElementById('fieldwidth').value);
60                 Studio2.panelNumber = parseInt(document.getElementById('nextPanelId').value);
61                 Studio2.isIE = SUGAR.isIE;
62                 Studio2.expandableFields = [];
63
64                 //      Activate the layout panels
65                 var panels = document.getElementById('panels');
66                 Dom.setStyle(panels, "visibility", "hidden");
67                 //new Studio2.PanelDD(panels.id,'studio2.panels'); // add the main layout area into PANELS to allow for panel drags to empty areas
68                 new DDTarget(panels.id, 'studio2.panels');
69                 for (var i=0;i<panels.childNodes.length;i++) {
70                         var panel = panels.childNodes[i];
71                         if (panel.nodeName == 'DIV') { // a valid panel
72
73                                 // add the panel into the ROWS drag-and-drop group to allow for drags to empty areas of the panels
74                                 new DDTarget(panel.id,'studio2.rows');
75
76                                 for (var j=0;j<panel.childNodes.length;j++) {
77                                         var row = panel.childNodes[j];
78                                         if(typeof(row.id)!='undefined' && row.id!=null) 
79
80                                         if (row.nodeName == 'DIV' && row.className == 'le_row' ) { // a valid row
81
82                                                 // Convert all (empty) fields into variable width fields
83                                                 var leftSibling = null;
84                                                 var foundEmpty = 0;
85
86                                                 for (var k=0;k<row.childNodes.length;k++) {
87                                                         var field = row.childNodes[k];
88                                                         var ranOnce = false;
89                                                         if (field.nodeName == 'DIV') { // field
90
91                                                                 for (var l=0;l<field.childNodes.length;l++) {
92                                                                         var property = field.childNodes[l];
93
94                                                                         if (property.className && (property.className.indexOf('field_name') != -1) && property.firstChild) {
95                                                                                 if (property.firstChild.nodeValue.indexOf('(empty)') != -1) {
96                                                                                         //register field to be expandable
97                                                                                         _write_("(empty) found");
98                                                                                         Studio2.setSpecial(field);
99                                                                                         Studio2.registerExpandableField( Studio2.prevField(field) || Studio2.nextField( field ) );
100                                                                                         break;
101                                                                                 }else if (property.firstChild.nodeValue.indexOf('(filler)') != -1){
102                                                                                         var sibling = Studio2.prevField( field ) || Studio2.nextField( field );
103                                                                                         Studio2.setSpecial( field );
104                                                                                         var swapFields = Studio2.nextField( field ) != null;
105                                                                                         Studio2.registerExpandableField( sibling);
106                                                                                         this.toggleFieldWidth (sibling );
107                                                                                         ranOnce = true;
108                                                                                         if( swapFields ){
109                                                                                                 //swap (filler) with the sibling
110                                                                                                 field = Studio2.nextField (sibling ) || Studio2.prevField( sibling );
111
112                                                                                                 this.swapElements( sibling , field)
113
114                                                                                         }
115                                                                                         break;
116                                                                                 }
117
118                                                                         }
119                                                                 }
120                                                         }
121                                                         if( ranOnce ){break;}
122                                                 }
123
124                                                 Studio2.activateElement(row);
125                                         }
126                                 }
127                         }
128                 }
129                 Studio2.activateElement(panels);
130         Dom.setStyle(panels, "visibility", '');
131
132                 // Activate the fields in the availablefields list
133                 var availablefields = document.getElementById('availablefields');
134                 Studio2.activateElement(availablefields);
135
136                 // Setup Delete area in the toolbox (the Trash icon)
137                 var d = document.getElementById('delete');
138                 Studio2.setSpecial(d);
139                 var delDD = new DDTarget('delete', 'studio2.panels');
140                 delDD.addToGroup('studio2.rows');
141                 delDD.addToGroup('studio2.fields');
142                 
143                 var fillerProxy = Studio2.newField();
144                 Studio2.setSpecial(fillerProxy);
145                 var hanger = document.getElementById('fillerproxy');
146                 hanger.parentNode.insertBefore(fillerProxy,hanger.nextSibling);
147                 Studio2.activateElement(fillerProxy);
148
149                 rowProxy = Studio2.newRow(true);
150                 Studio2.setSpecial(rowProxy);
151                 var hanger = document.getElementById('rowproxy');
152                 hanger.parentNode.insertBefore(rowProxy,hanger.nextSibling);
153                 Studio2.activateElement(rowProxy);
154
155                 var hanger = document.getElementById('panelproxy');
156                 if (hanger != null) // if no panelproxy then don't display a new panel option: needed for portal layouts which have only one panel
157                 {
158                         panelProxy = Studio2.newPanel();
159                         Studio2.setSpecial(panelProxy);
160                         hanger.parentNode.insertBefore(panelProxy,hanger.nextSibling);
161                         Studio2.activateElement(panelProxy);
162                 }
163                 
164                 Studio2.resizeDivs();
165
166                 ModuleBuilder.helpRegisterByID('layoutEditor','div');
167                 ModuleBuilder.helpRegisterByID('layoutEditorButtons','input');
168                 ModuleBuilder.helpSetup('layoutEditor','default');
169
170         },
171         
172         resizeDivs : function () {
173                 var Dom = YAHOO.util.Dom;
174                 var body = document.getElementById('mbtabs');
175                 var targetHeight =  body.clientHeight - (Dom.getY('panels') - Dom.getY(body)) - 30;
176                 if (Studio2.isIE) targetHeight -= 10;
177                 Dom.setStyle('panels', "height", targetHeight + "px");
178                 Dom.setStyle('panels', "width" , ((Studio2.fieldwidth * 2) + 112) + "px");
179                 Dom.setStyle('toolbox', "height", targetHeight + "px");
180         },
181
182         /**
183         * SIGNATURE
184         *       array = Studio2.expandableFields
185         *       element = id of the element to unregister.
186         * RETURN
187         *       element is removed from Studio2.expandableFields if found.
188         */
189
190         unregisterExpandableField:function( field ){
191                 //_write_("received for unregister: "+field.id);
192                 if(field==null || typeof(field) == 'undefined'){ return; }
193                 if ( this.isExpandable(field) ) {
194                         if (this.getColumnWidth( field ) > 1) { this.reduceFieldWidth( field ); }
195                          _write_("Unregistered:"+field.id);
196                          field.removeChild( field.childNodes[1] );
197                          field.removeAttribute("expandable");
198                          field.removeAttribute("state");
199                 }
200         },
201         isExpandable:function( field ){
202                 return field.getAttribute("expandable")!=null && !this.isSpecial(field);//&& field.getAttribute("expandable") == "true";
203         },
204         swapStates:function( src, dest ){
205                 var old_src= {state:src.getAttribute("state"), img: src.childNodes[1].src};
206                 src.setAttribute("state", dest.getAttribute("state"));
207                 src.childNodes[1].src = dest.childNodes[1].src;
208                 dest.childNodes[1].src = old_src.img;
209                 dest.setAttribute("state", old_src.state);
210         },
211
212         getImageElement:function(default_toggle){
213                 var img = document.createElement('img');
214                 if(!default_toggle)
215                         img.src = 'index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=minus_inline.gif';
216                 else
217                         img.src = 'index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=plus_inline.gif';
218                 img.className = 'le_edit';
219                 img.style.paddingRight = 2;
220                 img.style.cssFloat = 'left';
221                 img.name = 'expandable_field_icon';
222                 return img;
223         },
224
225
226         toggleFieldWidth:function(id){
227
228                 var field = YAHOO.util.Dom.get(id);
229                 if ( typeof(field) == 'undefined' || field === null ) return; 
230                 var img = field.childNodes[1];
231
232                 if( field.getAttribute("state") && field.getAttribute("state")=='reduced' ){
233                         field.parentNode.removeChild( Studio2.nextField(field) || Studio2.prevField(field) );
234                         Studio2.setColumnWidth(id,2);
235                         img.src = 'index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=minus_inline.gif';
236                         this.setExpanded( field );
237
238
239                 }else if( field.getAttribute("state") && field.getAttribute("state")=='expanded' ){
240                         Studio2.setColumnWidth(id,1);
241                         var newField = Studio2.newField();
242                         Studio2.setSpecial(newField);
243                         Studio2.activateElement(newField);
244                         field.parentNode.appendChild(newField);
245                         this.setReduced( field );
246                         img.src='index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=plus_inline.gif';
247
248                 }
249         },
250         setExpanded: function( field ){
251                 field.setAttribute("expandable","true");
252                 field.setAttribute("state","expanded");
253                 _write_("Expanded: "+field.id);
254         },
255         setReduced: function( field ){
256                 field.setAttribute("expandable","true");
257                 field.setAttribute("state","reduced");
258                 _write_("Recued: "+field.id);
259         },
260         isExpanded: function (field ){
261                 return field.getAttribute('state') == 'expanded';
262         },
263         isReduced:function (field ){
264                 return field.getAttribute('state') == 'reduced';
265         },
266         registerExpandableField: function( field ) {//field = HTML element
267                 if( Studio2.maxColumns < 2 || field == null || typeof(field) == 'undefined' || this.isSpecial (field) ) { return; }
268                 if( !this.isExpandable( field ) )  {
269                         var next = this.nextField ( field ) ;
270                         var prev = this.prevField ( field ) ;
271                         var removeMe = next || prev ;
272                         if( this.isSpecial( next) || this.isSpecial( prev ) || this.isEmpty( next ) || this.isEmpty( prev ) || removeMe == null ){ //Always Expanded
273                                 _write_("remove me is :"+removeMe);
274                                 if (removeMe != null) { field.parentNode.removeChild(removeMe); }
275                                 var img = this.getImageElement ( false );
276                                 img.onclick = function () { Studio2.toggleFieldWidth ( field.id ) };
277                                 field.insertBefore ( img, field.childNodes[1] );
278                                 this.setColumnWidth( field.id, 2 );
279                                 this.setExpanded( field );
280                                 _write_("registered field");
281                         }
282                 }else{ _write_("Could not Register field:"+field.id); }
283         },
284         setStartId: function(id) {
285                 Studio2.idStack = [id];
286         },
287
288         nextId: function() {
289                 if (Studio2.idStack.length == 1) { // if down to our last id, allocate another
290                         Studio2.idStack[0]++;
291                         Studio2.idStack.push(Studio2.idStack[0]);
292                 }
293                 return Studio2.idStack.pop();
294         },
295
296         setNextId: function(id) {
297                 Studio2.idStack.push(id);
298         },
299
300         isSpecial: function(element) {
301                 if(element==null || typeof(element) == 'undefined'){return false;};
302                 return YAHOO.util.Dom.hasClass(element,'special');
303         },
304
305         setSpecial: function(el) {
306                 YAHOO.util.Dom.addClass(el, 'special');
307         },
308
309         unsetSpecial: function(el) {
310                 YAHOO.util.Dom.removeClass(el, 'special');
311         },
312         isEmpty: function( element ){
313                 if (element == null || typeof(element) == 'undefined') {return false;};
314                 return YAHOO.util.Dom.hasClass(element, 'le_field special');
315         },
316         count: function(element) {
317                 var count = 0;
318                 for (var j=0;j<element.childNodes.length;j++) {
319                         var child = element.childNodes[j];
320                         if (child.nodeName == 'DIV') { // a valid child
321                                 count++;
322                         }
323                 }
324                 return count;
325         },
326
327         newField: function(){ // TODO: use properties to set field contents
328                 //This object must exists on the page
329                 var newField = document.createElement('div');
330                 newField.className ='le_field';
331                 newField.id = Studio2.nextId();
332                 newField.innerHTML = '<span>'+SUGAR.language.get('ModuleBuilder', 'LBL_FILLER')+'</span>' + // the displayed label
333                                                          '<span class=\'field_name\'>(filler)</span>'; // the hidden field that identifies this as something to be saved by prepareForSave()
334                 return newField;
335         },
336
337         newRow: function(titleRequired) {
338                 var newRow = document.createElement('div');
339                 if (titleRequired) {
340                         var child = document.createElement('span');
341                 child.className = 'panel_name';
342                 child.appendChild(document.createTextNode(SUGAR.language.get('ModuleBuilder', 'LBL_NEW_ROW') ) );
343                 newRow.appendChild(child);
344                 }
345                 newRow.className='le_row';
346                 newRow.id = Studio2.nextId();
347                 for(var i=0;i<Studio2.maxColumns;i++) {
348                         var newField = Studio2.newField();
349                         Studio2.setSpecial(newField);
350                         newRow.appendChild(newField);
351                 }
352                 return newRow;
353         },
354
355         newPanel: function() {
356                 var newPanel = document.createElement('div');
357                 newPanel.className='le_panel';
358                 newPanel.id = Studio2.nextId();
359                 // get the panelid for this panel - must be unique in the layout, even across saves
360                 // our dynamically assigned DOM ids won't work as any panel given one of these DOM ids could find itself in conflict with a panel created in a later session
361                 //var panelIdentifier = 'lbl_panel'+(Studio2.panelNumber ++) ;
362                 var panelNumber = (Studio2.panelNumber ++) ;
363                 var view = document.getElementById('prepareForSave').view.value;
364                 var panelLabel = 'lbl_' + view +  '_panel' + panelNumber;
365
366                 var div = document.createElement('div');
367                 div.id = 'le_panellabel_' + newPanel.id;
368
369         var child = document.createElement('span');
370         child.id = 'le_panelname_' + newPanel.id;
371         child.className = 'panel_name';
372         child.appendChild(document.createTextNode(SUGAR.language.get('ModuleBuilder', 'LBL_NEW_PANEL') ) );
373         div.appendChild(child);
374         var child = document.createElement('span');
375         child.id = 'le_panelid_' + newPanel.id;
376         child.className = 'panel_id';
377         child.appendChild(document.createTextNode(panelLabel));
378                 div.appendChild(child);
379                 newPanel.appendChild(div);
380
381                 var img = document.createElement('img');
382                 img.src='index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=edit_inline.gif';
383                 img.className = 'le_edit';
384                 img.style.cursor="pointer;";
385                 var editModule = document.getElementById('prepareForSave').view_module.value;
386                 var editString = 'module=ModuleBuilder&action=editProperty&view_module='+editModule+'&view='+view+'&id_label=le_panelname_'+newPanel.id+'&name_label=label_'+panelLabel+'&title_label='+SUGAR.language.get('ModuleBuilder', 'LBL_LABEL_TITLE') ;
387                 if (document.getElementById('prepareForSave').view_package)
388                       editString += '&view_package='+document.getElementById('prepareForSave').view_package.value ;
389                 var view = document.prepareForSave.view.value;
390                 img.onclick = function() { var value_label = document.getElementById('le_panelname_'+newPanel.id).innerHTML;ModuleBuilder.asyncRequest( editString + '&value_label=' + value_label, ModuleBuilder.updateContent ); }
391                 newPanel.appendChild(img);
392                 return newPanel;
393         },
394
395         establishLocation: function(element) {
396                 var location = null;
397                 while(element.parentNode != 'body') {
398                         location = element.id;
399                         if ((location == 'panels') || (location == 'toolbox') || (location == 'delete')){
400                                 break;
401                         }
402                         element = element.parentNode;
403                 }
404                 if (location == null) {
405                         alert("Studio2:establishLocation: badly formed document");
406                         die();
407                 }
408                 return location;
409         },
410
411         reclaimIds: function(element) {
412                 // return the ids in this element to the available pool
413                 // do not reclaim field IDs as they never really disappear - they just move between toolbox and panel
414                 if (element.className.indexOf('le_field') == -1) {
415                         Studio2.setNextId(element.id);
416                         for (var i=0;i<element.childNodes.length;i++) {
417                                 var child = element.childNodes[i];
418                                 if (child.nodeName == 'DIV') { // a subelement
419                                         Studio2.reclaimIds(child);
420                                 }
421                         }
422                 }
423         },
424
425         reclaimFields: function(element) {
426                 if (element.className.indexOf('le_field') != -1) {
427                         if (! Studio2.isSpecial(element)) {
428                                 var destination = document.getElementById('availablefields');
429 //                              destination.appendChild(element.parentNode.removeChild(element));
430                                 destination.appendChild(element);
431                                 Studio2.resetFieldWidth(element);
432                         } else {
433                                 element.parentNode.removeChild(element);
434                         }
435                 } else {
436                         for (var i=0;i<element.childNodes.length;i++) {
437                                 var child = element.childNodes[i];
438                                 if (child.nodeName == 'DIV') { // a subelement
439                                         Studio2.reclaimFields(child);
440                                 }
441                         }
442                 }
443         },
444
445         highlightElement: function(field) {
446                 YAHOO.util.Dom.setStyle(field,'visibility','hidden');
447         },
448
449         /* FIELD WIDTH FUNCTIONS */
450
451         getSpacing: function(field) {
452                 var Field = new YAHOO.util.Element(field);
453                 var leftMargin = parseInt(Field.getStyle('margin-left'));
454                 var rightMargin = parseInt(Field.getStyle('margin-right'));
455                 var leftPadding = parseInt(Field.getStyle('padding-left'));
456                 var rightPadding = parseInt(Field.getStyle('padding-right'));
457                 if (Studio2.isIE) {
458                         return (leftMargin + rightMargin);
459                 } else {
460                         return (leftMargin + rightMargin + leftPadding + rightPadding + 2);
461                 }
462         },
463
464         resetFieldWidth: function(field) {
465                 YAHOO.util.Dom.setStyle(field,'width',Studio2.fieldwidth + 'px');
466                 //Dom.setStyle(field,'width',Studio2.fieldwidth + 'px' );
467         },
468
469         /* a hack function, purely because Firefox has a problem with field widths during the init function */
470         /* so rather than relying on the style values we just set the width directly to the final value */
471         adjustWidth: function(field,columns) {
472                 var newWidth = columns * (Studio2.fieldwidth + Studio2.getSpacing(field));
473                 YAHOO.util.Dom.setStyle(field,'width',newWidth + 'px' );
474         },
475
476         increaseFieldWidth: function(field) {
477                 var newWidth;
478 //              var currentWidth = parseInt(field.clientWidth);
479                 var currentWidth = Studio2.getFieldWidth(field);
480                 newWidth = currentWidth + Studio2.fieldwidth + Studio2.getSpacing(field);
481 //              field.style.width = newWidth+'px';
482                 YAHOO.util.Dom.setStyle(field,'width',newWidth + 'px' );
483         },
484
485         reduceFieldWidth: function(field) {
486                 var newWidth;
487                 var currentWidth = Studio2.getFieldWidth(field);
488                 newWidth = currentWidth - Studio2.fieldwidth - Studio2.getSpacing(field);
489                 YAHOO.util.Dom.setStyle(field,'width',newWidth + 'px' );
490         },
491
492         getFieldWidth: function(field) {
493                 var width = parseInt(YAHOO.util.Dom.getStyle(field, 'width')); // computed style value of the field width (or currentStyle in IE - same result)
494                 if (isNaN(width)) {
495                         width = Studio2.fieldwidth; // if field width is set to something like 'auto' we need to take a better guess
496                 }
497                 return width;
498         },
499
500         setFieldWidth: function(field,width) {
501                 YAHOO.util.Dom.setStyle(field,'width',width);
502         },
503
504         getColumnWidth: function(field) {
505                 return Math.floor(Studio2.getFieldWidth(field)/Studio2.fieldwidth);
506         },
507
508         setColumnWidth: function(field,columns) {
509                 var spacing = Studio2.getSpacing(field);
510                 var newWidth = columns * (Studio2.fieldwidth + spacing) - spacing;
511                 YAHOO.util.Dom.setStyle(field,'width',newWidth + 'px' );
512         },
513
514         firstField: function(row) {
515                 var firstfield = row.firstChild;
516                 while (firstfield.nodeName != 'DIV') {
517                         firstfield = firstfield.nextSibling;
518                 }
519                 return firstfield;
520         },
521
522         getColumn: function(field) {
523                 var firstfield = Studio2.firstField(field.parentNode);
524                 return Math.ceil((YAHOO.util.Dom.getX(field) - YAHOO.util.Dom.getX(firstfield) / Studio2.fieldwidth));  
525         },
526
527         getRow: function(field) {
528                 // find our parent row
529                 // find how many previous siblings we have that are also rows
530                 // our row is that + 1
531                 var row = field.parentNode;
532                 var count = 1;
533                 while ((row = row.previousSibling) !== null) {
534                         if (row.nodeName == 'DIV') {
535                                 count++;
536                         }
537                 }
538                 return count;
539         },
540
541         prevField: function(field){
542                 var prev = field.previousSibling;
543                 while( (null !== prev) && (prev.nodeName != 'DIV')){
544                         prev = prev.previousSibling;
545                 }
546                 return prev;
547         },
548         nextField: function(field) {
549                 var next = field.nextSibling;
550                 while (typeof(next)!='undefined' && (next !== null) && (next.nodeName != 'DIV')) {
551                         next = next.nextSibling;
552                 }
553                 return next;
554         },
555
556
557         /* ELEMENT FUNCTIONS */
558
559         // TODO: rewrite tidyPanels, tidyRows and tidyFields as a recursive tidy
560         tidyPanels: function() {
561                 var panels = document.getElementById('panels');
562                 if (Studio2.count(panels) <= 0) {
563                         var newPanel = Studio2.newPanel();
564                         newPanel.appendChild(Studio2.newRow(false));
565                         panels.appendChild(newPanel);
566                         Studio2.activateElement(newPanel);
567                 }
568         },
569
570         tidyRows: function(panel) {
571                 if (Studio2.count(panel) <= 0) { // no rows left
572                         if (Studio2.count(panel.parentNode)>1) {
573                                 Studio2.removeElement(panel);
574                                 Studio2.tidyPanels();
575                         } else {
576                                 // add a blank row back in
577                                 var newRow = Studio2.newRow(false);
578                                 panel.appendChild(newRow);
579                                 Studio2.activateElement(newRow);
580 //                              debugger;
581                         }
582                 }
583         },
584
585         tidyFields: function(row) {
586                 if (Studio2.count(row) <= 0) { // no fields left
587                         var panel = row.parentNode;
588                         Studio2.removeElement(row);
589                         Studio2.tidyRows(panel);
590                 }
591         },
592
593         removeElement: function(element) {
594                 Studio2.reclaimIds(element);
595                 Studio2.reclaimFields(element);
596                 if (element.className.indexOf('le_field') == -1) {
597                         // all fields have been moved to availablefields in Studio2.reclaimFields
598                         element.parentNode.removeChild(element);
599                 }
600         },
601
602         swapElements: function(el1,el2) {
603                 // TODO: record this swap in TRANSACTION
604                 var el1Width = Studio2.getFieldWidth(el1);
605                 var el2Width = Studio2.getFieldWidth(el2);
606                 YAHOO.util.DragDropMgr.swapNode(el1, el2);
607                 Studio2.setFieldWidth(el1,el2Width);
608                 Studio2.setFieldWidth(el2,el1Width);
609         },
610
611         activateElement: function(element) {
612                 if (!document.getElementById(element.id)) {
613                         document.body.appendChild(element);
614                 }
615                 if (element.className.indexOf('le_panel') != -1) {
616                         new Studio2.PanelDD(element.id,'studio2.panels');
617                         new YAHOO.util.DDTarget(element.id,'studio2.rows'); // add so a background for row moves
618                 }
619                 if (element.className.indexOf('le_row') != -1) {
620                         new Studio2.RowDD(element.id,'studio2.rows');
621                 }
622                 if (element.className.indexOf('le_field') != -1) {
623                         new Studio2.FieldDD(element,'studio2.fields');
624                 }
625                 for (var i=0;i<element.childNodes.length;i++) {
626                         var child = element.childNodes[i];
627                         if (child.nodeName == 'DIV') { // a valid child
628                                 Studio2.activateElement(child);
629                         }
630                 }
631
632         },
633
634         /**
635          * A substitute for cloneNode that is Yahoo Drag-and-Drop compatible.
636          * Using document.cloneNode causes Yahoo DnD to fail as the ID is also cloned, leading to duplicate IDs in the document
637          * This substitute doesn't copy the ID
638          */
639
640         copyElement: function(element) {
641                 var copy = document.createElement(element.tagName);
642                 if (element.attributes.length > 0) {
643                         var attrs = element.attributes;
644                         for(var i=0;i<attrs.length;i++) {
645                                 if (attrs[i].name != 'id') {
646                                         // check to see if this attribute is actually set in the document, or just a default - IE's attributes array contains both, and we only want the specified attributes
647                                         var a = element.getAttributeNode(attrs[i].name);
648                                         if (a && a.specified) {
649                                                 if (attrs[i].name == 'class') { // Needed for IE
650                                                         copy.className = attrs[i].value;
651                                                 }
652                                                 copy.setAttribute(attrs[i].name,attrs[i].value);
653                                         }
654                                 }
655                         }
656                 }
657
658                 Studio2.copyChildren(element, copy);
659                 copy.id = Studio2.nextId();
660                 return copy;
661         },
662         
663         copyChildren : function(original, clone)
664         {
665                 var children = original.childNodes
666                 for (var i in children)
667                 {
668                         if (children[i])
669                         {
670                                 if (children[i].tagName && children[i].tagName.substr(0,1) != "#"){
671                                         clone.appendChild(Studio2.copyElement(children[i]));
672                                 }
673                                 else if (children[i].nodeName && children[i].nodeName == "#text")
674                                 {
675                                         clone.innerHTML += children[i].data;
676                                 }
677                         }
678                 }
679         },
680
681         setCopy: function(copy) {
682                 Studio2.copyId = copy.id;
683         },
684
685         copy: function() {
686                 if (Studio2.copyId != null) {
687                         return document.getElementById(Studio2.copyId);
688                 } else {
689                         return false;
690                 }
691         },
692
693         activateCopy:   function() {
694                 Studio2.activateElement(document.getElementById(Studio2.copyId));
695         },
696
697         removeCopy:      function() {
698                 if (Studio2.copyId != null) {
699                         Studio2.removeElement(Studio2.copy());
700                 }
701                 Studio2.copyId = null;
702         },
703
704         // Copy all the slot content across to a temporary form table for submitting to the backend for the save
705         // We could have made all the slots be hidden fields within a form, (ala the original Portal editor), but then we'd have to do a lot of work during
706         // editing that really only needs to be done once per save
707
708         prepareForSave: function() {
709                 // create a new saveForm
710                 var panels = document.getElementById('panels');
711                 var saveForm = document.getElementById('prepareForSave');
712                 if (! saveForm) {
713                         saveForm = document.createElement('form');
714                         saveForm.id = 'prepareForSave';
715                         YAHOO.util.Dom.setStyle(saveForm,"visibility", "hidden");
716                         panels.parentNode.appendChild(saveForm);
717                 }
718                 // remove any existing slot information, but importantly, preserve any non-slot stuff needed for form submittal
719                 var length = saveForm.childNodes.length;
720                 var index = 0;
721                 for( var i=0; i<length; i++) {
722                         if (saveForm.childNodes[index].nodeName != 'INPUT') {
723                                 index++;
724                         } else {
725                                 if (saveForm.childNodes[index].getAttribute('name').substr(0,4) == "slot") {
726                                         saveForm.removeChild(saveForm.childNodes[index]);
727                                 } else {
728                                         index++;
729                                 }
730                         }
731                 }
732
733                 //      convert to input name='slot-{panel}-{slot}-{type}' value={value}
734                 var panelid = 0;
735                 var panels = document.getElementById('panels');
736
737                 for( var i=0;i<panels.childNodes.length;i++) {
738                         var panel = panels.childNodes[i];
739
740                         if (panel.nodeName == 'DIV') { // a panel
741                                 panelid++;
742                                 var fieldid = -1;
743
744                                 for (var j=0;j<panel.childNodes.length;j++) {
745                                         var row = panel.childNodes[j];
746
747                                         // save the panel name and label
748                                         if (row.id && row.id.indexOf('le_panellabel') != -1) {
749                                                 // a panel label
750                                                 var inputField = document.createElement('input');
751                                                 inputField.setAttribute('type','hidden');
752                                                 inputField.setAttribute('name','panel-'+panelid+'-name');
753                         inputField.setAttribute('value',document.getElementById('le_panelname_'+row.id.substr(14,row.id.length)).innerHTML);
754                                                 saveForm.appendChild(inputField);
755                                                 var inputField = document.createElement('input');
756                                                 inputField.setAttribute('type','hidden');
757                         inputField.setAttribute('name','panel-'+panelid+'-label');
758                         inputField.setAttribute('value',document.getElementById('le_panelid_'+row.id.substr(14,row.id.length)).innerHTML);
759                         saveForm.appendChild(inputField);
760                                         }
761
762                                         // now for the rows
763                                         if (row.nodeName == 'DIV') { // a row
764                                                 for (var k=0;k<row.childNodes.length;k++) {
765                                                         var field = row.childNodes[k];
766
767
768                                                         if (field.nodeName == 'DIV') { // a field
769                                                                 fieldid++;
770                                                                 for ( var l=0; l < field.childNodes.length; l++ ) {
771                                                                         var property = field.childNodes[l];
772
773                                                                         if (property.nodeName == 'SPAN') { // a property of a field
774                                                                                 if (property.attributes.length > 0) {
775 //                                                                              if (property.hasAttributes) {
776                                                                                         var type = property.className;
777                                                                                         if ((type.length>5) && (type.substr(0,5) == 'field') && (property.childNodes.length != 0)) {
778                                                                                                 var value = property.firstChild.nodeValue;
779                                                                                                 var inputField = document.createElement('input');
780                                                                                                 inputField.setAttribute('type','hidden');
781                                                                                                 inputField.setAttribute('name','slot-'+panelid+'-'+fieldid+'-'+type.substr(6,type.length));
782                                                                                                 inputField.setAttribute('value',value);
783                                                                                                 saveForm.appendChild(inputField);
784                                                                                         }
785                                                                                 }
786                                                                         }
787                                                                 }
788                                                                 // check fieldwidth in the layout; if more than one, then add an (empty) for each (so the parser can keep track of the slots)
789                                                                 var endId = fieldid+Studio2.getColumnWidth(field)-1;
790                                                                 while (fieldid<endId) {
791                                                                         fieldid++;
792                                                                         var inputField = document.createElement('input');
793                                                                         inputField.setAttribute('type','hidden');
794                                                                         inputField.setAttribute('name','slot-'+panelid+'-'+fieldid+'-name');
795                                                                         inputField.setAttribute('value','(empty)');
796                                                                         saveForm.appendChild(inputField);
797
798                                                                 }
799
800                                                         }
801                                                 }
802                                         }
803                                 }
804                         }
805                 }
806         },
807
808         handleSave: function() {
809                 ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVING'));
810                 ModuleBuilder.state.isDirty=false;
811                 this.prepareForSave();
812                 // set <input type='hidden' name='action' value='saveLayout'>
813                 var saveForm = document.forms['prepareForSave'];
814                 var inputField = document.createElement('input');
815                 inputField.setAttribute('type','hidden');
816                 inputField.setAttribute('name','action');
817                 inputField.setAttribute('value','saveLayout');
818                 saveForm.appendChild(inputField);
819                 ModuleBuilder.submitForm('prepareForSave');
820                 ajaxStatus.flashStatus('Save complete',5000);
821         },
822
823         handlePublish: function() {
824                 ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVING'));
825                 ModuleBuilder.state.isDirty=false;
826                 this.prepareForSave();
827                 // set <input type='hidden' name='action' value='saveAndPublishLayout'>
828                 var saveForm = document.forms['prepareForSave'];
829                 var inputField = document.createElement('input');
830                 inputField.setAttribute('type','hidden');
831                 inputField.setAttribute('name','action');
832                 inputField.setAttribute('value','saveAndPublishLayout');
833                 saveForm.appendChild(inputField);
834                 ModuleBuilder.submitForm('prepareForSave');
835                 ajaxStatus.flashStatus(SUGAR.language.get('ModuleBuilder','LBL_DEPLOYE_COMPLETE'),5000);
836         },
837         
838         checkGridLayout : function(view)
839         {
840             if (Studio2.countGridFields() == 0) {
841                    ModuleBuilder.layoutValidation.popup() ;
842                    return false;
843                 }
844                 if (view == "detailview")       
845                         return true;  
846                 
847             return Studio2.checkRequiredFields();
848         },
849
850         countGridFields : function() {
851             var count = 0;
852             var divs = document.getElementById( 'panels' ).getElementsByTagName( 'div' ) ;
853             for ( var j=0;j<divs.length;j++) {
854                 if (divs[j].className == 'le_field')
855                             count++;
856             }
857             return count;
858         },  
859
860     checkRequiredFields : function(){
861                 var Dom = YAHOO.util.Dom;
862                 var availablefields = Dom.get('availablefields');
863                 var fields = Dom.getElementsByClassName('field_name', '', 'availablefields');
864                 var missing = [ ];
865                 for(field in fields){
866                     if (Studio2.requiredFields.indexOf(fields[field].innerHTML) != -1) {
867                                 missing[missing.length] = fields[field].innerHTML;
868                         }
869                 }
870                 if (missing.length > 0) 
871                 {
872                     var msg = SUGAR.language.get("ModuleBuilder", "ERROR_REQUIRED_FIELDS");
873                         for (var i = 0; i < missing.length; i++) {
874                           msg += '"' + missing[i] + '"';
875                           if (i != missing.length - 1)
876                               msg += ",";
877                         }
878                 return window.confirm(msg);
879                 }
880                                 
881             return true;
882         },
883         
884         checkCalcFields: function(view, error) {
885                 if (view == "DetailView")
886            return true;
887                 
888                 var Dom = YAHOO.util.Dom;
889             var panels = Dom.get('panels');
890             var fields = Dom.getElementsByClassName('field_name', 'span', 'panels');
891             var cfs = [ ];
892             for(i in fields){
893                 if (Studio2.calcFieldList.indexOf(fields[i].innerHTML) != -1) {
894                     cfs.push(fields[i].innerHTML);
895                 }
896             }
897             if (cfs.length > 0) 
898             {
899                 var msg = SUGAR.language.get("ModuleBuilder", error) + "\n";
900                 for (var i = 0; i < cfs.length; i++) {
901                   msg += '"' + cfs[i] + '"';
902                   if (i != cfs.length - 1)
903                       msg += ",";
904                 }
905                 return window.confirm(msg);
906             }
907             return true;
908                 
909         }
910
911
912 };
913
914