/*****************************************************************************
 * $Header$
 * $Author$
 * $Revision$
 * $Date$
 *
 * controls.js
 *
 * Copyright: Neolane 2001-2007
 *****************************************************************************/

//[of]:DebugConsole
/** DebugConsole
  *
  * Widget used to display the context when __debug=1 is avaiable on the URL. */
function DebugConsole(controller)
{
  this.controller = controller
  controller.registerObserver("/", this, this.onNodeChange, "DebugConsole", controller.OBSERVE_CHILDREN)
}

/** One node has changed in the context */
DebugConsole.prototype.onNodeChange = function()
{
  if ( this.htmlElement == null )
  {
    this.htmlElement = document.getElementById("DebugConsole")
    if ( this.htmlElement == null )
    {
      this.htmlElement = document.body.appendChild(document.createElement("pre"));
      this.htmlElement.id = "DebugConsole"
    }
  }

  var strXMLContext = toXMLString(this.controller.ctx)
  this.htmlElement.innerHTML = "" /* reset the content */
  this.htmlElement.appendChild(document.createTextNode(strXMLContext))
}
//[cf]
//[of]:RichTextArea
/** RichTextArea
  *
  * Widget used to add an Html Text Area*/
  
  
  /** Constructor
  *
  * @controller       Main controller
  * @id               id of the td i want to be in
  * @xpath            the xpath of the richtextarea
  * @pos              position of the tool bar */ 
function richTextArea(controller, id, xpath, pos)
{
  this.controller = controller;
  this.htmlParent = document.getElementById(id);
  this.id = id + "_richTextArea";
  this.xpath = xpath;
  this.toolbarPosition = pos;
  this.countTrigger = 0;
  this.countCurrent = 0;
  this.isTimer = false;
  this.tableIframe = 0;
  this.divTextArea = 0;
  this.iframe = 0;
  this.divToolBar = 0;
  this.arrayFct = new Array();
  this.init();
  controller.registerObserver(xpath, this, this.onNodeChange, this.id, controller.OBSERVE_XPATH)
}

  
  /** Fct called on notify
  *
  * @xpath              the xpath of the change 
  * @value              value to set in */ 
richTextArea.prototype.onNodeChange = function (xpath, value)
{
  this.setContent(value);
}

/** Fonction called when the form is submit
  *
  *                             */

richTextArea.prototype.onSubmit = function()
{
  this.controller.setValue(this.xpath, this.getContent(), this.id);
  return true;
}


/** Initialisation fonction
  *
  *                             */ 
richTextArea.prototype.init = function ()
{
  this.initFunction();
  richTextArea.prototype.getMyArea(this.id, this) // register this richTextArea
  this.initTextArea();

  if (document.designMode && !isOpera()) 
  {
    this.divTextArea.style['display'] = "none";
    this.initBuildTable()
    this.iframe = document.getElementById(this.id);
    this.initAfterLoad();
  }
}


/** Add the function to build element to the arrayFCT
  *
  *                             */ 
richTextArea.prototype.initFunction = function ()
{
  this.arrayFct['bold'] = this.makeButton;
  this.arrayFct['italic'] = this.makeButton;
  this.arrayFct['underline'] = this.makeButton;
  this.arrayFct['justifyleft'] = this.makeButton;
  this.arrayFct['justifyfull'] = this.makeButton;
  this.arrayFct['justifycenter'] = this.makeButton;
  this.arrayFct['justifyright'] = this.makeButton;
  this.arrayFct['source'] = this.makeSource;
}

/** Make the textArea
  *
  *                             */ 
richTextArea.prototype.initTextArea = function ()
{
  this.divTextArea = document.createElement("div");
  this.htmlParent.appendChild(this.divTextArea);
  this.textArea = document.createElement("textarea");
  this.textArea.id = this.id + '_textarea';
  this.textArea.onblur = this.makeEvent(this.id, this.refresh);
  this.textArea.className = "textarea";
  this.divTextArea.appendChild(this.textArea);
}


/** Make the Table for the Iframe and the Iframe
  *
  *                             */ 
richTextArea.prototype.initBuildTable = function()
{
  this.tableIframe = document.createElement('table');
  this.tableIframe.appendChild(document.createElement('tbody'));
  this.tableIframe.lastChild.appendChild(document.createElement("tr"));
  if (this.toolbarPosition == 0)
  {
    this.divBar = this.tableIframe.lastChild.lastChild.appendChild(document.createElement("td"));
    this.tableIframe.lastChild.appendChild(document.createElement("tr"));
    this.tableIframe.lastChild.lastChild.appendChild(document.createElement("td")).appendChild(this.makeIframe("type"));
  }
  else if (this.toolbarPosition == 1)
  {
    this.divBar = this.tableIframe.lastChild.lastChild.appendChild(document.createElement("td"));
    this.tableIframe.lastChild.lastChild.appendChild(document.createElement("td")).appendChild(this.makeIframe("type"));
  }
  else if (this.toolbarPosition == 2)
  {
    this.tableIframe.lastChild.lastChild.appendChild(document.createElement("td")).appendChild(this.makeIframe("type"));
    this.tableIframe.lastChild.appendChild(document.createElement("tr"));
    this.divBar = this.tableIframe.lastChild.lastChild.appendChild(document.createElement("td"));
  }
  else if (this.toolbarPosition == 3)
  {
    this.tableIframe.lastChild.lastChild.appendChild(document.createElement("td")).appendChild(this.makeIframe("type"));
    this.divBar = this.tableIframe.lastChild.lastChild.appendChild(document.createElement("td"));
  }
  else
  {
    this.tableIframe.lastChild.lastChild.appendChild(document.createElement("td")).appendChild(this.makeIframe("type"));
    this.divBar = this.tableIframe.lastChild.lastChild.appendChild(document.createElement("td"));
    this.divBar.style['display'] = 'none';
  }
  
  this.divBar.className = "richAreaToolbar"
  this.htmlParent.appendChild(this.tableIframe);
}

