1 /*********************************************************************************
2 * SugarCRM Community Edition is a customer relationship management program developed by
3 * SugarCRM, Inc. Copyright (C) 2004-2013 SugarCRM Inc.
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.
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
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
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.
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.
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 ********************************************************************************/
37 if(typeof('console') == 'undefined'){
39 log: function(message) {
45 var _write_ = function( message ){ if(_debug_){ console.log(message);} }
52 var Dom = YAHOO.util.Dom,
53 DDTarget = YAHOO.util.DDTarget,
54 DDM = YAHOO.utilDragDropMgr;
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 Studio2.scrollZones = {};
65 // Activate the layout panels
66 var panels = document.getElementById('panels');
67 Dom.setStyle(panels, "visibility", "hidden");
68 //new Studio2.PanelDD(panels.id,'studio2.panels'); // add the main layout area into PANELS to allow for panel drags to empty areas
69 new DDTarget(panels.id, 'studio2.panels');
70 for (var i=0;i<panels.childNodes.length;i++) {
71 var panel = panels.childNodes[i];
72 if (panel.nodeName == 'DIV') { // a valid panel
74 // add the panel into the ROWS drag-and-drop group to allow for drags to empty areas of the panels
75 new DDTarget(panel.id,'studio2.rows');
77 for (var j=0;j<panel.childNodes.length;j++) {
78 var row = panel.childNodes[j];
79 if(typeof(row.id)!='undefined' && row.id!=null)
81 if (row.nodeName == 'DIV' && row.className == 'le_row' ) { // a valid row
83 // Convert all (empty) fields into variable width fields
84 var leftSibling = null;
87 for (var k=0;k<row.childNodes.length;k++) {
88 var field = row.childNodes[k];
90 if (field.nodeName == 'DIV') { // field
92 for (var l=0;l<field.childNodes.length;l++) {
93 var property = field.childNodes[l];
95 if (property.className && (property.className.indexOf('field_name') != -1) && property.firstChild) {
96 if (property.firstChild.nodeValue.indexOf('(empty)') != -1) {
97 //register field to be expandable
98 _write_("(empty) found");
99 Studio2.setSpecial(field);
100 Studio2.registerExpandableField( Studio2.prevField(field) || Studio2.nextField( field ) );
102 }else if (property.firstChild.nodeValue.indexOf('(filler)') != -1){
103 var sibling = Studio2.prevField( field ) || Studio2.nextField( field );
104 Studio2.setSpecial( field );
105 var swapFields = Studio2.nextField( field ) != null;
106 Studio2.registerExpandableField( sibling);
107 this.toggleFieldWidth (sibling );
110 //swap (filler) with the sibling
111 field = Studio2.nextField (sibling ) || Studio2.prevField( sibling );
113 this.swapElements( sibling , field)
122 if( ranOnce ){break;}
125 Studio2.activateElement(row);
130 Studio2.activateElement(panels);
131 Dom.setStyle(panels, "visibility", '');
133 // Activate the fields in the availablefields list
134 var availablefields = document.getElementById('availablefields');
135 Studio2.activateElement(availablefields);
137 // Setup Delete area in the toolbox (the Trash icon)
138 var d = document.getElementById('delete');
139 Studio2.setSpecial(d);
140 var delDD = new DDTarget('delete', 'studio2.panels');
141 delDD.addToGroup('studio2.rows');
142 delDD.addToGroup('studio2.fields');
144 var fillerProxy = Studio2.newField();
145 Studio2.setSpecial(fillerProxy);
146 var hanger = document.getElementById('fillerproxy');
147 hanger.parentNode.insertBefore(fillerProxy,hanger.nextSibling);
148 Studio2.activateElement(fillerProxy);
150 rowProxy = Studio2.newRow(true);
151 Studio2.setSpecial(rowProxy);
152 var hanger = document.getElementById('rowproxy');
153 hanger.parentNode.insertBefore(rowProxy,hanger.nextSibling);
154 Studio2.activateElement(rowProxy);
156 var hanger = document.getElementById('panelproxy');
157 if (hanger != null) // if no panelproxy then don't display a new panel option: needed for portal layouts which have only one panel
159 panelProxy = Studio2.newPanel();
160 Studio2.setSpecial(panelProxy);
161 hanger.parentNode.insertBefore(panelProxy,hanger.nextSibling);
162 Studio2.activateElement(panelProxy);
165 Studio2.resizeDivs();
167 ModuleBuilder.helpRegisterByID('layoutEditor','div');
168 ModuleBuilder.helpRegisterByID('layoutEditorButtons','input');
169 ModuleBuilder.helpSetup('layoutEditor','default');
171 var elem = document.getElementById('prepareForSave').elements;
175 for (var i = 0; i < elem.length; i++) {
176 if (elem[i].name.match(/^tabDefs_.*_newTab$/)) {
177 if (elem[i].value == '1' && elem[i].name != 'tabDefs_' + Studio2.firstPanelId + '_newTab')
181 if (has_tab == true) {
182 document.getElementById('le_paneltype_select_' + Studio2.firstPanelIdCount).disabled = true;
187 resizeDivs : function () {
188 var Dom = YAHOO.util.Dom;
189 if (!Dom.get('panels'))
191 var body = document.getElementById('mbtabs');
192 var targetHeight = body.clientHeight - (Dom.getY('panels') - Dom.getY(body)) - 32;
193 if (Studio2.isIE) targetHeight -= 10;
194 Dom.setStyle('panels', "height", targetHeight + "px");
195 Dom.setStyle('panels', "width" , ((Studio2.fieldwidth * 2) + 112) + "px");
196 Dom.setStyle('toolbox', "height", targetHeight + "px");
197 Studio2.scrollZones = {
198 panels: Studio2.getScrollZones('panels'),
199 toolbox: Studio2.getScrollZones('toolbox')
205 * array = Studio2.expandableFields
206 * element = id of the element to unregister.
208 * element is removed from Studio2.expandableFields if found.
211 unregisterExpandableField:function( field ){
212 //_write_("received for unregister: "+field.id);
213 if(field==null || typeof(field) == 'undefined'){ return; }
214 if ( this.isExpandable(field) ) {
215 if (this.getColumnWidth( field ) > 1) { this.reduceFieldWidth( field ); }
216 _write_("Unregistered:"+field.id);
217 field.removeChild( field.childNodes[1] );
218 field.removeAttribute("expandable");
219 field.removeAttribute("state");
222 isExpandable:function( field ){
223 return field.getAttribute("expandable")!=null && !this.isSpecial(field);//&& field.getAttribute("expandable") == "true";
225 swapStates:function( src, dest ){
226 var old_src= {state:src.getAttribute("state"), img: src.childNodes[1].src};
227 src.setAttribute("state", dest.getAttribute("state"));
228 src.childNodes[1].src = dest.childNodes[1].src;
229 dest.childNodes[1].src = old_src.img;
230 dest.setAttribute("state", old_src.state);
233 getImageElement:function(default_toggle){
234 var img = document.createElement('img');
236 img.src = 'index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=minus_inline.gif';
238 img.src = 'index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=plus_inline.gif';
239 img.className = 'le_edit';
240 img.style.paddingRight = 2;
241 img.style.cssFloat = 'left';
242 img.name = 'expandable_field_icon';
247 toggleFieldWidth:function(id){
249 var field = YAHOO.util.Dom.get(id);
250 if ( typeof(field) == 'undefined' || field === null ) return;
251 var img = field.childNodes[1];
253 if( field.getAttribute("state") && field.getAttribute("state")=='reduced' ){
254 field.parentNode.removeChild( Studio2.nextField(field) || Studio2.prevField(field) );
255 Studio2.setColumnWidth(id,2);
256 img.src = 'index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=minus_inline.gif';
257 this.setExpanded( field );
260 }else if( field.getAttribute("state") && field.getAttribute("state")=='expanded' ){
261 Studio2.setColumnWidth(id,1);
262 var newField = Studio2.newField();
263 Studio2.setSpecial(newField);
264 Studio2.activateElement(newField);
265 field.parentNode.appendChild(newField);
266 this.setReduced( field );
267 img.src='index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=plus_inline.gif';
271 setExpanded: function( field ){
272 field.setAttribute("expandable","true");
273 field.setAttribute("state","expanded");
274 _write_("Expanded: "+field.id);
276 setReduced: function( field ){
277 field.setAttribute("expandable","true");
278 field.setAttribute("state","reduced");
279 _write_("Recued: "+field.id);
281 isExpanded: function (field ){
282 return field.getAttribute('state') == 'expanded';
284 isReduced:function (field ){
285 return field.getAttribute('state') == 'reduced';
287 registerExpandableField: function( field ) {//field = HTML element
288 if( Studio2.maxColumns < 2 || field == null || typeof(field) == 'undefined' || this.isSpecial (field) ) { return; }
289 if( !this.isExpandable( field ) ) {
290 var next = this.nextField ( field ) ;
291 var prev = this.prevField ( field ) ;
292 var removeMe = next || prev ;
293 if( this.isSpecial( next) || this.isSpecial( prev ) || this.isEmpty( next ) || this.isEmpty( prev ) || removeMe == null ){ //Always Expanded
294 _write_("remove me is :"+removeMe);
295 if (removeMe != null) { field.parentNode.removeChild(removeMe); }
296 var img = this.getImageElement ( false );
297 img.onclick = function () { Studio2.toggleFieldWidth ( field.id ) };
298 field.insertBefore ( img, field.childNodes[1] );
299 this.setColumnWidth( field.id, 2 );
300 this.setExpanded( field );
301 _write_("registered field");
303 }else{ _write_("Could not Register field:"+field.id); }
305 setStartId: function(id) {
306 Studio2.idStack = [id];
310 if (Studio2.idStack.length == 1) { // if down to our last id, allocate another
311 Studio2.idStack[0]++;
312 Studio2.idStack.push(Studio2.idStack[0]);
314 return Studio2.idStack.pop();
317 setNextId: function(id) {
318 Studio2.idStack.push(id);
321 isSpecial: function(element) {
322 if(element==null || typeof(element) == 'undefined'){return false;};
323 return YAHOO.util.Dom.hasClass(element,'special');
326 setSpecial: function(el) {
327 YAHOO.util.Dom.addClass(el, 'special');
330 unsetSpecial: function(el) {
331 YAHOO.util.Dom.removeClass(el, 'special');
333 isEmpty: function( element ){
334 if (element == null || typeof(element) == 'undefined') {return false;};
335 return YAHOO.util.Dom.hasClass(element, 'le_field special');
337 count: function(element) {
339 for (var j=0;j<element.childNodes.length;j++) {
340 var child = element.childNodes[j];
341 if (child.nodeName == 'DIV') { // a valid child
348 newField: function(){ // TODO: use properties to set field contents
349 //This object must exists on the page
350 var newField = document.createElement('div');
351 newField.className ='le_field';
352 newField.id = Studio2.nextId();
353 newField.innerHTML = '<span>'+SUGAR.language.get('ModuleBuilder', 'LBL_FILLER')+'</span>' + // the displayed label
354 '<span class=\'field_name\'>(filler)</span>'; // the hidden field that identifies this as something to be saved by prepareForSave()
358 newRow: function(titleRequired) {
359 var newRow = document.createElement('div');
361 var child = document.createElement('span');
362 child.className = 'panel_name';
363 child.appendChild(document.createTextNode(SUGAR.language.get('ModuleBuilder', 'LBL_NEW_ROW') ) );
364 newRow.appendChild(child);
366 newRow.className='le_row';
367 newRow.id = Studio2.nextId();
368 for(var i=0;i<Studio2.maxColumns;i++) {
369 var newField = Studio2.newField();
370 Studio2.setSpecial(newField);
371 newRow.appendChild(newField);
376 newPanel: function() {
377 var newPanel = document.createElement('div');
378 newPanel.className='le_panel';
379 newPanel.id = Studio2.nextId();
380 // get the panelid for this panel - must be unique in the layout, even across saves
381 // 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
382 //var panelIdentifier = 'lbl_panel'+(Studio2.panelNumber ++) ;
383 var panelNumber = (Studio2.panelNumber ++) ;
384 var view = document.getElementById('prepareForSave').view.value;
385 var panelLabel = 'lbl_' + view + '_panel' + panelNumber;
387 var div = document.createElement('div');
388 div.id = 'le_panellabel_' + newPanel.id;
390 var child = document.createElement('span');
391 child.id = 'le_panelname_' + newPanel.id;
392 child.className = 'panel_name';
393 child.appendChild(document.createTextNode(SUGAR.language.get('ModuleBuilder', 'LBL_NEW_PANEL') ) );
394 div.appendChild(child);
395 var child = document.createElement('span');
396 child.id = 'le_panelid_' + newPanel.id;
397 child.className = 'panel_id';
398 child.appendChild(document.createTextNode(panelLabel));
399 div.appendChild(child);
400 newPanel.appendChild(div);
402 var img = document.createElement('img');
403 img.src='index.php?entryPoint=getImage&themeName='+SUGAR.themes.theme_name+'&imageName=edit_inline.gif';
404 img.className = 'le_edit';
405 img.style.cursor="pointer;";
406 var editModule = document.getElementById('prepareForSave').view_module.value;
407 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') ;
408 if (document.getElementById('prepareForSave').view_package)
409 editString += '&view_package='+document.getElementById('prepareForSave').view_package.value ;
410 var view = document.prepareForSave.view.value;
411 img.onclick = function() { var value_label = document.getElementById('le_panelname_'+newPanel.id).innerHTML;ModuleBuilder.asyncRequest( editString + '&value_label=' + value_label, ModuleBuilder.updateContent ); }
412 newPanel.appendChild(img);
416 establishLocation: function(element) {
418 while(element.parentNode != 'body') {
419 location = element.id;
420 if ((location == 'panels') || (location == 'toolbox') || (location == 'delete')){
423 element = element.parentNode;
425 if (location == null) {
426 alert("Studio2:establishLocation: badly formed document");
432 reclaimIds: function(element) {
433 // return the ids in this element to the available pool
434 // do not reclaim field IDs as they never really disappear - they just move between toolbox and panel
435 if (element.className.indexOf('le_field') == -1) {
436 Studio2.setNextId(element.id);
437 for (var i=0;i<element.childNodes.length;i++) {
438 var child = element.childNodes[i];
439 if (child.nodeName == 'DIV') { // a subelement
440 Studio2.reclaimIds(child);
446 reclaimFields: function(element) {
447 if (element.className.indexOf('le_field') != -1) {
448 if (! Studio2.isSpecial(element)) {
449 var destination = document.getElementById('availablefields');
450 // destination.appendChild(element.parentNode.removeChild(element));
451 destination.appendChild(element);
452 Studio2.resetFieldWidth(element);
454 element.parentNode.removeChild(element);
457 for (var i=0;i<element.childNodes.length;i++) {
458 var child = element.childNodes[i];
459 if (child.nodeName == 'DIV') { // a subelement
460 Studio2.reclaimFields(child);
466 highlightElement: function(field) {
467 YAHOO.util.Dom.setStyle(field,'visibility','hidden');
470 /* FIELD WIDTH FUNCTIONS */
472 getSpacing: function(field) {
473 var Field = new YAHOO.util.Element(field);
474 var leftMargin = parseInt(Field.getStyle('margin-left'));
475 var rightMargin = parseInt(Field.getStyle('margin-right'));
476 var leftPadding = parseInt(Field.getStyle('padding-left'));
477 var rightPadding = parseInt(Field.getStyle('padding-right'));
479 return (leftMargin + rightMargin);
481 return (leftMargin + rightMargin + leftPadding + rightPadding + 2);
485 resetFieldWidth: function(field) {
486 YAHOO.util.Dom.setStyle(field,'width',Studio2.fieldwidth + 'px');
487 //Dom.setStyle(field,'width',Studio2.fieldwidth + 'px' );
490 /* a hack function, purely because Firefox has a problem with field widths during the init function */
491 /* so rather than relying on the style values we just set the width directly to the final value */
492 adjustWidth: function(field,columns) {
493 var newWidth = columns * (Studio2.fieldwidth + Studio2.getSpacing(field));
494 YAHOO.util.Dom.setStyle(field,'width',newWidth + 'px' );
497 increaseFieldWidth: function(field) {
499 // var currentWidth = parseInt(field.clientWidth);
500 var currentWidth = Studio2.getFieldWidth(field);
501 newWidth = currentWidth + Studio2.fieldwidth + Studio2.getSpacing(field);
502 // field.style.width = newWidth+'px';
503 YAHOO.util.Dom.setStyle(field,'width',newWidth + 'px' );
506 reduceFieldWidth: function(field) {
508 var currentWidth = Studio2.getFieldWidth(field);
509 newWidth = currentWidth - Studio2.fieldwidth - Studio2.getSpacing(field);
510 YAHOO.util.Dom.setStyle(field,'width',newWidth + 'px' );
513 getFieldWidth: function(field) {
514 var width = parseInt(YAHOO.util.Dom.getStyle(field, 'width')); // computed style value of the field width (or currentStyle in IE - same result)
516 width = Studio2.fieldwidth; // if field width is set to something like 'auto' we need to take a better guess
521 setFieldWidth: function(field,width) {
522 YAHOO.util.Dom.setStyle(field,'width',width);
525 getColumnWidth: function(field) {
526 return Math.floor(Studio2.getFieldWidth(field)/Studio2.fieldwidth);
529 setColumnWidth: function(field,columns) {
530 var spacing = Studio2.getSpacing(field);
531 var newWidth = columns * (Studio2.fieldwidth + spacing) - spacing;
532 YAHOO.util.Dom.setStyle(field,'width',newWidth + 'px' );
535 firstField: function(row) {
536 var firstfield = row.firstChild;
537 while (firstfield.nodeName != 'DIV') {
538 firstfield = firstfield.nextSibling;
543 getColumn: function(field) {
544 var firstfield = Studio2.firstField(field.parentNode);
545 return Math.ceil((YAHOO.util.Dom.getX(field) - YAHOO.util.Dom.getX(firstfield) / Studio2.fieldwidth));
548 getRow: function(field) {
549 // find our parent row
550 // find how many previous siblings we have that are also rows
551 // our row is that + 1
552 var row = field.parentNode;
554 while ((row = row.previousSibling) !== null) {
555 if (row.nodeName == 'DIV') {
562 prevField: function(field){
563 var prev = field.previousSibling;
564 while( (null !== prev) && (prev.nodeName != 'DIV')){
565 prev = prev.previousSibling;
569 nextField: function(field) {
570 var next = field.nextSibling;
571 while (typeof(next)!='undefined' && (next !== null) && (next.nodeName != 'DIV')) {
572 next = next.nextSibling;
578 /* ELEMENT FUNCTIONS */
580 // TODO: rewrite tidyPanels, tidyRows and tidyFields as a recursive tidy
581 tidyPanels: function() {
582 var panels = document.getElementById('panels');
583 if (Studio2.count(panels) <= 0) {
584 var newPanel = Studio2.newPanel();
585 newPanel.appendChild(Studio2.newRow(false));
586 panels.appendChild(newPanel);
587 Studio2.activateElement(newPanel);
591 tidyRows: function(panel) {
592 if (Studio2.count(panel) <= 0) { // no rows left
593 if (Studio2.count(panel.parentNode)>1) {
594 Studio2.removeElement(panel);
595 Studio2.tidyPanels();
597 // add a blank row back in
598 var newRow = Studio2.newRow(false);
599 panel.appendChild(newRow);
600 Studio2.activateElement(newRow);
606 tidyFields: function(row) {
607 if (Studio2.count(row) <= 0) { // no fields left
608 var panel = row.parentNode;
609 Studio2.removeElement(row);
610 Studio2.tidyRows(panel);
614 removeElement: function(element) {
615 Studio2.reclaimIds(element);
616 Studio2.reclaimFields(element);
617 if (element.className.indexOf('le_field') == -1) {
618 // all fields have been moved to availablefields in Studio2.reclaimFields
619 element.parentNode.removeChild(element);
623 swapElements: function(el1,el2) {
624 // TODO: record this swap in TRANSACTION
625 var el1Width = Studio2.getFieldWidth(el1);
626 var el2Width = Studio2.getFieldWidth(el2);
627 YAHOO.util.DragDropMgr.swapNode(el1, el2);
628 Studio2.setFieldWidth(el1,el2Width);
629 Studio2.setFieldWidth(el2,el1Width);
632 activateElement: function(element) {
633 if (!document.getElementById(element.id)) {
634 document.body.appendChild(element);
636 if (element.className.indexOf('le_panel') != -1) {
637 new Studio2.PanelDD(element.id,'studio2.panels');
638 new YAHOO.util.DDTarget(element.id,'studio2.rows'); // add so a background for row moves
640 if (element.className.indexOf('le_row') != -1) {
641 new Studio2.RowDD(element.id,'studio2.rows');
643 if (element.className.indexOf('le_field') != -1) {
644 new Studio2.FieldDD(element,'studio2.fields');
646 for (var i=0;i<element.childNodes.length;i++) {
647 var child = element.childNodes[i];
648 if (child.nodeName == 'DIV') { // a valid child
649 Studio2.activateElement(child);
656 * A substitute for cloneNode that is Yahoo Drag-and-Drop compatible.
657 * Using document.cloneNode causes Yahoo DnD to fail as the ID is also cloned, leading to duplicate IDs in the document
658 * This substitute doesn't copy the ID
661 copyElement: function(element) {
662 var copy = document.createElement(element.tagName);
663 if (element.attributes.length > 0) {
664 var attrs = element.attributes;
665 for(var i=0;i<attrs.length;i++) {
666 if (attrs[i].name != 'id') {
667 // 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
668 var a = element.getAttributeNode(attrs[i].name);
669 if (a && a.specified) {
670 if (attrs[i].name == 'class') { // Needed for IE
671 copy.className = attrs[i].value;
673 copy.setAttribute(attrs[i].name,attrs[i].value);
679 Studio2.copyChildren(element, copy);
680 copy.id = Studio2.nextId();
684 copyChildren : function(original, clone)
686 var children = original.childNodes
687 for (var i in children)
691 if (children[i].tagName && children[i].tagName.substr(0,1) != "#"){
692 clone.appendChild(Studio2.copyElement(children[i]));
694 else if (children[i].nodeName && children[i].nodeName == "#text")
696 clone.innerHTML += children[i].data;
702 setCopy: function(copy) {
703 Studio2.copyId = copy.id;
707 if (Studio2.copyId != null) {
708 return document.getElementById(Studio2.copyId);
714 activateCopy: function() {
715 Studio2.activateElement(document.getElementById(Studio2.copyId));
718 removeCopy: function() {
719 if (Studio2.copyId != null) {
720 Studio2.removeElement(Studio2.copy());
722 Studio2.copyId = null;
725 // Copy all the slot content across to a temporary form table for submitting to the backend for the save
726 // 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
727 // editing that really only needs to be done once per save
729 prepareForSave: function() {
730 // create a new saveForm
731 var panels = document.getElementById('panels');
732 var saveForm = document.getElementById('prepareForSave');
734 saveForm = document.createElement('form');
735 saveForm.id = 'prepareForSave';
736 YAHOO.util.Dom.setStyle(saveForm,"visibility", "hidden");
737 panels.parentNode.appendChild(saveForm);
739 // remove any existing slot information, but importantly, preserve any non-slot stuff needed for form submittal
740 var length = saveForm.childNodes.length;
742 for( var i=0; i<length; i++) {
743 if (saveForm.childNodes[index].nodeName != 'INPUT') {
746 if (saveForm.childNodes[index].getAttribute('name').substr(0,4) == "slot") {
747 saveForm.removeChild(saveForm.childNodes[index]);
754 // convert to input name='slot-{panel}-{slot}-{type}' value={value}
756 var panels = document.getElementById('panels');
758 for( var i=0;i<panels.childNodes.length;i++) {
759 var panel = panels.childNodes[i];
761 if (panel.nodeName == 'DIV') { // a panel
765 for (var j=0;j<panel.childNodes.length;j++) {
766 var row = panel.childNodes[j];
768 // save the panel name and label
769 if (row.id && row.id.indexOf('le_panellabel') != -1) {
771 var inputField = document.createElement('input');
772 inputField.setAttribute('type','hidden');
773 inputField.setAttribute('name','panel-'+panelid+'-name');
774 inputField.setAttribute('value',document.getElementById('le_panelname_'+row.id.substr(14,row.id.length)).innerHTML);
775 saveForm.appendChild(inputField);
776 var inputField = document.createElement('input');
777 inputField.setAttribute('type','hidden');
778 inputField.setAttribute('name','panel-'+panelid+'-label');
779 inputField.setAttribute('value',document.getElementById('le_panelid_'+row.id.substr(14,row.id.length)).innerHTML);
780 saveForm.appendChild(inputField);
784 if (row.nodeName == 'DIV') { // a row
785 for (var k=0;k<row.childNodes.length;k++) {
786 var field = row.childNodes[k];
789 if (field.nodeName == 'DIV') { // a field
791 for ( var l=0; l < field.childNodes.length; l++ ) {
792 var property = field.childNodes[l];
794 if (property.nodeName == 'SPAN') { // a property of a field
795 if (property.attributes.length > 0) {
796 // if (property.hasAttributes) {
797 var type = property.className;
798 if ((type.length>5) && (type.substr(0,5) == 'field') && (property.childNodes.length != 0)) {
799 var value = property.firstChild.nodeValue;
800 var inputField = document.createElement('input');
801 inputField.setAttribute('type','hidden');
802 inputField.setAttribute('name','slot-'+panelid+'-'+fieldid+'-'+type.substr(6,type.length));
803 inputField.setAttribute('value',value);
804 saveForm.appendChild(inputField);
809 // check fieldwidth in the layout; if more than one, then add an (empty) for each (so the parser can keep track of the slots)
810 var endId = fieldid+Studio2.getColumnWidth(field)-1;
811 while (fieldid<endId) {
813 var inputField = document.createElement('input');
814 inputField.setAttribute('type','hidden');
815 inputField.setAttribute('name','slot-'+panelid+'-'+fieldid+'-name');
816 inputField.setAttribute('value','(empty)');
817 saveForm.appendChild(inputField);
829 handleSave: function() {
830 ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVING'));
831 ModuleBuilder.state.isDirty=false;
832 this.prepareForSave();
833 // set <input type='hidden' name='action' value='saveLayout'>
834 var saveForm = document.forms['prepareForSave'];
835 var inputField = document.createElement('input');
836 inputField.setAttribute('type','hidden');
837 inputField.setAttribute('name','action');
838 inputField.setAttribute('value','saveLayout');
839 saveForm.appendChild(inputField);
840 ModuleBuilder.submitForm('prepareForSave');
841 ajaxStatus.flashStatus('Save complete',5000);
844 handlePublish: function() {
845 ajaxStatus.showStatus(SUGAR.language.get('app_strings', 'LBL_SAVING'));
846 ModuleBuilder.state.isDirty=false;
847 this.prepareForSave();
848 // set <input type='hidden' name='action' value='saveAndPublishLayout'>
849 var saveForm = document.forms['prepareForSave'];
850 var inputField = document.createElement('input');
851 inputField.setAttribute('type','hidden');
852 inputField.setAttribute('name','action');
853 inputField.setAttribute('value','saveAndPublishLayout');
854 saveForm.appendChild(inputField);
855 ModuleBuilder.submitForm('prepareForSave');
856 ajaxStatus.flashStatus(SUGAR.language.get('ModuleBuilder','LBL_DEPLOYE_COMPLETE'),5000);
859 checkGridLayout : function(view)
861 if (Studio2.countGridFields() == 0) {
862 ModuleBuilder.layoutValidation.popup() ;
865 if (view == "detailview")
868 return Studio2.checkRequiredFields();
871 countGridFields : function() {
873 var divs = document.getElementById( 'panels' ).getElementsByTagName( 'div' ) ;
874 for ( var j=0;j<divs.length;j++) {
875 if (divs[j].className == 'le_field')
881 checkRequiredFields : function(){
882 var Dom = YAHOO.util.Dom;
883 var availablefields = Dom.get('availablefields');
884 var fields = Dom.getElementsByClassName('field_name', '', 'availablefields');
886 for(field in fields){
887 if (Studio2.requiredFields.indexOf(fields[field].innerHTML) != -1) {
888 missing[missing.length] = fields[field].innerHTML;
891 if (missing.length > 0)
893 var msg = SUGAR.language.get("ModuleBuilder", "ERROR_REQUIRED_FIELDS");
894 for (var i = 0; i < missing.length; i++) {
895 msg += '"' + missing[i] + '"';
896 if (i != missing.length - 1)
899 return window.confirm(msg);
905 checkCalcFields: function(view, error) {
906 if (view == "DetailView")
909 var Dom = YAHOO.util.Dom;
910 var panels = Dom.get('panels');
911 var fields = Dom.getElementsByClassName('field_name', 'span', 'panels');
914 if (Studio2.calcFieldList.indexOf(fields[i].innerHTML) != -1) {
915 cfs.push(fields[i].innerHTML);
920 var msg = SUGAR.language.get("ModuleBuilder", error) + "\n";
921 for (var i = 0; i < cfs.length; i++) {
922 msg += '"' + cfs[i] + '"';
923 if (i != cfs.length - 1)
926 return window.confirm(msg);
932 getScrollZones: function(parent){
933 var Dom = YAHOO.util.Dom, TL, TR, BL, BR;
934 //Height of the scroll zones
935 var h = 20, el = Dom.get(parent);
936 //Calculate the top area
938 BR = [TL[0] + el.clientWidth, TL[1] + h];
939 var scrollUpBox = [TL, BR];
940 //Calculate the bottom area.
941 BR = [BR[0], TL[1] + el.clientHeight];
942 TL = [TL[0], BR[1] - h];
944 var scrollDownBox = [TL, BR];
951 isWithinBox: function(xy, box)
953 return xy[0] > box[0][0] && xy[0] < box[1][0] && xy[1] > box[0][1] && xy[1] < box[1][1];
956 setScrollObj: function(o){
957 Studio2.scrollObj = o;
958 Studio2.scrollCheck = setInterval(function(){
959 var o = Studio2.scrollObj;
960 for(var i in Studio2.scrollZones)
962 var zone = Studio2.scrollZones[i];
963 if (Studio2.isWithinBox([o.lastX, o.lastY], zone.up))
965 document.getElementById(i).scrollTop -= 5;
966 YAHOO.util.DragDropMgr.refreshCache();
969 else if (Studio2.isWithinBox([o.lastX, o.lastY], zone.down))
971 document.getElementById(i).scrollTop += 5;
972 YAHOO.util.DragDropMgr.refreshCache();
979 clearScrollObj: function() {
980 Studio2.scrollObj = false;
981 if (Studio2.scrollCheck)
982 clearInterval(Studio2.scrollCheck);
983 Studio2.scrollCheck = false;
986 onDrag: function(e) {
987 // Keep track of the direction of the drag for use during onDragOver
990 if (y < this.lastY) {
992 } else if (y > this.lastY) {
993 this.goingUp = false;
996 this.lastY = e.pageY || e.clientY;
997 this.lastX = e.pageX || e.clientX;
1001 Studio2.firstPanelId = "";
1002 Studio2.firstPanelIdCount = 0;