/** STATIC fct that let the browser build the iframe document
  * @id               id of the iframe
  *                             */ 
richTextArea.prototype.initAfterLoad = function ()
{
  var idoc;
  var w3c = true;
  if (this.iframe.contentDocument !== undefined)
    idoc = this.iframe.contentDocument;
  else if (this.iframe.contentWindow !== undefined)
  {
    idoc = this.iframe.contentWindow;
    w3c = false;
  }

  if (idoc == null || idoc === undefined)
  {
    window.setTimeout(this.makeEvent(this.id, this.initAfterLoad) , 250);
  }
  else 
  {
    if (w3c == false)
    {
      idoc = idoc.document;
      if (window[this.id].document.body == null || window[this.id].document.body == undefined)
        {
          window.setTimeout(this.makeEvent(this.id, this.initAfterLoad) , 500);
          return ;
        }
    }

    idoc.open();
    idoc.close();
    idoc.designMode = w3c ? "on" : "On";
    this.setContent(this.controller.getValue(this.xpath));
    this.addEvents();
    this.initIframeStyle(idoc);
  }
}


/** Make Set the style of the Iframe Body and get it from the .richTextArea_Body in the document.styleSheets
  *
  *                             */ 
richTextArea.prototype.initIframeStyle = function (idoc)
{
  var rule;
  for (var i = 0; i < document.styleSheets.length; i++)
  {
    var rules;
    if (isIE())
      rules = document.styleSheets[i].rules;
    else
      rules = document.styleSheets[i].cssRules;
    for (var j = 0; j < rules.length; j++)
      if (rules[j].selectorText == ".richTextArea_Body")
        rule = rules[j];
  }
  var  style_node = idoc.createElement("style");
  style_node.setAttribute("type", "text/css");
  style_node.setAttribute("media", "screen");
  if (isSafari())
  {
    var head = idoc.createElement("head");
    idoc.firstChild.insertBefore(head, idoc.firstChild.firstChild);
  }
  if (idoc.getElementsByTagName("head").length > 0)
  {
    idoc.getElementsByTagName("head")[0].appendChild(style_node);
    if (isIE() && idoc.styleSheets && idoc.styleSheets.length > 0)
    {
      var last_style_node = idoc.styleSheets[idoc.styleSheets.length - 1];
      if (typeof(last_style_node.addRule) == "object")
      {
        last_style_node.addRule(".richTextArea_Body", rule.style.cssText);
        last_style_node.addRule("P", "margin: 0;");
      }
    }
    else
      style_node.appendChild(document.createTextNode(rule.cssText));
  }
  if (idoc.body)
  {
    idoc.body.className = "richTextArea_Body";
  }
}

/** Make a button
  * @type      type of the element you want to add
  *                             */
richTextArea.prototype.addElement = function (type)
{
  if (document.designMode /*&& !isOpera()*/) 
  {
    if (this.arrayFct[type] !== undefined)
    {
      this.divBar.appendChild(this.arrayFct[type].call(this, type));
      if (this.toolbarPosition & 1)
        this.divBar.appendChild(document.createElement("br"));
    }
  }
}

/** Change the width of the RichtextArea
  * @value                      value you want to set
  *                             */
richTextArea.prototype.setWidth = function(value)
{
  this.textArea.style["width"] = value;
  if (document.designMode && !isOpera())
    this.iframe.style["width"] = value;
}

/** Change the height of the RichtextArea
  * @value                      value you want to set
  *                             */
richTextArea.prototype.setHeight = function(value)
{
  this.textArea.style["height"] = value;
  if (document.designMode && !isOpera())
    this.iframe.style["height"] = value;
}

/** Change the align of the RichtextArea
  * @value                      value you want to set
  *                             */
richTextArea.prototype.setAlign = function(value)
{
  this.htmlParent.style["align"] = value;
  this.divTextArea.style['align'] = value;
  if (document.designMode && !isOpera())
  {
    this.tableIframe.lastChild.firstChild.firstChild.style["align"] = value;
    this.tableIframe.lastChild.lastChild.firstChild.style["align"] = value;
    this.tableIframe.lastChild.lastChild.lastChild.style["align"] = value;
    this.tableIframe.lastChild.firstChild.lastChild.style["align"] = value;
  }
}

/** Change the valign of the RichtextArea
  * @value                      value you want to set
  *                             */
richTextArea.prototype.setVAlign = function(value)
{
  this.htmlParent.style["valign"] = value;
  this.divTextArea.style['valign'] = value;
  if (document.designMode && !isOpera())
  {
    this.tableIframe.lastChild.firstChild.firstChild.style["valign"] = value;
    this.tableIframe.lastChild.lastChild.firstChild.style["valign"] = value;
    this.tableIframe.lastChild.lastChild.lastChild.style["valign"] = value;
    this.tableIframe.lastChild.firstChild.lastChild.style["valign"] = value;
  }
}

/** Make a button
  * @type      type of the button (!!!used to execCommand!!!)
  *                             */ 
richTextArea.prototype.makeButton = function (type) 
{
  var input = document.createElement("img");
  input.src = "/xtk/img/form/"+ type + ".png";
  input.className = type;
  input.id = this.id + "_" + type;
  input.onmousedown = this.makeEvent(this.id, this.buttonOnMouseDown);
  input.onclick = this.makeEvent(this.id, this.buttonOnClick);

  var link = document.createElement("div");

  link.className = "button"
  link.appendChild(input)
  return (link);
}

/** Make a button
  * @type      nearly unused
  *                             */ 
richTextArea.prototype.makeSource = function (type) 
{
  var input = document.createElement("img");
  input.className = type;
  input.src = "/xtk/img/form/"+ type + ".png";
  input.id = this.id + "_" + type;
  input.onmousedown = this.makeEvent(this.id, this.buttonOnMouseDown);
  input.onclick = this.makeEvent(this.id, this.SourceOnClick);
  var input2 = input.cloneNode(true);
  this.divTextArea.appendChild(input2); 
  input2.onmousedown = this.makeEvent(this.id, this.buttonOnMouseDown);
  input2.onclick = this.makeEvent(this.id, this.SourceOnClick);
  var link = document.createElement("div");
  link.className = "button"
  link.appendChild(input)  
  return (link);
}


/** Make the iframe
  * @type              UNUSED
  *                             */ 
richTextArea.prototype.makeIframe = function (type)
{
  this.iframe = document.createElement("iframe");
  this.iframe.id = this.id;
  this.iframe.className = "richTextArea_Frame";
  return (this.iframe);
}

/** Set the EventsHandler to the iframe
  *
  *                             */ 
richTextArea.prototype.addEvents = function ()
{
  if (this.iframe.contentDocument && this.iframe.contentDocument.addEventListener)
  {
    this.iframe.contentDocument.addEventListener("keyup", this.makeEvent(this.id, this.askRefresh), false);
    this.iframe.contentDocument.addEventListener("mouseup", this.makeEvent(this.id, this.askRefresh), false);
  }
  else if(this.iframe.contentWindow && this.iframe.contentWindow.document &&
           this.iframe.contentWindow.document.attachEvent)
  {
    this.iframe.contentWindow.document.attachEvent("onkeyup", this.makeEvent(this.id, this.askRefresh))
    this.iframe.contentWindow.document.attachEvent("onmouseup", this.makeEvent(this.id, this.askRefresh))
  }
}

/** Handler of mousedown event on button. Do nothing but avoid some default problem with IE
  *
  *                             */ 
richTextArea.prototype.buttonOnMouseDown = function(e)
{
  var evt = e ? e : window.event; 
  if (evt.returnValue)
    evt.returnValue = false;
  else if (evt.preventDefault)
    evt.preventDefault( );
  return false;
}

/** Handler of click event on Style buttons.
  *
  *                             */ 
richTextArea.prototype.buttonOnClick = function (e) 
{
  var target;
  var event = e || window.event;
  if(event.target)
    target = event.target;
  else
    target = event.srcElement;

  if (window[this.id])
    window[this.id].document.execCommand(target.className, false, null);
  else
    document.getElementById(this.id).contentWindow.document.execCommand(target.className, false, null); 
  this.askRefresh(e);
  return false;
}

/** Handler of click event on Source button.
  *
  *                             */ 
richTextArea.prototype.SourceOnClick = function (e) 
{
  var target;
  var event = e || window.event;
  if(event.target)
    target = event.target;
  else
    target = event.srcElement;

  
  var str = this.getContent();
  var tmp = this.tableIframe.style['display'];
  this.tableIframe.style['display'] = this.divTextArea.style['display'];
  this.divTextArea.style['display'] = tmp;
  this.setContent(str);
  this.askRefresh(e);
  return false;
}

/** return the content of the RichTextArea.
  *
  *                             */ 
richTextArea.prototype.getContent = function() 
{
  if (document.designMode && !isOpera() && this.divTextArea.style['display'] == 'none') 
  {
    var str;
    if (window[this.id])
      str = window[this.id].document.body.innerHTML;
    else
      str = document.getElementById(this.id).contentWindow.document.body.innerHTML;
    if (isIE() && (str == '<P>&nbsp;</P>' || str == '<DIV>&nbsp;</DIV>'))
      str = "";
    else if (isGecko() && str == '<br>')
      str = "";
    else if (isSafari() && (str == '<div><br></div>' || str == '<br>'))
      str = "";
    return (str);
  } 
  else
  {
    return document.getElementById(this.id + "_textarea").value;
  }
}

/** Set the value of the RTA.
  *
  *                             */
richTextArea.prototype.setContent = function(value) 
{
  if (document.designMode && !isOpera() && this.divTextArea.style['display'] == 'none') 
  {
    if (this.iframe.contentDocument && this.iframe.contentDocument.body)
      this.iframe.contentDocument.body.innerHTML = value;
    else if(this.iframe.contentWindow && this.iframe.contentWindow.document
            && this.iframe.contentWindow.document.body)
      this.iframe.contentWindow.document.body.innerHTML = value;
    else
      this.initAfterLoad(this.id);
  }
  else
    document.getElementById(this.id + "_textarea").value = value;
  return (true);
}

/** STATIC FONCTION, retrieve or set a richtextarea associated to an id
  * @id              The RTA id that we want to retrieve
  * @val             if undefined the fct will return the RTA associated to the param id.
  *                  else it will store val and associated it to val.id
  *                             */
richTextArea.prototype.getMyArea = function (id, val)
{
  if (this.hashRichTextArea === undefined)
    this.hashRichTextArea = new Array();
  if (val !== undefined)
  {
    this.hashRichTextArea[val.id] = val;
  }
  else
    return this.hashRichTextArea[id];
  return null;
}

/** Fct to notifiate the controler from changes
  *
  *                             */
richTextArea.prototype.refresh = function(e)
{
  if (this.countCurrent != this.countTrigger)
  {
    this.isTimer = true;
    this.countTrigger = this.countCurrent;
    window.setTimeout(this.makeEvent(this.id, this.refresh), 500);
  }
  else
  {
    this.isTimer = false;
    this.controller.setValue(this.xpath, this.getContent(), this.id);
  }
}

/** Fct to temporate the notification
  *
  *                             */
richTextArea.prototype.askRefresh = function(e)
{
  this.countCurrent++;

  if (this.isTimer == false)
  {
    this.isTimer = true;
    this.countTrigger = this.countCurrent;
    window.setTimeout(this.makeEvent(this.id, this.refresh), 500);
  }
  return false;
}

/** STATIC FONCTION.  it return a function that you should use for eventhandling setting.
  *                   It helps calling richTextArea methode with the RTA associated to the @id
  * @id               The RTA id that will instanciate the fct param
  * @fct              the fonction you want to be called with the rta with the param id
  *                             */
richTextArea.prototype.makeEvent = function(id, fct)
{
  return function(e)
  {
    fct.call(richTextArea.prototype.getMyArea(id), e);
    return false;
  };
}
//[cf]

/** Functions to set the width of a table's tds to the size of the biggest one
  *
  *                                 */
function AutoAdjustMatrixColumns(id)
{
  var table = document.getElementById(id);
  var ths = table.getElementsByTagName ('TH');
  var max = 0;
  for (var i = 1; i < ths.length; i++)
  {
    if (max < ths[i].offsetWidth)
      max = ths[i].offsetWidth;
  }
  if( max > 0 ) // if displayed
  {
    for (var i = 1; i < ths.length; i++)
      ths[i].width = max + "px";
  }
}

// ---------------------------------------------------------------
// Calls a function when the enter key is pressed
// ---------------------------------------------------------------
function onEnterPressed(e, func) 
{
  var evt = (e) ? e:(window.event) ? window.event : null;
  if( evt )
  {
    var cKey = (evt.charCode) ? evt.charCode : 
                ((evt.keyCode) ? evt.keyCode : 
                  ((evt.which) ? evt.which : 0));
    if( cKey == "13" )
      return func();
  }
  return true;
}


// ---------------------------------------------------------------
// Performs a click
// @option URL or object ID list or javascript code
// ---------------------------------------------------------------
function PerformClickAction(ctx, action, target, transition, option, param, event)
{
  // Use a form to pass URL parameters.
  // If the form already exists, reuse it.
  if( action == "url" )
  {
    /** Add a value as an hidden input in a form */
    function addInputValue(form, strName, strValue)
    {
      input = document.createElement("input")
      input.type = "hidden"
      input.name = strName
      input.value = strValue
      form.appendChild(input)
    }

    if( document.getElementById("URLForm") != null )
    {
      var ndForm = document.getElementById("URLForm")
      // Delete previous form inputs 
      var ndFormChild = ndForm.firstChild
      while( ndFormChild != null )
      {
        if( ndFormChild.tagName == "INPUT" )
          ndFormChild = ndForm.removeChild(ndFormChild)
        ndFormChild = ndFormChild.nextSibling
      }
    }
    
    var ndURLForm = document.createElement("form")
    ndURLForm.setAttribute("id", "URLForm")
    
    ndURLForm.method = "GET"
    ndURLForm.action = option
    ndURLForm.target = target
    
    for (var i=0; i < param.length; i++)
      addInputValue(ndURLForm, param[i].name, param[i].value)
    
    document.body.appendChild(ndURLForm)
    ndURLForm.submit()
  }
  else
  {
    for (var i=0; i < ctx.length; i++)
      document.controller.setValue(ctx[i].xpath, ctx[i].value)
    
    if( action == "refreshData" )
    {
      var jsString = ""
      for ( var i in option )
        jsString += "document.lstData"+ option[i] +".load(true);"
      return eval(jsString)
    }
    else if( action == "javascript" )
      return eval(option)
    else
      return document.controller.submit(action, target, transition)
  }
}

// ===========================================================================
// HTML  dialog
// ===========================================================================
// ---------------------------------------------------------------------------
// constructor
// [in] strTitle : dialog title
// [in] strOkLabel : 
// [in] dialogsCallBacks : object which implement some functions
// ---------------------------------------------------------------------------
function HtmlDialog(strTitle, strOkLabel, dialogsCallBacks, bCenter)
{
  this.htmlElement = document.createElement("div")
  
  // disable text selection
  if( isIE() ) 
    this.htmlElement.onselectstart = function () { return false }
  else
    this.htmlElement.onmousedown = function (event) 
    { 
      if (typeof event.preventDefault != 'undefined') 
        event.preventDefault();
    }
  this.htmlElement.className = "dialog"
  this.htmlElement.style.display = "none"
  this.divOverToDisable = document.getElementById("overToDisable")
  this.dialogsCallBacks = dialogsCallBacks
  this.bCenter = bCenter
  var title = document.createElement("table")
  title.className = "title"
  var tr = title.appendChild(document.createElement("tbody")).appendChild(document.createElement("tr"))
  var tdTitle = tr.appendChild(document.createElement("td"))
  tdTitle.style.width="100%"
  tdTitle.appendChild(document.createTextNode(strTitle))
  tdTitle.className = "title"

  // close button
  var tdClose = tr.appendChild(document.createElement("td"))
  tdClose.className = "close"
  var closeBtn = tdClose.appendChild(document.createElement("img"))
  closeBtn.src = "/xtk/img/close.png"
  closeBtn.className = "close"
  closeBtn.dialog = this
  
  this.htmlElement.appendChild(title)

  this.divContent = document.createElement("div")
  this.divContent.className = "content"
  this.divContent.style.display = "none"
  this.htmlElement.appendChild(this.divContent)
  
  this.divLoading = document.createElement("div")
  this.divLoading.className = "loading"
  this.divLoading.innerHTML = 
        "<div><object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='https://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,65,0' width='48' height='48' id='preload48x48' align='middle'>"+
        "  <param name='movie' value='/xtk/img/form/classic/preload48x48.swf'/>"+
        "  <param name='quality' value='high' /><param name='bgcolor' value='#ffffff' />"+
        "  <embed src='/xtk/img/form/classic/preload48x48.swf' quality='high' bgcolor='#ffffff' width='48' height='48' name='preload48x48' align='middle' type='application/x-shockwave-flash' pluginspage='https://www.macromedia.com/go/getflashplayer'/>"+
        "</object></div>"
  this.htmlElement.appendChild(this.divLoading)
  
  var divCommand = document.createElement("div")
  divCommand.className = "command"
  this.htmlElement.appendChild(divCommand)
  
  this.buttonOk = document.createElement("input")
  this.buttonOk.type = "button"
  if( strOkLabel == "" || strOkLabel == null )
    strOkLabel = xtk_formbase.dialog_defaultOk()
  this.buttonOk.value = strOkLabel
  this.buttonOk.dialog = this  
  divCommand.appendChild(this.buttonOk)
  
  this.buttonCancel = document.createElement("input")
  this.buttonCancel.type = "button"
  this.buttonCancel.value = xtk_formbase.dialog_cancel()
  this.buttonCancel.dialog = this
  divCommand.appendChild(this.buttonCancel)        
  document.getElementById("dialogsLib").appendChild(this.htmlElement)
  
  this.buttonCancel.onclick = function ()
  {
    this.dialog.show(false)
  }
  this.buttonOk.onclick = function ()
  {
    var bHide = true 
    if( this.dialog.dialogsCallBacks && typeof(this.dialog.dialogsCallBacks.onValidDialog) == "function" )
      bHide = this.dialog.dialogsCallBacks.onValidDialog()
    if( bHide )
      this.dialog.show(false)
  }
  closeBtn.onclick = function()
  {
    this.dialog.htmlElement.style.display  = 'none'
    var divOverToDisable = document.getElementById("overToDisable")
    if( divOverToDisable != null )
      divOverToDisable.style.display = 'none'
  }
}

HtmlDialog.prototype.setSize = function(width, height)
{
  if( typeof(width) == "string" )
    this.htmlElement.style.width = width
  else if( width )
    this.htmlElement.style.width = width + "px"
  if( typeof(height) == "string" )
    this.htmlElement.style.height = height
  else if( height )
    this.htmlElement.style.height = height + "px"
}

HtmlDialog.prototype.show = function(bVisible)
{
  function getWindowWidth()
  {
    var iWindowWidth
    if( window.innerWidth ) // all except IE
      iWindowWidth  = window.innerWidth;
    else if( document.documentElement && document.documentElement.clientWidth ) // IE 6
      iWindowWidth = document.documentElement.clientWidth
    else if( document.body ) // IE 7
      iWindowWidth = document.body.clientWidth;
    return iWindowWidth
  }   
  
  if( bVisible != false )
  {
    this.htmlElement.style.display = "block"
    if( this.bCenter )
    { 
      var iScrollLeft, iScrollTop
      if( document.documentElement.scrollLeft != null )
      {
        iScrollLeft = document.documentElement.scrollLeft
        iScrollTop = document.documentElement.scrollTop
      }
      else 
      {
        iScrollLeft = document.body.scrollLeft 
        iScrollTop = document.body.scrollTop   
      }
    
      // Center the dialog horizontally      
      this.htmlElement.style.left = iScrollLeft+Math.floor((getWindowWidth() - this.htmlElement.offsetWidth)/2)+"px"
      this.htmlElement.style.top = 50 + iScrollTop + "px"
    }
  }
  else
    this.htmlElement.style.display = "none"

  if( this.divOverToDisable )
  {
    this.divOverToDisable.style.display = this.htmlElement.style.display
    this.divOverToDisable.style.height  = document.body.clientHeight + "px"  
    this.divOverToDisable.style.width  = document.body.clientWidth + "px"  
  }
  
  if( bVisible != false && this.dialogsCallBacks 
   && typeof(this.dialogsCallBacks.onShowDialog) == "function" )
    this.dialogsCallBacks.onShowDialog()
} 

HtmlDialog.prototype.addContent = function(html)
{
  this.divContent.appendChild(html)
} 

HtmlDialog.prototype.setLoading = function(bLoading)
{
  if( bLoading )
  {
    this.divContent.style.display = "none"
    this.divLoading.style.display = "block"
  }
  else
  {
    this.divContent.style.display = "block"
    this.divLoading.style.display = "none"
  }
} 


// ===========================================================================
// DHTML version of linkEdit
// ===========================================================================
// ---------------------------------------------------------------------------
// constructor
// [in] controller 
// [in] id : javascript id of this linkEdit
// [in] xpath : xpath of an element to store id and compute string
// [in] strFolderModel : xpath of an element to store id and compute string
// [in] strFolderLinkId : xpath folder link id
// [in] strFolderLink : xpath folder link t
// [in] bIsFolder : this link edit link to a folder
// [in] bWriteAccess : force to filter on right folder access
// ---------------------------------------------------------------------------
function XtkLinkEdit(controller, id, xpath, strSchemaId, strFolderModel, strFolderLinkId,strFolderLink,  bIsFolder, bWriteFolderAccess)
{
  this.controller = controller
  this.id = id
  this.xpath = xpath
  this.isFolder = false
  this.iSelectedFolderId = 0
  this.strSchemaId = strSchemaId
  this.isFolder = bIsFolder
  this.strFolderModel = strFolderModel
  this.strFolderLinkId = strFolderLinkId
  this.strFolderLink = strFolderLink
  if( this.strFolderModel != "" || this.isFolder )
  {
    this.xtkNavigationTree = new XtkNavigationTree(this.controller, this.strFolderModel,
                                                   "/ctx/" + this.id + "/folder", this)
    if (bWriteFolderAccess != undefined && (bWriteFolderAccess == "true" || bWriteFolderAccess == 1))
      this.xtkNavigationTree.isWriteAccess = true
  }
  this.ndSysFilter = null
  this.aJoinPath = new Array()
  this.aSelectionData = null
  this.bNavtreeLoaded = false
}

XtkLinkEdit.prototype.setSysFilter = function(ndSysFilter)
{
  if( this.isFolder && this.xtkNavigationTree )
    this.xtkNavigationTree.setSysFilter(ndSysFilter)
  else
    this.ndSysFilter = ndSysFilter
}

XtkLinkEdit.prototype.addJoinPath = function(xtrXPath)
{
  this.aJoinPath.push(xtrXPath)
}

XtkLinkEdit.prototype.initNavtree = function()
{
  if( !this.bNavtreeLoaded )
    this.xtkNavigationTree.init(this.iSelectedFolderId, this.strSelectedFolderFullName)
  this.bNavtreeLoaded = true
}

// ---------------------------------------------------------------------------
// onShowDialog callback 
// get first authorized folder or load folder's documents 
// ---------------------------------------------------------------------------
XtkLinkEdit.prototype.onShowDialog = function()
{
  this.aSelection = new Array()
  for( var index in this.aJoinPath )
  {
    var xpath = this.aJoinPath[index]
    var value = this.controller.getValue(this.xpath + "/" + xpath)
    if( value )
      this.aSelection.push({"xpath":xpath, "value":value})
  }
    
  if( this.aSelection.length > 0 && this.strFolderModel != ""  )
  { //
    // we have a selection : get parent folder
    var query = new QueryDef(this.strSchemaId, "get")
    query.action = "getEntityFolder"
    query.addSelectExpr("[" + this.strFolderLinkId + "]")
    query.addSelectExpr("[" + this.strFolderLink + "/@fullName]")
    for(var index in this.aSelection )
      query.addWhereConditionExpr("[" + this.aSelection[index].xpath + "] = " 
                                      + escapeXtkString(this.aSelection[index].value))
    query.execute(this.controller.soapRouterUrl, this.controller.getSessionToken(), this)  
  }
  else if( this.aSelection.length > 0 && this.isFolder )
  {
    this.iSelectedFolderId = this.aSelection[0].value
    this.initNavtree()   
    // hide loading    
    this.dialog.setLoading(false)
  }
  else 
  {
    if( !this.bNavtreeLoaded && (this.strFolderModel != "" || this.isFolder ))
    {
      var soapCall = new SoapMethodCall("xtk:folder", "FindFirstAuthorized",
                                        SoapMethodCall.SOAP_ENCODING_NATIVE, 
                                        this.controller.getSessionToken())
      soapCall.writeString("folderFilter", "@model = "+ escapeXtkString(this.strFolderModel))
      soapCall.writeBoolean("writeAccess", false)
      soapCall.finalizeDocument()
      soapCall.execute(this.controller.soapRouterUrl, this)      
    }
    else if( !this.isFolder )
      this.loadList()
  }
}

// ---------------------------------------------------------------------------
// onValidDialog callback 
// set values (compute string and key) via controller
// return a boolean to hide the dialog
// ---------------------------------------------------------------------------
XtkLinkEdit.prototype.onValidDialog = function()
{
  if( this.isFolder )
  {
    this.controller.setValue(this.xpath + "/@_cs", getXPathValue(this.selectedItem, "@label"))
    this.controller.setValue(this.xpath + "/@id", getXPathValue(this.selectedItem, "@id"))
  }
  else
  {
    this.controller.setValue(this.xpath + "/@_cs", getXPathValue(this.selectedItem, "@_cs"))
    if( this.aJoinPath.length > 0 )
    {
      for( var index in this.aJoinPath )
      {
        var xpath = this.aJoinPath[index]
        this.controller.setValue(this.xpath + "/" + xpath, getXPathValue(this.selectedItem, xpath))
      }
    }
    else
      this.controller.setValue(this.xpath + "/@id", getXPathValue(this.selectedItem, "@id"))
  }
  return true
}

// ---------------------------------------------------------------------------
// onXtkQueryCompleted callback 
// render list result in the dialog
// ---------------------------------------------------------------------------
XtkLinkEdit.prototype.onXtkQueryCompleted = function(queryDef, xmlResult, ex)
{
  if( ex == null )
  {
    if( queryDef.action == "loadList" )
    {
      var node = firstChildElement(xmlResult)    
      this.list.innerHTML = "" // clean old list
      
      while( node )
      {
        var item = this.list.appendChild(document.createElement("a"))
        item.href = "javascript:;"
        item.className = "linkEditListItem"
        item.itemKeys = node
        // test if this item is selected
        if( this.aSelection.length > 0 )
        {
          var bIsSelected = true
          for( var index in this.aSelection )
            bIsSelected = bIsSelected && this.aSelection[index].value == getXPathValue(node, this.aSelection[index].xpath)        
          if( bIsSelected )
          {
            this.selection = item
            item.className = "linkEditListItemSelected"          
          }
        }
        item.linkEdit = this
        item.onclick = function()
        {
          if( this.linkEdit.selection )
            this.linkEdit.selection.className = "linkEditListItem"
          this.className = "linkEditListItemSelected"
          this.linkEdit.selectedItem = this.itemKeys
          this.linkEdit.selection = this
          this.linkEdit.dialog.buttonOk.disabled = false
        }
        item.appendChild(document.createTextNode(getXPathValue(node, "@_cs")))
        node = nextSiblingElement(node)
      }
    }
    else if( queryDef.action == "getEntityFolder" )
    {
      this.iSelectedFolderId = parseInt(getXPathValue(xmlResult, this.strFolderLinkId))
      this.strSelectedFolderFullName = getXPathValue(xmlResult, this.strFolderLink + "/@fullName")
      this.initNavtree()
      this.loadList()    
    }
    
    // hide loading    
    this.dialog.setLoading(false)
  }
  else
    alert(ex)
}

// ---------------------------------------------------------------------------
// onSoapRequestCompleted callback 
// for FindFirstAuthorized
// ---------------------------------------------------------------------------
XtkLinkEdit.prototype.onSoapRequestCompleted = function(soapCall, ex)
{
  if( ex == null )
  {
    if( soapCall.strMethodName == "FindFirstAuthorized" )
    { //
      // Get next id of report counter to build a new unique internal name
      //
      var ndResult = soapCall.getNextElement();
      soapCall.checkNoMoreArgs();
      if( ndResult != null )
      { //
        // Get folder data and load content 
        this.strSelectedFolderFullName = ndResult.getAttribute("fullName")
        this.iSelectedFolderId = parseInt(ndResult.getAttribute("id"))
        this.initNavtree()
        this.loadList()
      }
      else if( this.isFolder )
        this.initNavtree()
      
      this.dialog.setLoading(false)
    } 
  }
  else
    alert(ex)
}

// ---------------------------------------------------------------------------
// Call back function called when a folder is selected in full dhml mode
// [in] xtkNavtree : navtree widget
// [in] xtkEntity : selected folder node
// ---------------------------------------------------------------------------
XtkLinkEdit.prototype.onFolderChange = function(xtkNavtree, xtkEntity)
{
  this.iSelectedFolderId = parseInt(getXPathValue(xtkEntity, "@id"))
  if( this.isFolder )
  {
    this.selectedItem = xtkEntity
    this.dialog.buttonOk.disabled = false
  }
  else
    this.loadList()
}

// ---------------------------------------------------------------------------
// render : draw the widget
// [in] htmlParent : where the widget will be added
// [in] strDocumentLabel : type of looked document (displayed in dialog title)
// ---------------------------------------------------------------------------
XtkLinkEdit.prototype.render = function(htmlParent, strDocumentLabel)
{
  this.input = document.createElement("input")
  this.input.id = this.id
  this.input.name = this.id
  this.input.className = "linkEdit"
  this.input.readOnly = "true"  

  htmlParent.appendChild(this.input)
  
  var button = document.createElement("div")
  button.linkEdit = this
  htmlParent.appendChild(button)
  button.onclick = function()
  {    
    this.linkEdit.dialog.show()
  }
  var img = document.createElement("img")
  img.src = "/xtk/img/form/xawchoice.png"
  button.appendChild(img)
  
  // Build the dialog
  this.dialog = new HtmlDialog(strDocumentLabel, "OK", this, true)
  this.dialog.buttonOk.disabled = true
  this.dialog.setSize("40em", "20em")
  var table = document.createElement("table")
  table.style.width = "100%"
  var tr = table.appendChild(document.createElement("tbody")).appendChild(document.createElement("tr"))

  // display navtree if needed 
  if( this.strFolderModel != "" || this.isFolder )
  {
    var folderTreeTd = document.createElement("td")
    folderTreeTd.className = "linkEditFolderTree"
    if( this.isFolder )
      folderTreeTd.style.width = "100%"
    tr.appendChild(folderTreeTd)
    var folderTreeDiv = document.createElement("div")
    folderTreeTd.appendChild(folderTreeDiv)
    folderTreeDiv.className = "linkEditFolderTree"
    this.xtkNavigationTree.render(folderTreeDiv)
  }
  
  // display the list to select entity
  if( !this.isFolder )
  {
    this.list = tr.appendChild(document.createElement("td")).appendChild(document.createElement("div"))
    this.list.className = "linkEditList"    
    var loadList = this.list.appendChild(document.createElement("div"))
    loadList.className = "loading"
    loadList.innerHTML = "<div><object classid='clsid:d27cdb6e-ae6d-11cf-96b8-444553540000' codebase='https://fpdownload.macromedia.com/pub/shockwave/cabs/flash/swflash.cab#version=6,0,65,0' width='48' height='48' id='preload48x48' align='middle'>"+
                         "  <param name='movie' value='/xtk/img/form/classic/preload48x48.swf'/>"+
                         "  <param name='quality' value='high' /><param name='bgcolor' value='#ffffff' />"+
                         "  <embed src='/xtk/img/form/classic/preload48x48.swf' quality='high' bgcolor='#ffffff' width='48' height='48' name='preload48x48' align='middle' type='application/x-shockwave-flash' pluginspage='https://www.macromedia.com/go/getflashplayer'/>"+
                         "</object></div>"
  }

  this.dialog.addContent(table)
}

// ---------------------------------------------------------------------------
// Start the query to load 
// ---------------------------------------------------------------------------
XtkLinkEdit.prototype.loadList = function()
{
  var query = new QueryDef(this.strSchemaId, "select")
  if( this.aJoinPath.length > 0 )
  {
    for(var index in this.aJoinPath )
    {
      var xpath = this.aJoinPath[index]
      query.addSelectExpr("[" + xpath + "]")
    }
  }
  else
    query.addSelectExpr("@id")
  query.addSelectExpr("[/]")
  query.setLineCount(100)
  if( this.strFolderLinkId != "" && this.strFolderModel != "")
    query.addWhereConditionExpr("[" + this.strFolderLinkId + "] = " + this.iSelectedFolderId)  
  if( this.ndSysFilter != null )
    query.addWhereCondition(this.ndSysFilter, "", true)
  query.action = "loadList"
  query.execute(this.controller.soapRouterUrl, this.controller.getSessionToken(), this)  
}
