/**
 * @fileoverview The Webnote specific classes.<br /><br />
 * The two main classes are {@link workspace} and {@link Note}.
 * {@link workspace} represents the workspace as a whole.  It contains
 * refernces to all the notes and methods for operations such as saving
 * the notes or undo-ing/redo-ing an action.
 */

// global variables
// user options



var debugOn = 0;
var notePadding = 5;
var noteBorder = 1;
var noteBorderColor = '#666666';
var miniWidth = 51;
var exposeSize = "70";


var adminEmail, baseURI, numDates,maxfen,maxtaillefenetre;

// TODO: make it easier for users to make custom color maps
var colorMap = {
'#ABAFD8' : 'mauve',
'#000000' : 'noir',
'#333333' : 'gris',
'#666666' : 'gris2',
'#999999' : 'gris3',
'#CCCCCC' : 'gris4',
'#FFFFFF' : 'blanc',
'#9999CC' : 'mauve1',
'#330099' : 'violet',
'#3300CC' : 'violet2',
'#6600CC' : 'violet3',
'#3333FF' : 'bleu',
'#3366CC' : 'bleu2',
'#6699FF' : 'bleu3',
'#99CCFF' : 'bleu4',
'#336600' : 'vert',
'#666633' : 'vert1',
'#33CC00' : 'vert2',
'#66CC00' :'vert3',
'#99FF00' :'vert4',
'#FF0000' :'rouge',
'#CE0000' : 'rouge1',
'#E78BF1' :'rose',
'#FF9900' : 'orange',
'#FFCC33' : 'orange1',
'#FFFF33' : 'jaune',
'#9E6949' : 'marron'

};
var bgColors = new Array();
for (var c in colorMap)
{
  bgColors.push(c);
}

// other global variables, you shouldn't change these
var BROWSER_IE_6 = 0;
var BROWSER_IE_5 = 1;
var BROWSER_SAFARI = 2;
var BROWSER_MOZILLA = 3;
var BROWSER_OPERA = 4;
var browser;

(function () { // closure away userAgent
  var userAgent = navigator.userAgent.toLowerCase();
  if (userAgent.indexOf('opera') != -1) { // opera contains msie and opera
    browser = BROWSER_OPERA;
  } else if (userAgent.indexOf('safari') != -1) {
    browser = BROWSER_SAFARI;
  } else if (userAgent.indexOf('msie') != -1) {
    if (userAgent.indexOf('6.0') != -1) {
      browser = BROWSER_IE_6;
    } else {
      browser = BROWSER_IE_5;
    }
  } else {
    browser = BROWSER_MOZILLA;
  }
})();

/**
 * Create a new note object.  You shouldn't need to call this directly, use
 * {@link workspace#createNote} instead.
 * @class A class that acts as a wrapper to the actual html div that is a
 * note.  Rather than operating directly on the html object, use this
 * class instead.
 * TODO: attach these methods directly to the html objects.
 * @param {HtmlElement} note a reference to the actual note or a string that
 * is the id of the note
 * @param {workspace} p a reference to the parent workspace
 * @param {string} text the text of the note
 */
function Note(note, p, text) {
  // constructor code
  if (typeof note == 'string')
    note = get(note);
  if (!text) text = '';

  
  /**
   * TODO: fix references to workspace with this.parent
   * @type workspace
   */
  this.parent = p;
  /**
   * Whether or not is it possible to click on a note and select it
   * @type boolean
   */
  this.selectable = true;
  /**
   * Whether or not we can double click and edit a note
   * @type boolean
   */
  this.editable = true;
  /**
   * The html id of the note
   * @type string
   */
  this.id = note.id;
  /**
   * The height and width of the note
   * @type Point
   */
  this.size = new Point(parseInt(note.style.width), parseInt(note.style.height));

  // create the mini note dom object
  var dotElt = document.createElement('div');
  dotElt.id = 'm' + this.id;
  dotElt.onmousedown = hitch(this, this.miniMouseDown);
  get('mini').appendChild(dotElt);

  var dot = get('m' + this.id);
  dot.className = 'mininote';
  dot.style.backgroundColor = note.style.backgroundColor;

  // call methods
  this.setColor(note.style.backgroundColor, true);
  this.setText(text);
 
  this.updateSize();
}
/**
 * User clicked on a note.
 */
Note.prototype.mouseDown = function(ev) {
  ev = ev || window.event;
  var target = ev.target || ev.srcElement;
  if (!this.selectable)
    return false;

  // alt + rt click == send to back
  // 2 is rt click in both IE and Mozilla
  if (ev.altKey && 2 == ev.button) {
    this.sendToBack();
    return false;
  }

  var lbutton = false;
  if (BROWSER_IE_6 == browser || BROWSER_IE_5 == browser
      || BROWSER_SAFARI == browser) // IE and Safari's button mapping (1, 2, 4)
    lbutton = 1 == ev.button;
  else // mozilla and w3c's button mapping (0, 1, 2)
    lbutton = 0 == ev.button;

  // only the left button should have an event
  // likewise we can disable actions by using meta or ctrl+alt
  if (!lbutton || ev.metaKey || (ev.ctrlKey && ev.altKey))
    return true;

  // Determine if we're clicking on the note or a scrollbar
  var pos = findRelativeMousePos(ev);
  var size = this.getCorrectedSize();

  if (!target.clientWidth || // no clientWidth if you click on a scrollbar in FF1.0
      (pos.x > target.clientWidth + noteBorder
       && pos.x < size.x - noteBorder) ||
      (pos.y > target.clientHeight + noteBorder
       && pos.y < size.y - noteBorder)) {
    cancelBubble(ev);
    return;
  }

  this.parent.mouse.select(this, ev);
  cancelBubble(ev);
  return false;
}

/**
 * User clicked on one of the mini notes at the top of the page.
 */
Note.prototype.miniMouseDown = function(ev)
{
  ev = ev || window.event;
  // bring all notes of the same color to the front
  if (ev.ctrlKey) {
    for (var n in this.parent.notes) {
      var note = this.parent.notes[n];
      if (note != this && note.bgColor.toString() == this.bgColor.toString())
        note.select();
    }
  } else if (ev.shiftKey) {
    workspace.filter('couleur:' + colorMap[this.bgColor.toString()]);
  }
  this.select();

  // bring it back if it's off screen
  var size = this.getCorrectedSize();
  var pos = this.getPosition();
  var elt = get(this.id);
  if (size.x + pos.x < 5)
    elt.style.left = "1px";
  if (size.y + pos.y < 5)
    elt.style.top = "1px";
}
/**
 * User deselected a note (stopped dragging).
 */
Note.prototype.mouseUp = function() { this.parent.mouse.deselect();

}
/**
 * Note keyboard events.
 */
Note.prototype.keyDown = function(ev)
{
  // don't do anything if we're editing the note
  if (this.parent.edit == this)
    return;

  // set the color based on number
  var idx = parseInt(String.fromCharCode(ev.keyCode)) - 1;
  if (idx >= 0 && idx < bgColors.length)
    this.setColor(bgColors[idx]);
}
/**
 * Moving the mouse while over a note (changes cursor).
 */
Note.prototype.mouseMove = function(ev)
{
  ev = ev || window.event;
  var elt = get(this.id);
  if (!this.selectable)
  {
    elt.style.cursor = 'auto';
    return;
  }
  if (this.parent.mouse.selObj)
    return;

  if (typeof(ev.layerX) == 'undefined') ev.layerX = ev.offsetX;
  if (typeof(ev.layerY) == 'undefined') ev.layerY = ev.offsetY;

  if (BROWSER_IE_5 == browser || BROWSER_IE_6 == browser) {
    ev.layerX += noteBorder;
    ev.layerY += noteBorder;
  } else if (BROWSER_OPERA == browser) {
    ev.layerX += noteBorder + notePadding;
    ev.layerY += noteBorder + notePadding;
  }

  var top = false;
  var left = false;
  var right = false;
  var bottom = false;
  var resize_cursor = '';
  var size = this.getCorrectedSize();
  if (BROWSER_IE_5 == browser || BROWSER_IE_6 == browser) {
    // We only seem to get events on every other offset value, so we
    // make the threashold bigger for IE
    size.x -= 1;
    size.y -= 1;
  }

  if (ev.layerY <= noteBorder) {
    top = true;
    resize_cursor += 'n';
  } else if (size.y - ev.layerY <= noteBorder) {
    bottom = true;
    resize_cursor += 's';
  }

  if (ev.layerX <= noteBorder) {
    left = true;
    resize_cursor += 'w';
  } else if (size.x - ev.layerX <= noteBorder) {
    right = true;
    resize_cursor += 'e';
  }

  if (resize_cursor == '') {
    elt.style.cursor = 'move';
  } else {
    elt.style.cursor = resize_cursor + '-resize';
  }

  this.parent.mouse.notePosRel['top'] = top;
  this.parent.mouse.notePosRel['bottom'] = bottom;
  this.parent.mouse.notePosRel['left'] = left;
  this.parent.mouse.notePosRel['right'] = right;
}
/**
 * Mouse moves over a note (darken the background color).
 */
Note.prototype.mouseOver = function() {
  var elt = get(this.id);
  elt.style.background = (new Color(this.bgColor.toString())).hsvadj(0, 0, -0.1);
  this.parent.mouse.noteOver = this;
}
/**
 * Mouse leaves a note (restore original background color).
 */
Note.prototype.mouseOut = function() {
	
	
  var elt = get(this.id);
  elt.style.backgroundColor = this.bgColor.toString();
  delete this.parent.mouse.noteOver;
}
/**
 * Double-click event on a note (try to toggle edit mode).
 */
Note.prototype.mouseDblClick = function() {
	

	
  if (!this.editable)
    return;

  if (this.parent.edit == this) {
    this.parent.editOff();
    return;
  }
  this.parent.editOff();
  var pSize = this.getCorrectedSize();
  pSize.x -= 2 * (noteBorder + notePadding + 1);
  pSize.y -= 2 * (noteBorder + notePadding + 1) + 20;
  var html = "<div style='text-align:right;margin: 0 2px 1px 0;'>"

  // color swatches here
  for (var c in bgColors) {
  	if(parseInt(c) < 25 ) {
  		color_title = "appuyer sur "+ (parseInt(c)+1) + " change cette couleur";
  	}else {
  		color_title = "";
  	}
    html += "<div style='width: 12px;height:12px;font-size:1px;float:left;background: "
          + bgColors[c] + ";border: 1px #000 solid; margin:0 1px 1px 0;cursor:auto;' "
          + "onmousedown='workspace.notes." + this.id
          + ".setColor(\"" + bgColors[c] + "\");event.cancelBubble=true;' title='"
          + color_title+"'></div>";
  }
 
  html += "<img onclick='workspace.notes." + this.id
        + ".destroy(true);' src='images/close.gif' alt='fermer fenetre'"
        + " title='click pour detruire une fenetre' style='cursor:auto;border:0;height:12px;width:12px;' />"
        + "</div><textarea wrap='virtual' id='"
        + this.id + "text' style='width:" + pSize.x
        + "px;height:" + pSize.y + "px' onmousedown='event.cancelBubble=true;' ondblclick='event.cancelBubble=true;'>"
        + this.text.replace(/>/g, '&gt;').replace(/</g, '&lt;') + '</textarea>';
  var elt = get(this.id);
  elt.innerHTML = html;
  elt.title = '';
  elt.onselectstart = null;
  elt.style.overflow = 'hidden';
  get(this.id + 'text').focus();
  this.parent.edit = this;
}
/**
 * Destroy the note (user clicked on the X).
 * @param {boolean} addToHistory should we add information to the undo
 * stack?
 */
Note.prototype.destroy = function(addToHistory)
{
  // if it's being edited, turn it off
  if (this.parent.edit == this)
    this.parent.editOff();

  var elt = get(this.id);

  // save undo information
  if (addToHistory)
  {
    var pos = this.getPosition();
    var ws = this.parent;
    var f = {
      title : 'delete note',
      noteData : {
          'id' : this.id,
          'xPos' : pos.x,
          'yPos' : pos.y,
          'height' : this.size.y,
          'width' : this.size.x,
          'bgcolor' : this.bgColor.toString(),
          'zIndex' : elt.style.zIndex,
          'text' : this.text
        },
      undo : function() {
        ws.createNote(this.noteData);
      },
      redo : function() {
        ws.notes[this.noteData.id].destroy(false);
      }
    };
    this.parent.history.add(f);
  }

  // now delete the html node
  elt.parentNode.removeChild(elt);

  // delete the mini html node
  elt = get('m' + this.id);
  elt.parentNode.removeChild(elt);

  // remove it from the array of notes
  delete this.parent.notes[this.id];
  this.parent.numNotes--;
  this.parent.changed = true;

  // resize the mini box and update the stats
  this.parent.updateMiniBox();

  // is the garbage collector smart enough to delete the object now?
}
/**
 * Get the coordinates of the upper left corner of the note.
 * @type Point
 */
Note.prototype.getPosition = function()
{
  var ret = new Point(0, 0);
  var elt = get(this.id);
  ret = new Point(parseInt(elt.style.left), parseInt(elt.style.top));
  return ret;
}
/**
 * Get the size of the note according to the dom object (this varies on
 * browser).
 * @type Point
 */
Note.prototype.getSize = function()
{
  return new Point(this.size.x, this.size.y);
}
/**
 * Get the size of the note including border and padding.
 * @type Point
 */
Note.prototype.getCorrectedSize = function() {
  var ret = this.getSize();

  if (BROWSER_IE_5 != browser) {
    var offset = 2*(noteBorder+notePadding);
    ret.x += offset;
    ret.y += offset;
  }
  return ret;
}

/**
 * Set the color of a note.
 * @param {string} hex the color in hex
 * @param {boolean} ignoreHistory should we add it to the history?
 * Different default values makes this inconsistent with {@link #destroy}
 */
Note.prototype.setColor = function(hex, ignoreHistory)
{
  var newColor = new Color(hex);

  if (!ignoreHistory)
  {
    var f = {
      title : 'change color',
      note : this,
      ucolor : this.bgColor,
      rcolor : newColor,
      undo : function()
      {
        this.note.setColor(this.ucolor.toString(), true);
      },
      redo : function()
      {
        this.note.setColor(this.rcolor.toString(), true);
      }
    }
    this.parent.history.add(f);
  }

  this.bgColor = newColor;

  var elt = get(this.id);
  if (this.parent.mouse.noteOver && this.parent.mouse.noteOver == this)
    elt.style.background = (new Color(this.bgColor.toString())).hsvadj(0, 0, -0.1);
  else
    elt.style.background = this.bgColor.toString();

  get('m' + this.id).style.background = this.bgColor;
}
/**
 * Convert the text of a note to html.  We perform a simple transform of
 * newlines into <br/> and ! into headings.  Other wiki/textile like
 * transforms would happen here.
 * @type string
 */
Note.prototype.getHTML = function() // wikification
{
  var sCopy = this.text.replace(/\n/g,"<br />\n");
  var lines = sCopy.split('\n');
  for (var i = 0; i < lines.length; i++)
  {
    if (lines[i].length > 0)
    {
      // handle headings
      switch(lines[i].charAt(0))
      {
        case '!': // headings
          var c = 0;
          while ('!' == lines[i].charAt(c))
            c++;
          lines[i] = lines[i].substring(c);
          c = Math.min(c, 3); // h3 is the biggest
          c = 4 - c;
          lines[i] = '<h' + c + '>' + lines[i] + '</h' + c + '>';
          break;
        default:
          // lines[i] = lines[i] + '<br />';
      }
    }
  }
  return lines.join('');
}
/**
 * Generate the xml representing a note (used when we save notes).
 * @type string
 */
Note.prototype.toXML = function()
{
  
  
  var ret = "<note noteid='" + this.id + "'";
  ret += " bgcolor='" + this.bgColor + "'";
  ret += " xposition='" + this.getPosition().x + "'";
  ret += " yposition='" + this.getPosition().y + "'";
  ret += " height='" + this.getSize().y + "'";
  ret += " width='" + this.getSize().x + "'";
  ret += " zindex='" + get(this.id).style.zIndex + "'";
  ret += ">\n" + escape(this.text) + "\n";
  return ret + "</note>"
}
/**
 * Change the text of a note.
 * @param {string} str the text for the note.
 */
Note.prototype.setText = function(str)
{
  // convert characters from 160-255 to html codepoints (this provides
  // Safari compatability
  var chars = new Array();
  var i;
  
 
  
  for (i = 0; i < str.length; i++)
  {
    var c = str.charCodeAt(i);
    if (c >= 160 && c <= 255)
      chars.push("&#" + c + ";");
    else
      chars.push(str.charAt(i));
  }
  str = chars.join('');

  if (str != this.text)
  {
    this.parent.changed = true;
    this.text = str;
  }
 
  
  var elt = get(this.id);
  elt.innerHTML = this.getHTML();

  // make images undraggable
  var imgs = elt.getElementsByTagName('img');
  for (i = 0; i < imgs.length; i++) {
    if (BROWSER_IE_6 == browser || BROWSER_IE_5 == browser) {
      imgs[i].unselectable = 'on';
    } else {
      imgs[i].onmousedown = retFalse;
    }
  }

  elt.title = 'double click pour modifier';
  get('m' + this.id).title = str;
}
/**
 * We keep track of the size of the note internally; this method updates
 * that value.
 */
Note.prototype.updateSize = function()
{
  var elt = get(this.id);
  this.size.x = parseInt(elt.style.width);
  this.size.y = parseInt(elt.style.height);
}
/**
 * Disable a note (can't be moved or edited).
 */
Note.prototype.disable = function()
{
  this.selectable = this.editable = false;
  var elt = get(this.id);
  elt.title = '';
}
/**
 * Enable a note (can be moved and edited).
 */
Note.prototype.enable = function()
{
  this.selectable = this.editable = true;
  var elt = get(this.id);
  elt.title = 'double click pour modifier';
}
/**
 * When a note is selected from the mini note toolbar, we bring it to the
 * front and flash the background.
 */
Note.prototype.select = function()
{
  this.parent.reZOrder(this.id);
  var self = this;
  var elt = get(this.id);
  elt.style.backgroundColor = (new Color(this.bgColor.toString()))
                                   .hsvadj(0, 0, -0.1);
  // make a new layer with the name
  var d = document.createElement('div');
  d.innerHTML = this.id;
  d.style.position = 'absolute';
  d.style.top = (parseInt(elt.style.top) + 5) + 'px';
  d.style.left = (parseInt(elt.style.left) + 5) + 'px';
  d.style.zIndex = 1000;
  d.style.backgroundColor = '#fff';
  d.style.padding = '4px';
  d.style.opacity = 0.8;
  get('content').appendChild(d);

  setTimeout(function() {
    elt.style.backgroundColor = self.bgColor.toString();
    d.parentNode.removeChild(d);
  }, 500);
}
/**
 * Send a note to the back of the workspace.
 */
Note.prototype.sendToBack = function()
{
  var elt = get(this.id);
  elt.style.zIndex = 0;
  this.parent.reZOrder();
}
/**
 * Move the note relative to its current position.
 * @param {Point} delta a point object
 */
Note.prototype.move = function(delta) {
  var newpos = this.getPosition().add(delta);
  var elt = get(this.id);
  elt.style.left = newpos.x + 'px';
  elt.style.top = newpos.y + 'px';
}

/**
 * Determine which note is above which other note.  Used when re-stacking
 * notes.  Returns -1 if a is below b, +1 if a is above b, and 0 if they
 * have the same z value.
 * @param {Note} a
 * @param {Note} b
 * @type int
 */
function cmpNotesZ(a, b)
{
  var av = parseInt(get(a.id).style.zIndex);
  var bv = parseInt(get(b.id).style.zIndex);
  if (av < bv)
    return -1;
  if (av > bv)
    return 1;
  return 0;
}

//
// Mouse objects
//

/**
 * @class A class that tracks the mouse position and handles mouse events.
 * @constructor
 */
var Mouse =
{
  /**
   * When resizing a note, this determines which edges need to be moved and
   * which edges remain fixed.  It is a dictionary from string -> boolean
   * where the string is either 'top, 'right', 'bottom' or 'left' and true
   * means the edge is moving.
   * @see Note#mouseMove
   * @type dictionary
   */
  notePosRel : {},
  /**
   * The current location of the mouse.  We initialize it to a dummy value
   * because object.js probably hasn't loaded yet (and Point is undefined).
   * It actually gets set in {@link GLOBALS#init}
   * @type Point
   */
  curPos : 0,

  /**
   * Update the mouse position and resize/move notes if necessary.
   * @param {int} x x position
   * @param {int} y y position
   */
  update : function(x, y)
  {
    this.curPos.x = x;
    this.curPos.y = y;

    // if something is selected
    if (this.selObj)
      this.selObj.update(this);
  },
  /**
   * Select a note either for dragging or for resizing.
   * @param {Note} note the selected note
   * @param {event} ev the javascript event object
   */
  select : function(note, ev) {
    if (this.selObj) // something already selected
      return;

    if (get(note.id).style.cursor != "move")
      this.selObj = new SelectedObjectResize(note, this.notePosRel);
    else
    {
      if (ev.altKey)
      {
        this.selObj = new SelectedObjectResize(note,
              {'top': false, 'bottom':true, 'left':false, 'right':true});
      }
      else if (ev.ctrlKey)
        this.selObj = new SelectedObjectDrag(note, true)
      else
        this.selObj = new SelectedObjectDrag(note, false);
    }
    this.downPos = this.curPos.copy();

    // move the selected item to the top
    workspace.reZOrder(note.id);
  },
  /**
   * Release selected notes.
   */
  deselect : function()
  {
    if (this.selObj)
    {
      this.selObj.deselect();
      delete this.selObj;
    }
  }
};


/**
 * Create a new Dragging object.
 * @class A class that contains information about note(s) that is being
 * dragged.
 * @see Mouse#select
 * @param {Note} note a reference to the note being dragged
 * @param {boolean} isGroup are we dragging all notes of the same color?
 * @constructor
 */
function SelectedObjectDrag(note, isGroup)
{
  /**
   * The note(s) being dragged.
   * @type Array
   */
  this.notes = new Array();

  // if ctrl is down, move all the notes of the same color
  if (isGroup)
  {
    for (var n in workspace.notes)
    {
      if (workspace.notes[n].bgColor.toString() == note.bgColor.toString())
      {
        this.notes.push( { 'id' : workspace.notes[n].id,
              'pos' : workspace.notes[n].getPosition() } );
      }
    }
  }
  else // single note move
    this.notes.push( { 'id' : note.id, 'pos' : note.getPosition() } );

  // set the border color of the notes that are being moved
  var elt;
  for (n in this.notes)
  {
    elt = get(this.notes[n].id);
    elt.style.border =  noteBorder + 'px #980000 solid';
  }
}
/**
 * Update the position of note(s) when the user moves the mouse.
 * @param {Mouse} md a reference to the parent mouse object
 */
SelectedObjectDrag.prototype.update = function(md)
{
  var offset = md.curPos.sub(md.downPos);
  var elt;
  for (n in this.notes) {
    elt = get(this.notes[n].id);
    var newPos = this.notes[n].pos.add(offset);
    elt.style.left = newPos.x + 'px';
    elt.style.top = newPos.y + 'px';
    if (BROWSER_MOZILLA == browser) {
      // this is a hack to force ffx to resize the content div
      var c = get('content');
      var d = document.createElement('span');
      c.appendChild(d);
      c.removeChild(d);
    }
  }
};
/**
 * When we drop a note, we need to reset the colors of borders and add
 * information to the undo stack.
 */
SelectedObjectDrag.prototype.deselect = function()
{
  // check to see if we moved the object(s). if we did, add
  // information to the undo stack.
  var md = workspace.mouse;
  var offset = md.curPos.sub(md.downPos);
  if (!offset.equals(new Point(0, 0)))
  {
    var f = {
      title : 'Deplace',
      notes : this.notes,
      off : offset,
      undo : function()
      {
        var elt;
        for (n in this.notes)
        {
          elt = get(this.notes[n].id);
          pos = this.notes[n].pos;
          elt.style.left = pos.x + 'px';
          elt.style.top = pos.y + 'px';
        }
      },
      redo : function()
      {
        var elt;
        for (n in this.notes)
        {
          elt = get(this.notes[n].id);
          pos = this.notes[n].pos.add(this.off);
          elt.style.left = pos.x + 'px';
          elt.style.top = pos.y + 'px';
        }
      }
    };

    workspace.history.add(f);
  }
  // reset the border color to black
  var elt;
  for (var n in this.notes)
  {
    elt = get(this.notes[n].id);
    elt.style.border =  noteBorder + 'px ' + noteBorderColor + ' solid';
  }
};


// inheritance might be useful here
/**
 * Create a new Resizing object.
 * @class A class that contains information about a note being resized.
 * @see Mouse#select
 * @param {Note} note a reference to the note being dragged
 * @param {dictionary} pnotePosRel which edges are being resized? It is
 * a dictionary from string -> boolean where the string is either
 * 'top, 'right', 'bottom' or 'left' and true means the edge is moving.
 * @constructor
 */
function SelectedObjectResize(note, pnotePosRel)
{
  /**
   * The note being resized
   * @type Note
   */
  this.note = note;
  /**
   * The original size of the note
   * @type Point
   */
  this.size = note.getSize();
  /**
   * The original position of the note
   * @type Point
   */
  this.pos = note.getPosition();
  /**
   * The edges being moved.
   * @type dictionary
   */
  this.edges = pnotePosRel;
}
/**
 * Update the size of the note when the user moves the mouse.
 * @param {Mouse} md a reference to the parent Mouse object
 */
SelectedObjectResize.prototype.update = function(md)
{
  var elt = get(this.note.id);

  // this depends on which edge they grabbed
  var minSize = 10;
  var offset = md.curPos.sub(md.downPos);
  if (this.edges['top'])
  {
    if (this.size.y - offset.y > minSize)
    {
      elt.style.top = (this.pos.y + offset.y) + 'px';
      elt.style.height = (this.size.y - offset.y) + 'px';
    }
  }
  else if (this.edges['bottom'])
    elt.style.height = Math.max(this.size.y + offset.y, minSize) + 'px';

  if (this.edges['left'])
  {
    if (this.size.x - offset.x > minSize)
    {
      elt.style.left = (this.pos.x + offset.x) + 'px';
      elt.style.width = (this.size.x - offset.x) + 'px';
    }
  }
  else if (this.edges['right'])
    elt.style.width = Math.max(this.size.x + offset.x, minSize) + 'px';

  if (this.note.parent.edit == this.note)
  {
    var edit = get(this.note.id + 'text');
    var pSize = this.note.getCorrectedSize();
    pSize.x -= 2*(noteBorder+notePadding+1);
    pSize.y -= 2*(noteBorder+notePadding+1) + 16;
    edit.style.height = Math.max(pSize.y, 10) + 'px';
    edit.style.width = Math.max(pSize.x, 10) + 'px';
  }

  this.note.updateSize();
};
/**
 * Add information to the undo stack when the user stops resizing.
 */
SelectedObjectResize.prototype.deselect = function()
{
  // add information to the undo stack if the item was resized
  var curSize = this.note.getSize();

  if (!this.size.equals(curSize))
  {
    var f = {
      title : 'resize note',
      usize : this.size,
      upos : this.pos,
      rsize : curSize,
      rpos : this.note.getPosition(),
      id : this.note.id,
      undo : function()
      {
        this.set(this.usize, this.upos);
      },
      redo : function()
      {
        this.set(this.rsize, this.rpos);
      },
      set : function(size, pos)
      {
        var elt = get(this.id);
        elt.style.top = pos.y + 'px';
        elt.style.left = pos.x + 'px';
        elt.style.height = size.y + 'px';
        elt.style.width = size.x + 'px';
        workspace.notes[this.id].updateSize();
      }
    };
    workspace.history.add(f);
  }
};


/**
 * @class A class that maintains the undo/redo stacks.
 */
var History =
{
  /**
   * The number of items to keep in the undo stack.
   * @type int
   */
  maxSize : 40,
  /**
   * @type Array
   */
  undoStack : new Array(), // each item in the array is an object
  /**
   * @type Array
   */
  redoStack : new Array(), // with methods called undo and redo

  /**
   * Add an event to the undo stack.  This clears the redo stack.
   * @param {function} funcPtr a closure that when called will
   * undo the last action
   */
  add : function(funcPtr)
  {
    this.redoStack = new Array();
    this.undoStack.push(funcPtr);
    if (this.undoStack.length > this.maxSize)
      this.undoStack.shift();
    this.updateTitles();
  },
  /**
   * Undo the last action and move an item from the undo stack to the
   * redo stack.
   */
  undo : function()
  {
    if (this.undoStack.length > 0)
    {
      var f = this.undoStack.pop();
      this.redoStack.push(f);
      f.undo();
      this.updateTitles();
    }
  },
  /**
   * Redo the last undo action.  Moves the action back to the undo stack.
   */
  redo : function()
  {
    if (this.redoStack.length > 0)
    {
      var f = this.redoStack.pop();
      this.undoStack.push(f);
      f.redo();
      this.updateTitles();
    }
  },
  /**
   * Update the tool tips on the undo and redo icons.
   */
  updateTitles : function()
  {
    var elt = get('undoImg');
    if (0 == this.undoStack.length)
    {
      elt.title = 'Aucune action précédente';
      elt.className = 'controlsDisabled';
      elt = get('saveImg');
      elt.className = 'controlsDisabled';
    }
    else
    {
      elt.title = this.undoStack[this.undoStack.length-1].title
          + ' (' + this.undoStack.length + ' action(s))';
      elt.className = 'controls';
      elt = get('saveImg');
      elt.className = 'controls';
    }
    elt = get('redoImg');
    if (0 == this.redoStack.length)
    {
      elt.title = 'Rien à refaire';
      elt.className = 'controlsDisabled';
    }
    else
    {
      elt.title = this.redoStack[this.redoStack.length-1].title
          + ' (' + this.redoStack.length + ' action(s))';
      elt.className = 'controls';
    }
  }
};

//
/**
 * @class A generator class that returns the position of the next new note.
 */
var NotePos =
{
  /**
   * @type int
   */
  x : 170,
  /**
   * @type int
   */
  y : 40,
  /**
   * Compute the position of a new note given the size of the note.
   * @param {int} w the width of the new note
   * @param {int} h the height of the new note
   * @type Point
   */
  nextPos : function(w, h) {
    var ret = new Point(this.x, this.y);

    this.x += 20;
    this.y += 20;
    var s = getPageSize();

    if (this.x + w > s.x || this.y + h > s.y) {
      this.x = 40;
      this.y = 40;
    }

    return ret;
  }
};


/**
 * @class A class that represents the workspace.  This includes maintaining
 * information about the notes and undo/redo information.
 */
var workspace =
{
  /**
   * A dictionary of all the notes.
   * @type dictionary
   */
  notes : {},
  /**
   * When creating new notes, we sometimes need to assign a random name to
   * it.  The first random note is note0, the second is note1, etc.
   * @type int
   */
  nextNoteNum : 0,
  /**
   * Number of notes on the workspace.  We keep this as a separate variable
   * since there's no way to determine the size of a dictionary.
   * @type int
   */
  numNotes : 0,
  /**
   * The last time that we loaded this workspace (used to check for update
   * collision).
   * @type int
   */
  loadedTime : 0,
  /**
   * Have we changed the workspace?
   * @type boolean
   */
  changed : false,
  /**
   * The note we are editing.
   * @type Note
   */
  edit : '',
  /**
   * The name of the workspace.
   * @type string
   */
  name : 'Untitled',


  /**
   * @type History
   */
  history : History,
  /**
   * @type NotePos
   */
  notePos : NotePos,
  /**
   * @type Mouse
   */
  mouse : Mouse,
  /**
   * Mouse down position on the document.
   * @type Point
   */
  mouseDown : null,
  /**
   * Should keyboard shortcuts work?
   * @type boolean
   */
  shortcuts : true,
  /**
   * The id of the note on top.
   * @type string
   */
  topId: '',
  /**
   * How frequently we check for changes.
   */
  updateInterval: 1000*60*10,

  /**
   * Create a new note. Any of the parameter values may be left blank
   * and default values will be used.
   * @param {dictionary} note a dictionary with any of the following keys:
   * note['id'] = the name of the note<br />
   * note['xPos'] = the x position of the note<br />
   * note['yPos'] = the y position of the note<br />
   * note['height'] = the height of the note<br />
   * note['width'] = the width of the note<br />
   * note['bgcolor'] = the background color of the note (hex)<br />
   * note['zIndex'] = the stacking position of the note<br />
   * note['text'] = the text value of the note<br />
   */
  createNote : function(note, skipFilter) {
    if (!note)
      note = {};
    if (!('id' in note)) {
      note.id = "note" + this.nextNoteNum;

      // a new note is being made, save information to the undo stack
      var self = this;
      var f = {
        title : 'Créer une fenêtre',
        nnn : this.nextNoteNum,
        id : note.id,
        pos : new Point(this.notePos.x, this.notePos.y),
        undo : function()
        {
          self.notes[this.id].destroy(); // don't add to history
          self.nextNoteNum = this.nnn;
        },
        redo : function()
        {
          self.createNote({'id': this.id, 'xPos' : this.pos.x,
              'yPos' : this.pos.y});
          self.nextNoteNum++;
        }
      };
      this.history.add(f);

      this.nextNoteNum++;
    }

    // don't create a layer if it already exists, just move it to the top
    if (get(note.id))
    {
      this.reZOrder(note.id);
      return note;
    }

    if (!('height' in note)) note.height = 350;
    if (!('width' in note)) note.width = 350;

    var pos;
    if (!('xPos' in note) || !('yPos' in note)) {
      pos = this.notePos.nextPos(note.width, note.height);
    }
    if (!('xPos' in note)) note.xPos = pos.x;
    if (!('yPos' in note)) note.yPos = pos.y;

    if (!('bgcolor' in note)) note.bgcolor = bgColors[0].toString();

    if (!('text' in note)) note.text = '';

    // disable editing of a different note
    this.editOff();

    var newDiv = document.createElement('div');
    newDiv.className = 'note';
    newDiv.id = note.id;
    // work around a safari bug
    if (BROWSER_SAFARI == browser) {
      newDiv.style.opacity = '0.99';
      newDiv.style.overflow = 'hidden';
    }
    get('content').appendChild(newDiv);

    //document.body.innerHTML += newDiv;
    var elt = get(note.id);
    elt.style.backgroundColor = note.bgcolor;
    elt.style.width = note.width + 'px';
    elt.style.height = note.height + 'px';
    elt.style.left = note.xPos + 'px';
    elt.style.top = note.yPos + 'px';
    elt.style.padding = notePadding + 'px';
    elt.style.position = 'absolute';
    elt.style.border = noteBorder + 'px ' + noteBorderColor + ' solid';

    if (!('zIndex' in note)) {
      this.reZOrder();
      elt.style.zIndex = this.numNotes + 1;
      this.topId = note.id;
    } else {
      elt.style.zIndex = note.zIndex;
      var topElt = get(this.topId);
      if (topElt) {
        if (parseInt(note.zIndex) > parseInt(topElt.style.zIndex)) {
          this.topId = note.id;
        }
      } else {
        this.topId = note.id;
      }
    }
    this.numNotes++;
    var nNote = new Note(elt, this, note.text);
    this.notes[nNote.id] = nNote;

    newDiv.onmouseover = hitch(nNote, nNote.mouseOver);
    newDiv.onmouseout = hitch(nNote, nNote.mouseOut);
    newDiv.onmousedown = hitch(nNote, nNote.mouseDown);
    newDiv.onmouseup = hitch(nNote, nNote.mouseUp);
    newDiv.onmousemove = hitch(nNote, nNote.mouseMove);
    newDiv.ondblclick = hitch(nNote, nNote.mouseDblClick);
    newDiv.onselectstart = retFalse;
    newDiv.title = 'double click pour modifier';

    if (!skipFilter) {
      this.filter('');
    } else {
      // this normally gets called by filter
      workspace.updateMiniBox();
    }

    return nNote;
  },
  /**
   * Mouse up action on the workspace.
   */
  mouseUp : function() {
    if (this.mouse.selObj) {
      this.mouse.selObj.deselect();
      delete this.mouse.selObj;
    }
    // stop dragging the document
    this.mouseDown = null;
  },

  docMove : function(x, y) {
    if (this.mouseDown) {
      var offX = this.mouseDown.x - x;
      var offY = this.mouseDown.y - y;
      var content = get('content');
      content.scrollTop += offY;
      content.scrollLeft += offX;
      this.mouseDown.x = x;
      this.mouseDown.y = y;
    }
  },

  /**
   * If we are editing any note, stop editing.
   */
  editOff : function()
  {
	  
	  
    if (this.edit)
    {
      var textbox = get(this.edit.id + 'text');
	  textbox.parentNode.onselectstart = retFalse;
      if (BROWSER_SAFARI != browser) {
        textbox.parentNode.style.overflow = 'auto';
      }

      // check to see if the text changed.  add to the
      // undo stack if it did.
	  
	    if (textbox.value.length >maxtaillefenetre) alert('la taille maximale possible du texte est de '+ maxtaillefenetre + ' caractères') ; 
	   
	  

      if (textbox.value != this.edit.text)
      {
        var f = {
          title : 'Modifier une fenêtre',
          utext : this.edit.text,
          rtext : textbox.value,
          note : this.edit,
          undo : function()
          {
            this.note.setText(this.utext);
          },
          redo : function()
          {
            this.note.setText(this.rtext);
          }
        };
        this.history.add(f);
      }

      this.edit.setText(textbox.value);
      this.edit = '';
    }
  },
  /**
   * Resort the notes and place topNoteID in front.
   * @param {string} topNoteID the name of the note to bring to the front.
   */
  reZOrder : function(topNoteID) {
    if (this.notes) {
      // it's not possible to sort an associative array
      // so we copy it into a regular array first
      var nArray = new Array();
      var i = 0;
      for (var nid in this.notes) {
        nArray[i] = this.notes[nid];
        ++i;
      }

      nArray.sort(cmpNotesZ);

      // set zIndex based on order
      var found = 0;
      for (i = 0; i < nArray.length; ++i) {
        if (nArray[i].id == topNoteID) {
          found = 1;
          get(nArray[i].id).style.zIndex = this.numNotes;
          this.topId = nArray[i].id;
        }
        else
          get(nArray[i].id).style.zIndex = i + 1 - found;
      }
    }
  },

  /**
   * Set the name of the workspace.  NOTE: this changes where notes get
   * saved.
   * @param {string} n the new name
   */
   
  setName : function(n)
  {
    this.name = n;
    var elt = get('wsname');
    elt.innerHTML = this.name;
  },
 

 
  
/**
   * This function acts as an "Expose`" like feature for the notes
   * It sets all of the notes to relative positioning and then grabs
   * the relative location, sets its "top" and "left" properties then
   * resets the positioning to absolute. -sph
   *
   * original patch submitted by Sean Hannan
   *
   * This isn't quite ready for release.
   */
  expose : function(zoom) {
    var n, style;
    for (n in this.notes) { //loop through the notes
      var note = this.notes[n];
      var elt = get(note.id);  // get the div
      style = elt.style; //get the note's style

      // save old values

	  note.lastX = style.left;
      note.lastY = style.top;
      note.lastWidth = style.width;
      note.lastHeight = style.height;

      //Set the styles so that the notes nicely tile
      style.position = 'relative';
      style.margin = '5px';
      style.left = '';
      style.top = '';
	
      style.cssFloat = 'left';
      style.styleFloat = 'left';
      style.display = '';
      style.width = parseInt(exposeSize / (100.0 * zoom) * parseInt(style.width)) + 'px';
	  
      style.height = parseInt(exposeSize / (100.0 * zoom) * parseInt(style.height)) + 'px';
     // style.fontSize = exposeSize + '%';

      //get and set the position of the div
      var pos = findPos(elt);
      style.left = pos.x + 'px';
      style.top = pos.y + 'px';
	  
    }
    //loop through again to make it absolute.
    for (n in this.notes) {
      style = get(this.notes[n].id).style;
      style.position = 'absolute';
      style.cssFloat = 'none';
      style.styleFloat = 'none';
      style.margin = '';
    }
  },
  
   zoom : function(zam) {
    for (var n in this.notes) {  //loop through notes
      var note = this.notes[n];
      var style = get(note.id).style; //get the Div

      // restore values
      //style.top = note.lastY;
      //style.left = note.lastX;
	    style.width = parseInt(exposeSize / (100.0 * zam) * parseInt(style.width)) + 'px';
	  
      style.height = parseInt(exposeSize / (100.0 * zam) * parseInt(style.height)) + 'px';
 
	  
	  
      //style.width = note.lastWidth;
      //style.height = note.lastHeight;
      style.fontSize = '100%';
    }
  },

unzoom : function(zam) {
    for (var n in this.notes) {  //loop through notes
      var note = this.notes[n];
      var style = get(note.id).style; //get the Div

      // restore values
      //style.top = note.lastY;
      //style.left = note.lastX;
	  style.width = parseInt(exposeSize * zam + parseInt(style.width)) + 'px';
	  
      style.height = parseInt(exposeSize * zam + parseInt(style.height)) + 'px';
 
	  
	  
      //style.width = note.lastWidth;
      //style.height = note.lastHeight;
      style.fontSize = '100%';
    }
  },

  _expose : function(zam) {
    for (var n in this.notes) {  //loop through notes
      var note = this.notes[n];
      var style = get(note.id).style; //get the Div

      // restore values
      style.top = note.lastY;
      style.left = note.lastX;
	   	  
	  
      style.width = note.lastWidth;
      style.height = note.lastHeight;
      style.fontSize = '100%';
    }
  },

  /**
   * Filter the visible notes (kind of like a search).  Notes that match
   * the regular expression are moved to the front while other notes are
   * disabled and become mostly transparent.
   * @param {string} text the regular expression to filter by
   */
  filter : function(text) {
    var shouldHide;
    if (text.trim().substring(0, 8) == 'couleur:') {
      var color = text.trim().substring(8);
      shouldHide = function(note) {
        return (colorMap[note.bgColor.toString()] == color);
      };
    }
    else {
      var reg = new RegExp(text, 'i');
      shouldHide = function(note) {
        return reg.test(note.text);
      };
    }

    for (n in this.notes) {
      var note = this.notes[n];
      var elt = get(note.id);
      if (shouldHide(note)) {
        elt.className = 'note';
        if (BROWSER_SAFARI == browser) elt.style.opacity = '0.99';
        if (BROWSER_IE_5 == browser) elt.style.visibility = 'visible';
        note.enable();
        get('m' + note.id).className = 'mininote';
      } else {
        elt.className = 'noteHide';
        elt.style.zIndex = 0;
        if (BROWSER_SAFARI == browser) elt.style.opacity = '0.2';
        if (BROWSER_IE_5 == browser) elt.style.visibility = 'hidden';
        note.disable();
        get('m' + note.id).className = 'mininote noteHide';
      }
    }
    get('textfilter').value = text;
    this.reZOrder();
    this.updateMiniBox();
  },
  /**
   * Update the background color and tool tips of the mini notes.
   */
  updateMiniBox : function() {
    var mini = get('mini');
    var vNotes = 0;
    var total = 0;

    for (n in this.notes) {
      ++total;
      var tmp = new Color(get('m' + n).style.backgroundColor);
      if (!(0 == tmp.r && 0 == tmp.g && 0 == tmp.b))
        ++vNotes;
    }

    // Set the width of the mini div.
    // After the first 9 notes, we add space for additional notes
    // 10 is the width of a note.
    var miniNoteWidth = 10;
    if (BROWSER_IE_5 == browser) miniNoteWidth = 8; // width in IE5.5
    var diff = parseInt(Math.max(0, total - 9) / 2) * miniNoteWidth;
    mini.style.width = (diff + miniWidth) + 'px';

    if (0 == total)
      mini.title = 'Pas de notes';
    else if (vNotes == total)
      mini.title = 'Montre ' + total + ' fenêtre(s)';
    else if (0 == vNotes)
      mini.title = 'cache ' + total + ' fenêtre(s)';
    else
      mini.title = 'montre ' + vNotes + ' sur un total de ' + total + ' fenêtre(s) ('
            + parseInt(100 * vNotes / total) + '%)';
  },
  
  
  loadhelp: function()
 
 
 { this.createNote( {
      'id' : 'aide',
      'height' : '500',
      'width' : '500',
      'bgcolor' : '#A999B5'
    } );
   var txt =  unescape('%3Cb%3E%3Ccenter%3EBIENVENUE%20SUR%20L%27AIDE%20EN%20LIGNE%3C/b%3E%0D%0A%0D%0A%3Cinput%20type%3D%22button%22%20value%20%3D%20%22editeur%22%20onclick%3D%22%20javascript%3Aworkspace.createNote%28%7B%27id%27%3A%27editeur%27%2C%20%27xPos%27%3A%20%2750%27%2C%20%27yPos%27%3A%20%27150%27%2C%27height%27%3A%27350%27%2C%27width%27%3A%20%27500%27%2C%27bgcolor%27%3A%20%27%23CCCCCC%27%2C%27text%27%3A%20%27%3Ctextarea%20id%20%3D%20textarea%20name%3Dtextarea%3E%3C/textarea%3E%27%7D%29%3Bgenerate_wysiwyg%28%27textarea%27%29%3B%22%3B%0D%0A%3Cinput%20type%3D%22button%22%20onclick%3D%22javascript%3A%20if%20%28workspace.notes%5B%27fondecran%27%5D%20%21%3D%20null%29%20workspace.notes.fondecran.destroy%28true%29%3Bworkspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%2Cid%3A%27fondecran%27%2CxPos%3A1500%2CyPos%3A1500%2Cheight%3A1%2Cwidth%3A1%7D%29%22%20value%3D%22fondecran%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%7D%29%22%20value%3D%22tchat-1400cm3%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%2Cheight%3A400%2Cwidth%3A800%7D%29%22%20value%3D%22un%20site%20web%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%2Cheight%3A500%2Cwidth%3A400%7D%29%22%20value%3D%22Commentaires%20perso%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%2Cheight%3A50%2Cwidth%3A150%7D%29%22%20value%3D%22Email%20perso%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%2Cheight%3A500%2Cwidth%3A400%7D%29%22%20value%3D%22Commentaires%201400cm3%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%2Cheight%3A50%2Cwidth%3A150%7D%29%22%20value%3D%22heure%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%7D%29%22%20value%3D%22flux%20rss%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%7D%29%22%20value%3D%22flux%20rss%201400cm3%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%2Cheight%3A450%2Cwidth%3A450%7D%29%22%20value%3D%22google%20map%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%2Cheight%3A450%2Cwidth%3A450%7D%29%22%20value%3D%22news%20map%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%2Cheight%3A100%2Cwidth%3A150%7D%29%22%20value%3D%221400cm3%20Ami%22/%3E%3Cinput%20type%3D%22button%22%20onclick%3D%22workspace.createNote%28%7B%27text%27%3A%20eval%28workspace.notes%5B%27aidecode%27%5D.text%29%2Cheight%3A600%2Cwidth%3A600%7D%29%22%20value%3D%22telecharger%20un%20document%20%28photo%2C%20video%2Cmp3%2Ctxt%29%22/%3E%0D%0A%3C/center%3E%0D%0A%0D%0A%0D%0A%3Ccenter%3E%3Cb%3EIci%20vous%20trouverez%20tout%20pour%20am%26%23233%3Bliorer%20votre%201400cm3.%3C/center%3E%3C/b%3E%0D%0ALe%20principe%20g%26%23233%3Bn%26%23233%3Bral%20est%20%20celui%20de%20la%20fen%26%23234%3Btre.%0D%0AEn%20cliquant%20sur%20%20%20%3Cimg%20id%3D%22newImg%22%20src%3D%27images/new.gif%27%20class%3D%27controls%27%20onclick%3D%22workspace.createNote%28%29%22%20title%3D%22Nouvelle%20fen%26%23234%3Btre%22%20alt%3D%27new%20note%27%20/%3E%2C%20vous%20allez%20ouvrir%20une%20fen%26%23234%3Btre%20vierge.%20%0D%0AVous%20pouvez%20la%20d%26%23233%3Bplacer%20et%20l%27aggrandir%20comme%20une%20fen%26%23234%3Btre%20MAC%20ou%20WINDOWS.%0D%0AEn%20cliquant%202%20fois%20dessus%2C%20vous%20pourrez%20mettre%20du%20texte%20simple%20ou%20du%20code%20html%20ou%20javascript.%0D%0A%0D%0AUne%20s%26%23233%3Brie%20de%20modules%20fonctionnels%20%28widget%29%20est%20disponible%3A%20Cliquez%20sur%20chaque%3C/center%3E%20bouton%20ci%20dessus%20pour%20les%20activer.%0D%0AN%27oubliez%20pas%20que%20le%20principe%20est%20celui%20du%20copier/coller%20d%27une%20fen%26%23234%3Btre%20%26%23224%3B%20une%20autre%2C%20sachant%20que%20l%27on%20peut%20additionner%20ces%20codes%20dans%20une%20m%26%23234%3Bme%20fen%26%23234%3Btre.Donc%20n%27h%26%23233%3Bsitez%20pas%20%26%23224%3B%20double-cliquez%20sur%20une%20fen%26%23234%3Btre%20pour%20reprendre%20un%20exemple%20et%20le%20modifier.%0D%0A%0D%0A%0D%0A%3Cb%3E%3Ccenter%3ECette%20librairie%20s%27am%26%23233%3Bliore%20de%20jour%20en%20jour%20dans%20l%27atelier%20des%201400cm3%3C/b%3E%0D%0A%0D%0A%3Ccenter%3E%3Cform%20%20name%3Dform1%20method%3Dpost%20action%3Dhttp%3A//1400cm3.net/atelier-1400cm3%20target%3D_blank%20%3E%20%20%3Clabel%3E%20%3Cinput%20type%3Dsubmit%20name%3DSubmit%20value%3D%22Voir%20atelier%20des%201400cm3%22%20/%3E%20%20%20%20%20%20%20%20%20%20%3C/label%3E%3C/form%3E%3C/center%3E%0D%0A%0D%0A%3Cb%3E%3Ccenter%3EFAQ%3C/b%3E%3C/center%3E%0D%0A%0D%0A%3Cb%3EComment%20cr%26%23233%3Ber%20un%201400cm3%20%3F%3C/b%3E%0D%0AEntrez%20%20le%20nom%20du%201400cm3%2C%20un%20mot%20de%20passe%20et%20un%20email%3B%20Vous%20allez%20recevoir%20un%20email%20de%20confirmation%20%26%23224%3B%20valider%20%21%20Et%20voil%26%23224%3B%20%21%0D%0A%0D%0A%3Cb%3EQuelle%20est%20l%27adresse%20internet%20de%20mon%201400cm3%20%3F%3C/b%3E%0D%0ALa%20cr%26%23233%3Bation%20d%27un%201400cm3%20donne%20une%20adresse%20internet%20%28Une%20URL%29%20unique%20qui%20vous%20permet%20de%20le%20partager%20avec%20d%27autres%20ou%20de%20l%27integrer%20sur%20votre%20site%20perso.%20Cette%20adresse%20est%20dans%20le%20mail%20de%20confirmation%20que%20vous%20recevez%20%26%23224%3B%20la%20cr%26%23233%3Bation%3B%20Il%20a%20la%20forme%20suivante%3A%0D%0A%3Cb%3Ehttp%3A//1400cm3.net/nomdevotre1400cm3/%0D%0A%3C/b%3E%0D%0A%0D%0A%3Cb%3EQuelle%20est%20le%20fil%20rss%20de%20mon%201400cm3%3F%3C/b%3E%0D%0AVous%20pouvez%20cr%26%23233%3Bez%20un%20fil%20rss%20de%20votre%201400cm3%2C%20soit%20en%20cliquant%20sur%20ce%20bouton%20%3Cimg%20src%3D%22/images/minixml.gif%22%20width%3D%2219%22%20height%3D%229%22%20/%3E%20dans%20la%20barre%20haute%2C%20soit%20dans%20l%27aide%20en%20cliquant%20sur%20le%20bouton%20%27flux%20rss%20perso%27.%0D%0A%0D%0AD%27une%20mani%26%23232%3Bre%20g%26%23233%3Bn%26%23233%3Brale%2C%20l%27adresse%20de%20votre%20flux%20rss%20est%20de%20cette%20forme%20%3A%20%0D%0A%3Cb%3Ehttp%3A//1400cm3.net/rss.php%3Fname%3Dlenomdevotre1400cm3%3C/b%3E%0D%0A%0D%0A%0D%0A%3Cb%3EQu%27est-que%20l%27historique%3F%3C/b%3E%0D%0AL%27historique%20permet%20de%20sauvegarder%20l%27ensemble%20de%20votre%201400cm3%20%26%23224%3B%20une%20date%20donn%26%23233%3Be...en%20cliquant%20sur%20%20%3Cimg%20id%3D%22reloadImg%22%20src%3D%27images/timestamp.png%27%20class%3D%27controls%27%20onclick%3D%22workspace.loadlist%28%29%22%20title%3D%22Historique%20des%20versions%22%20alt%3D%27Historique%20des%20versions%27%20/%3E%2C%20vous%20pouvez%20revenir%20%26%23224%3B%20une%20version%20ant%26%23233%3Brieure%20de%20votre%201400cm3.%0D%0A%0D%0A%3Cb%3EQuelles%20sont%20les%20limites%20actuelles%20%3F%3C/b%3E%0D%0AJusqu%27%26%23224%3B%2050%20fen%26%23234%3Btres%20par%20espace%20et%20250%20fen%26%23234%3Btres%20en%20totalisant%20les%20historiques.Chaque%20fen%26%23234%3Btre%20peut%20contenir%20jusqu%27%26%23224%3B%2010000%20caract%26%23232%3Bres.%20Si%20vous%20saturez%2C%20purgez%20l%27historique%20votre%201400cm3.%0D%0A%0D%0A%3Cb%3EPour%20des%20besoins%20plus%20importants%20%3Ca%20href%3D%22mailto%3Ainfos@1400cm3.net%22%3Evous%20pouvez%20m%27%26%23233%3Bcrire%3C/a%3E%3C/b%3E%0D%0A%0D%0A%3Cb%3EComment%20rendre%20son%201400cm3%20public%20%3F%3C/b%3E%0D%0ADans%20le%20menu%20principal%2C%20choisir%20l%27option%20rendre%20visible%2C%20votre%201400cm3%20sera%20visible%20dans%20le%20menu%20%28liste%201400cm3%20publics%29%20%26%23224%3B%20la%20prochaine%20connexion.%0D%0A%0D%0A%3Cb%3EComment%20s%27en%20sortir%20si%20saturation%20de%20votre%201400cm3%3F%3C/b%3E%0D%0AIl%20suffit%20de%20choisir%20l%27option%20purger%20l%27historique%20et%20le%20site%20gardera%20votre%20derniere%20version%20en%20m%26%23233%3Bmoire.%0D%0A%0D%0A%3Cb%3EComment%20faire%20une%20int%26%23233%3Bgration%20de%20vid%26%23233%3Bo%3F%3C/b%3E%0D%0ADe%20daylimotion%2Cgoogle%20video%20ou%20youtube%2C%20%20il%20suffit%20d%27entrer%20le%20code%20fourni%20par%20chaque%20site%2C%20par%20exemple%2C%20sur%20google%20vid%26%23233%3Bo%2C%20%26%23224%3Bcot%26%23233%3B%20de%20la%20vid%26%23233%3Bo%20il%20y%20a%20un%20bouton%20email-blog%20et%20en%20cliquant%20dessus%2C%20un%20code%20apparait%2C%20il%20suffit%20de%20le%20copier/coller%20dans%20une%20fen%26%23234%3Btre%20comme%20ici%20%28cliquer%20deux%20fois%20dans%20cette%20fen%26%23234%3Btre%20pour%20voir%20le%20code%29%20%3A%0D%0A%0D%0A%3Cembed%20style%3D%22width%3A300px%3B%20height%3A226px%3B%22%20id%3D%22VideoPlayback%22%20type%3D%22application/x-shockwave-flash%22%20src%3D%22http%3A//video.google.com/googleplayer.swf%3FdocId%3D-6035121170646340376%26hl%3Dfr%22%20flashvars%3D%22%22%3E%20%3C/embed%3E%0D%0A%0D%0AFermer%20cette%20fen%26%23234%3Btre%20%3Cimg%20id%3D%22newImg%22%20src%3D%27images/close.gif%27%20class%3D%27controls%27%20onclick%3D%22workspace.notes.aidecode.destroy%28true%29%3Bworkspace.notes.aide.destroy%28true%29%22%20title%3D%22Nouvelle%20fen%26%23234%3Btre%22%20alt%3D%27new%20note%27%20/%3E');
   
   this.notes['aide'].setText(txt);
   this.reZOrder('aide');
   
   
    this.createNote( {
      'id' : 'aidecode',
	  'xPos':'1500',
	  'yPos':'1500',
      'height' : '1',
      'width' : '1',
      'bgcolor' : '#A999B5'
    } );
	
   var txto = unescape('//%20%3C%21--%0A%0Afunction%20main%28%29%20%7B%0A%0A%0A%0Aif%28%20value%20%3D%3D%22Commentaires%20perso%22%29%0A%7B%0Atxt%3Dcommentairesperso%28%29%3B%0Areturn%20txt%3B%0A%7D%0A%0Aif%28%20value%20%3D%3D%22Email%20perso%22%29%0A%7B%0Atxt%3Demailperso%28%29%3B%0Areturn%20txt%3B%0A%7D%0A%0Aif%28%20value%20%3D%3D%221400cm3%20Ami%22%29%0A%7B%0Atxt%3Dami%28%29%3B%0Areturn%20txt%3B%0A%7D%0A%0Aif%20%20%28value%3D%3D%22un%20site%20web%22%29%7B%0Atxt%3Dsiteweb%28%29%3B%0Areturn%20txt%3B%0A%7D%0A%0A%0Aif%20%20%28value%3D%3D%22fondecran%22%29%7B%0Afondecran%28%29%3B%0Areturn%20txt%3B%0A%20%7D%0A%0Aif%20%20%28value%3D%3D%22tchat-1400cm3%22%29%7B%0Atchat1400%28%29%3B%0Areturn%20txt%3B%0A%20%7D%0A%0Aif%20%20%28value%3D%3D%22Commentaires%201400cm3%22%29%7B%0Acommentaires%28%29%3B%0Areturn%20txt%3B%0A%20%7D%0A%0Aif%20%20%28value%3D%3D%22heure%22%29%7B%0Aheure%28%29%3B%0Areturn%20txt%3B%0A%20%7D%0A%0Aif%20%20%28value%3D%3D%22telecharger%20un%20document%20%28photo%2C%20video%2Cmp3%2Ctxt%29%22%29%7B%0Auploadbox%28%29%3B%0Areturn%20txt%3B%0A%20%7D%0A%0Aif%20%20%28value%3D%3D%22flux%20rss%22%29%7B%0Afluxrss%28%29%3B%0Areturn%20txt%3B%0A%20%7D%0A%0Aif%20%20%28value%3D%3D%22flux%20rss%201400cm3%22%29%7B%0Afluxrss1400%28%29%3B%0Areturn%20txt%3B%0A%20%7D%0A%0Aif%20%20%28value%3D%3D%22google%20map%22%29%7B%0Agooglemap%28%29%3B%0Areturn%20txt%3B%0A%20%7D%0A%0Aif%20%20%28value%3D%3D%22news%20map%22%29%7B%0Anewsmap%28%29%3B%0Areturn%20txt%3B%0A%20%7D%0A%0A%7D%0A%0A%0Afunction%20bild%28%29%20%7B%0Atxt%3D%22%3Cb%3E%22+form.inputbox.value%20+%22%3C/b%3E%22%3B%0Areturn%20txt%3B%0A%7D%0A%0A%0A%0Afunction%20fondecran%28%29%20%7B%0Apar%3DString.fromCharCode%2834%29%3B%0Aimageweb%3Dprompt%28%27Url%20image%20du%20fond%20ecran%3A%20%27%2C%27http%3A//www.1400cm3.net/imagesdavid/avenir.jpg%27%29%3B%0Aif%20%28imageweb%3D%3D0%29%20imageweb%3D%22%22%3B%0Aif%20%28imageweb%3D%3Dnull%29%20exit%3B%20%0Atxt%3D%22%3Cimg%20src%3Dimages/new%20onload%3D%22+par+%22document.body.style.background%3D%27url%28%22+imageweb+%22%29%27%3B%22+par+%22/%3E%22%3B%0Areturn%20txt%3B%0A%7D%0A%0Afunction%20tchat1400%28%29%20%7B%0Atxt%3D%22%3Ccenter%3E%3Cfont%20color%3D%23000099%20size%3D4%20face%3DGeneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3ETCHAT%201400cm3%3C/font%3E%3Cbr%3E%3Cbr%3E%3Ciframe%20src%3Dhttp%3A//www.i-tchat.com/29470%20width%3D155%20%20height%3D310%20frameborder%3D0%20allowTransparency%3Dtrue%3E%20%3C/iframe%3E%22%3B%0Areturn%20txt%3B%0A%7D%0A%0Afunction%20commentaires%28%29%20%7B%0Atxt%3D%22%3Ccenter%3E%3Cfont%20color%3D%23000099%20size%3D4%20face%3DGeneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3ECommentaires%20des%201400cm3%3C/font%3E%3Cbr%3E%3Cbr%3E%3Ciframe%20src%3Dhttp%3A//1400cm3.net/comment/intro.htm%20width%3D95%25%20%20height%3D95%25frameborder%3D0%20allowTransparency%3Dtrue%3E%20%3C/iframe%3E%22%3B%0Areturn%20txt%3B%0A%7D%0A%0Afunction%20commentairesperso%28%29%20%7B%0Atxt%3D%22%3Ccenter%3E%3Cfont%20color%3D%23000099%20size%3D4%20face%3DGeneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3ECommentaires%20de%20ce%201400cm3%3C/font%3E%3Cbr%3E%3Cbr%3E%3Ciframe%20src%3Dhttp%3A//1400cm3.net/%22+workspace.name+%22/comment.htm%20width%3D95%25%20%20height%3D95%25frameborder%3D0%20allowTransparency%3Dtrue%3E%20%3C/iframe%3E%22%3B%0Areturn%20txt%3B%0A%7D%0A%0Afunction%20siteweb%28%29%20%7B%0Asiteweb%3Dprompt%28%27url%20du%20site%20web%20%3A%20%27%2C%27http%3A//www.google.fr%27%29%3B%0Aif%20%28siteweb%3D%3Dnull%29%20exit%3B%0Aif%20%28siteweb%3D%3D0%29%20siteweb%3D%22http%3A//google.fr%22%3B%0Atxt%3D%22%3Ciframe%20%20src%3D%22%20+%20siteweb%20+%20%22%20width%3D95%25%20%20height%3D95%25frameborder%3D0%20allowTransparency%3Dtrue%3E%20%3C/iframe%3E%22%3B%0Areturn%20txt%3B%0A%7D%0A%0Afunction%20heure%28%29%20%7B%0Atxt%3D%22%3Cscript%20src%3Dhttp%3A//www.clocklink.com/embed.js%3E%3C/script%3E%3Cscript%20type%3Dtext/javascript%20language%3DJavaScript%3Eobj%20%3D%20new%20Object%3Bobj.clockfile%20%3D%205005-purple.swf%3Bobj.TimeZone%20%3D%20CET%3Bobj.width%20%3D%20120%3Bobj.height%20%3D%2040%3Bobj.wmode%20%3D%20transparent%3BshowClock%28obj%29%3B%3C/script%3E%3Cembed%20src%3Dhttp%3A//www.clocklink.com/clocks/5005-purple.swf%3FTimeZone%3DCET%26%20%20width%3D120%20height%3D40%20wmode%3Dtransparent%20type%3Dapplication/x-shockwave-flash%3E%22%3B%0Areturn%20txt%3B%0A%7D%0A%0Afunction%20uploadbox%28%29%20%7B%0Atxt%3D%22%3Ccenter%3E%3Cfont%20color%3D%23000099%20size%3D4%20face%3DGeneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3ETELECHARGER%20UN%20DOCUMENT%20%3C/font%3E%3Cbr%3E%3Cbr%3EGr%26%23226%3Bce%20%26%23224%3B%20BOX.NET%20t%26%23233%3Bl%26%23233%3Bcharger%20un%20fichier%20photo%2C%20mp3%2C%20vid%26%23233%3Bo%20ou%20texte%20et%20%3Cb%3Ecopier/coller%20le%20code%20resultat%20%3C/b%3Edans%20un%20fen%26%23234%3Btre%20de%20votre%201400cm3.%20%28pour%20les%20mp3%2C%20copier%20le%20code%20de%20la%20fen%26%23234%3Btre%20FLASH%20PLAYER%20et%20pour%20les%20photos%2C%20le%20code%20de%20la%20fen%26%23234%3Btre%20%20PHOTO%20CODE%29%20%3Cbr%3E%3Cbr%3E%3Ciframe%20src%3Dhttp%3A//www.box.net/lite%20width%3D95%25%20%20height%3D95%25frameborder%3D0%20allowTransparency%3Dtrue%3E%20%3C/iframe%3E%22%3B%0Areturn%20txt%3B%0A%7D%0A%0Afunction%20fluxrss%28%29%7B%0Aflux%3Dprompt%28%27Nom%20du%20flux%20RSS%3A%20%27%29%3B%0Aif%20%28flux%3D%3D0%29%20flux%3D%22http%3A//www.lemonde.fr/rss/sequence/0%2C2-3208%2C1-0%2C0.xml%22%3B%0Aif%20%28flux%3D%3Dnull%29%20exit%3B%0Atxt%3D%22%3CIFRAME%20SRC%3Dhttp%3A//1400cm3.net/rss2html.php%3FXMLFILE%3D%22+flux+%22%26MAXITEMS%3D20%20HEIGHT%3D300%20WIDTH%3D98%25%3E%3C/IFRAME%3E%22%0Areturn%20txt%3B%0A%7D%0A%0A%0Afunction%20fluxrss1400%28%29%7B%0Aflux%3Dprompt%28%27Entre%20le%20nom%20de%20votre%201400cm3%20ou%201400cm3%20ami%3A%20%27%29%3B%0Aif%20%28flux%3D%3D0%29%20flux%3D%22atelier%22%3B%0Aif%20%28flux%3D%3Dnull%29%20exit%3B%0Aflax%3D%22http%3A//1400cm3.net/rss.php%3Fname%3D%22+flux%3B%0Atxt%3D%22%3CIFRAME%20SRC%3Dhttp%3A//1400cm3.net/rss2html.php%3FXMLFILE%3D%22+flax+%22%26MAXITEMS%3D20%20HEIGHT%3D300%20WIDTH%3D98%25%3E%3C/IFRAME%3E%22%0A%0Areturn%20txt%3B%7D%0A%0A%0Afunction%20emailperso%28%29%7B%0Amail%3Dprompt%28%27entrez%20votre%20email%20de%20correspondance%3A%20%27%2C%27machin@truc.com%27%29%3B%0Aif%20%28mail%3D%3D0%29%20exit%3B%0Aif%20%28mail%3D%3Dnull%29%20exit%3B%0Atxt%3D%22%3Ca%20href%3Dmailto%3A%22+mail+%22%3EEnvoyez-moi%20un%20email%3C/a%3E%22%3B%0Areturn%20txt%3B%0A%7D%0A%0Afunction%20ami%28%29%7B%0Aami%3Dprompt%28%27Nom%20du%201400cm3%20Ami%3A%20%27%29%3B%0Aif%20%28ami%3D%3D0%29%20ami%3D%22introduction-1400cm3%22%3B%0Aif%20%28ami%3D%3Dnull%29%20exit%3B%0Atxt%3D%22%3Ccenter%3E%3Cform%20%20name%3Dform1%20method%3Dpost%20action%3Dhttp%3A//1400cm3.net/%22+ami+%22%20target%3D_blank%20%3E%20%20%3Clabel%3E%20%3Cinput%20type%3Dsubmit%20name%3DSubmit%20value%3D%22+ami+%22%20/%3E%20%20%20%20%20%20%20%20%20%20%3C/label%3E%3C/form%3E%3C/center%3E%22%3B%0Areturn%20txt%3B%0A%7D%0A%0Afunction%20googlemap%28%29%7B%0Atxt%3D%22%3Ccenter%3E%3Cfont%20color%3D%23000099%20size%3D4%20face%3DGeneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3EGOOGLE%20MAP%3C/font%3E%3Cbr%3E%3Cbr%3EAllez%20sur%20ce%20site%20pour%20cr%26%23233%3Ber%20votre%20propre%20carte%20%3Ca%20HREF%3Dhttp%3A//www.wayfaring.com/%20target%3D_blank%3Ehttp%3A//www.wayfaring.com/%3C/a%20%3E%3Ciframe%20src%3Dhttp%3A//www.wayfaring.com/maps/export/28704%20scrolling%3Dno%20frameborder%3D0%20style%3Dwidth%3A95%25%3Bheight%3A400%3Bborder%3A2px%20solid%20%23cccccc%3B%3E%3C/iframe%3E%22%0Areturn%20txt%3B%0A%7D%0A%0Afunction%20newsmap%28%29%7B%0Atxt%3D%22%3Ccenter%3E%3Cfont%20color%3D%23000099%20size%3D4%20face%3DGeneva%2C%20Arial%2C%20Helvetica%2C%20sans-serif%3EGOOGLE%20NEWS%20MAP%3C/font%3E%3Cbr%3E%3Cbr%3E%3Ca%20HREF%3Dhttp%3A//www.marumushi.com/apps/newsmap/%20target%3D_blank%3Ehttp%3A//www.marumushi.com/apps/newsmap/%3C/a%20%3Cbr%3E%3CIFRAME%20SRC%3Dhttp%3A//www.marumushi.com/apps/newsmap/newsmap.cfm%3Flayout%3D0%26selected%3Dfr%26categories%3Dworld%2Cnation%2Cbusiness%2Ctechnology%2Csports%2Centertainment%2Chealth%20HEIGHT%3D95%25%20WIDTH%3D95%25%3E%3C/IFRAME%3E%22%0Areturn%20txt%3B%0A%7D%0A%0Amain%28%29%3B%0A//%20--%3E');
   
   
   this.notes['aidecode'].setText(txto);
   this.reZOrder('aidecode');
   
	  
	  },
  
  /**
   * Create the "load old notes" note.
   * @param {int} offset how many saves do we want to go back?
   */
   
   
   
   
   
  loadlist : function(offset) {
    if (!offset)
      offset = 0;

    var xmlhttp = getxmlreqobj();
    xmlhttp.onreadystatechange = function() {
        if (4 == xmlhttp.readyState && 200 == xmlhttp.status) {
          workspace.loadlistCallback(xmlhttp, offset);
        }
        if (4 == xmlhttp.readyState) {
          try { // break circular ref
            xmlhttp.onreadystatechange = null;
          } catch (e) { }
        }
    };
    this.createNote( {
      'id' : 'load',
      'height' : '130',
      'width' : '270',
      'bgcolor' : '#A999B5'
    } );
    var txt = 'Chargement Historique...';
    this.notes['load'].setText(txt);
    this.reZOrder('load');
	
	xmlhttp.open('POST', 'getdates.php',true);
/* Effectue la requête en envoyant les données : */
xmlhttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xmlhttp.send('name='+escape(escape(this.name))+'&offset='+offset);
	//alert(xmlhttp.responseText);

  /*  xmlhttp.open('GET', 'getdates.php?name=' + escape(escape(this.name))
                 + '&offset=' + offset, true);
    xmlhttp.send(''); */
  },

  loadlistCallback : function(xmlhttp, offset) {
    var loadTimes = xmlhttp.responseText.split('|');
    this.createNote( {
      'id': 'load',
      'height': '130',
      'width': '270',
      'bgcolor': '#A999B5'
    } );
    var txt;
    db('resp: ' + xmlhttp.responseText.trim());
    db('resplen: ' + xmlhttp.responseText.trim().length);
    if (xmlhttp.responseText.trim() == '') {
      txt = this.notes['load'].text + '\nAucun historique '
            + ' en mémoire pour ce 1400cm3.';
    } else {

   txt = 'Pour afficher une version précédente de ce 1400cm3, '
            + 'selectionnez la date puis validez.\n'
            + '<div style="text-align: center;"><form method="POST" action="load.php" onmousedown="event.cancelBubble=true;">'
            + '<input type="hidden" name="name" value="'
            + escape(this.name) + '"/>'+
			/*'mot de passe <input name="pass" id="pass" type="password" size="10" value="">'+ */
			'<select class="loadfrm" name="time">';


 
			
        for (var i = 0; i < loadTimes.length && i < numDates; i++) {
        txt += "<option value='" + loadTimes[i].trim() + "'>"
               + (new MyDate(loadTimes[i])) + "</option>";
      }

 /*version avec mot de passe pour afficher version     txt += "' <input name='pass' id='pass' type='password' size='10' value=''> </select><input type='submit' value='load' /><br /><span style='font-size: 0.8em;'>";
*/
      txt += "' </select><input type='submit' value='OK' /><br /><span style='font-size: 0.8em;'>";

      if (loadTimes.length > numDates)
      {
        txt += "&laquo; <a class='fakelink' onclick='workspace.loadlist(" + (offset+numDates) + ")'>liste précédente</a> ";
        if (offset > 0)
          txt += "| ";
      }
      if (offset > 0)
        txt += "<a class='fakelink' onclick='workspace.loadlist(" + (offset-numDates) + ")'>liste suivante</a> &raquo;";

      txt += "<br /></span></div>";
    }
    this.notes['load'].setText(txt);
    this.reZOrder('load');
  },

  /**
   * Checks to see if the notes have changed since the last time we loaded
   * the notes.
   */
  checkUpdated : function() {
    var xmlhttp = getxmlreqobj();
    xmlhttp.onreadystatechange = function() {
        if (4 == xmlhttp.readyState && 200 == xmlhttp.status) {
          db('check updated');
          workspace.checkUpdatedCallback(xmlhttp);
        }
        if (4 == xmlhttp.readyState) {
          try { // break circular ref
            xmlhttp.onreadystatechange = null;
          } catch (e) { }
        }
    };
	xmlhttp.open('POST', 'getrecent.php',true);
/* Effectue la requête en envoyant les données : */
xmlhttp.setRequestHeader('Content-Type','application/x-www-form-urlencoded');
xmlhttp.send('name='+escape(escape(workspace.name)));
	
   /* xmlhttp.open('GET', 'getrecent.php?name=' + escape(escape(workspace.name)), true);
    xmlhttp.send('');*/
  },

  checkUpdatedCallback : function(xmlhttp) {
    var loadTime = xmlhttp.responseText.trim();
    if (loadTime > this.loadedTime) {
      this.createNote( {
        'id' : 'updated',
        'xPos' : '0',
        'yPos' : '40',
        'bgcolor' : '#ff6060',
        'height' : '100',
        'text' : "Attention, ce 1400cm3 est ouvert dans une autre fenetre. Verifier les eventuelles pertes de données."});
		/*<a href='"
              + 'load.php?name=' +  escape(escape(escape(this.name))) + "'  target='_new'>ouvrez-le dans une nouvelle fenetre</a>.*/
      
    } else {
      db('no changes');
      window.setTimeout(workspace.checkUpdated, workspace.updateInterval);
    }
  },

  /**
   * Generate the xml representation of the workspace (used when saving).
   * @type string
   */
  toString : function()
  {
    var ret = "<workspace name='" + escape(this.name) + "'";
    ret += " nextNoteNum='" + this.nextNoteNum + "'";
    ret += ">\n";
    for (nid in this.notes)
      ret += this.notes[nid].toXML() + "\n";
    return ret + "</workspace>"
  },
  /**
   * Get the next (or previous) note relative to the top note.
   * @param {int} diff The offset from the top note (positive mean
   * below and negative mean up from the bottom note).
   */
  selectNote : function(diff)
  {
    var max = -1;
    var maxNote;
    var noteArr = [];
    // determine which note is on top
    for (var n in this.notes)
    {
      var cur = parseInt(get(this.notes[n].id).style.zIndex);
      if (cur > max)
      {
        max = cur;
        maxNote = noteArr.length;
      }
      noteArr.push(this.notes[n]);
    }
    noteArr[ (maxNote+diff+noteArr.length) % noteArr.length ].select();
  },
  /**
   * Save the workspace.
   */
  save : function()
  {
    // there have to be changes to the workspace before saving is enabled
    var s = get('saveImg');
    if (s.className == 'controlsDisabled')
      return;

    s.src = 'images/saving.gif';
    this.editOff();

    var xmlhttp = getxmlreqobj();
    xmlhttp.onreadystatechange = function() {
        if (4 == xmlhttp.readyState && 200 == xmlhttp.status) {
          workspace.saveCallback(xmlhttp);
        } else if (4 == xmlhttp.readyState) {
          db(xmlhttp.status);
          alert("Impossible de sauvegarder ce 1400cm3. Essayez à nouveau. si le problème persiste écrire à  " + adminEmail + ".  Merci.");
          get('saveImg').src = 'images/save.gif';
        }
        if (4 == xmlhttp.readyState) {
          try { // break circular ref
            xmlhttp.onreadystatechange = null;
          } catch (e) { }
        }
    };

    xmlhttp.open('POST', 'save.php', true);
    xmlhttp.send(workspace.toString());
  },
  saveCallback : function(xmlhttp) {
    var doc = xmlhttp.responseXML;
	
    db("response: " + xmlhttp.responseText);
	
	if (doc && 'trop' == doc.getElementsByTagName('status')[0].getAttribute('value')) {
      alert("Vous avez dépassé le nombre maximum de "+maxfen+" fenêtres ouvertes");
	
    } else 
    if (doc && 'ok' == doc.getElementsByTagName('status')[0].getAttribute('value')) {
      this.changed = false;
      get('saveImg').className = 'controlsDisabled';
      this.loadedTime = doc.getElementsByTagName('status')[0].getAttribute('update');
    } else {
         alert("Problème base. Essayez à nouveau. si le problème persiste écrire à  " + adminEmail + ".  Merci.");

    }
    get('saveImg').src = 'images/save.gif';
  }
};

///
/// global methods
///

/**
 * Write a message to the debug textarea.
 * @param {string} msg the message to display
 */
function db(msg) {
  if (debugOn) {
    var elt = get('debug');
    elt.value = msg + '\n' + elt.value;
  }
}

/**
 * Initialize the workspace.
 */
function init()
{
  if (debugOn) {
    get('db').innerHTML = "<form name='debugForm'>" +
        "<textarea style='position:absolute;top:26px;right:10px;' id='debug' cols='50' rows='10'></textarea>" +
        "<input type='button' onclick='document.debugForm.debug.value=\"\";' value='clear' />" +
        "</form>";
    get('debug').value = '';
  }

  // preload the close image
  var closeImg = new Image();
  closeImg.src = 'images/close.gif';

  // a hack for safari compatability
  if (BROWSER_SAFARI == browser) {
    escape = myescape;
    //unescape = myunescape;
  }

  var toolbar = get('toolbar');
  toolbar.onmousedown = cancelBubble;
  if (BROWSER_SAFARI == browser) {
    toolbar.style.width = '100%';
  }

  workspace.mouse.curPos = new Point();
  document.onmousemove = docMouseMove;
  document.onkeydown = docKeyDown;
  get('content').onmousedown = docMouseDown;
  document.onmouseup = docMouseUp;

  /**
   * When the user navigates away, if there are changes, give the user a
   * chance to cancel.
   */
  window.onbeforeunload = winBeforeUnload;


  // periodically check for updates (every 10 minutes)
  window.setTimeout(workspace.checkUpdated, workspace.updateInterval);
}

function cancelBubble(e) {
  e = e || window.event;
  e.cancelBubble = true;
}
// absolute mouse positions; modified from:
// http://www.web-wise-wizard.com/javascript-tutorials/javascript-mouse-event-handlers.html
function docMouseMove(e) {
  e = e || window.event;
  var x, y;
  if (!e.pageX && !e.pageY) { // IE
    x = e.x+document.body.scrollLeft;
    y = e.y+document.body.scrollTop;
  } else {
    x = e.pageX;
    y = e.pageY;
  }
  workspace.mouse.update(x, y);
  workspace.docMove(x, y);
}

/**
 * If the user clicks on the background, turn off note editing and start dragging
 */
function docMouseDown(e) {
  workspace.editOff();

  // force a position update
  docMouseMove(e);
  var curPos = workspace.mouse.curPos.copy();
  // get rel pos
  // make sure we're not on a scrollbar
  var content = get('content');
  
  if (curPos.x < content.clientWidth && curPos.y < content.clientHeight) {
    workspace.mouseDown = workspace.mouse.curPos.copy();
  }
}

/**
 * @see workspace#mouseUp
 */
function docMouseUp(e) {
  workspace.mouseUp(e);
}

function docKeyDown(ev) {
  // the keydown event only seems to be a document event so we
  // can't put the event on the div layer.  Instead, events
  // need to be passed to the note that is being hovered over.
  if (!ev) ev = window.event;
  if (workspace.mouse.noteOver)
    workspace.mouse.noteOver.keyDown(ev);

  if (workspace.shortcuts && !workspace.edit) {
    // blah, I should turn this into a map
    var key = String.fromCharCode(ev.keyCode);
    var n;
    if ('P' == key && ev.altKey) {
      var note = workspace.createNote();
      note.mouseDblClick();
    } else if (37 == ev.keyCode) { // left
      n = workspace.notes[workspace.topId];
      if (n) n.move(new Point(-8, 0));
    } else if (38 == ev.keyCode) { // up
      n = workspace.notes[workspace.topId];
      if (n) n.move(new Point(0, -8));
    } else if (39 == ev.keyCode) { // right
      n = workspace.notes[workspace.topId];
      if (n) n.move(new Point(8, 0));
    } else if (40 == ev.keyCode) { // down
      n = workspace.notes[workspace.topId];
      if (n) n.move(new Point(0, 8));
    } else if ('O' == key && ev.altKey) {
      n = workspace.notes[workspace.topId];
      n.mouseDblClick();
    } else if ('N' == key) {
      workspace.selectNote(1);
    } else if ('P' == key) {
      workspace.selectNote(-1);
    } 
	
	
	/*
	else if ('B' == key) {
      workspace.createNote({
      'text':"This is a bookmarklet for quickly adding new notes.  Right click on the link and add it as a bookmark.  You can now quickly create a note by selecting text on any webpage and then clicking your bookmark.\n"
        + "<a href=\"javascript:var d=document;var e=encodeURIComponent;if(d.getSelection)txt=d.getSelection();if(d.selection)txt=d.selection.createRange().text;location.href='" + baseURI + "load.php?name="
        + escape(escape(escape(workspace.name))) + "&via='+e(location.href)+'&nn='+e(txt);\">new note</a>"});
    }
    /* //not ready yet
    else if ('E' == key) {
      workspace.expose();
      // swap the functionality with the undo effect
      var tmp = workspace.expose;
      workspace.expose = workspace._expose;
      workspace._expose = tmp;
    }
    */
  } else if (workspace.shortcuts) { // in edit mode
    if (27 == ev.keyCode) { // Esc
      workspace.editOff();
    }
  }
}

/**
 * Give the user a chance to save workspace.
 */
function winBeforeUnload() {
  if (workspace.changed && workspace.name != "Sample Workspace") {
    return "Votre 1400cm3 n'a pas été sauvegardé, vous allez perdre vos modifications.";
  }
}

/**
 * Get the size of the browser.
 * @type Point
 */
function getPageSize() {
  var ret;
  if (BROWSER_IE_5 == browser) {
    ret = new Point(document.body.clientWidth, document.body.clientHeight);
  } else if (BROWSER_IE_6 == browser) {
    ret = new Point(document.documentElement.clientWidth,
            document.documentElement.clientHeight);
  } else {
    ret = new Point(window.innerWidth, window.innerHeight);
  }
  return ret;
}

/**
 * Get a reference to an html object given the id.
 * @param {string} id id of the object
 * @type {HtmlElement}
 */
function get(id) { return document.getElementById(id); }

/**

FONCTIONS WY

 */
 
 // Images Directory
imagesDir = "icons/";

// CSS Directory
cssDir = "styles/";

// Popups Directory
popupsDir = "popups/";

// WYSIWYG Width and Height
wysiwygWidth = 450;
wysiwygHeight = 250;

// Include Style Sheet
document.write('<link rel="stylesheet" type="text/css" href="' +cssDir+ 'styles.css">\n');


/* ---------------------------------------------------------------------- *\
  Toolbar Settings: Set the features and buttons available in the WYSIWYG
	                  Toolbar.
\* ---------------------------------------------------------------------- */


// List of available font types
  var Fonts = new Array();
  Fonts[0] = "Arial";
  Fonts[1] = "Sans Serif";
  Fonts[2] = "Tahoma";
	Fonts[3] = "Verdana";
	Fonts[4] = "Courier New";
	Fonts[5] = "Georgia";
	Fonts[6] = "Times New Roman";
	Fonts[7] = "Impact";
  Fonts[8] = "Comic Sans MS";

// List of available block formats (not in use)
var BlockFormats = new Array();
  BlockFormats[0]  = "Address";
  BlockFormats[1]  = "Bulleted List";
  BlockFormats[2]  = "Definition";
	BlockFormats[3]  = "Definition Term";
	BlockFormats[4]  = "Directory List";
	BlockFormats[5]  = "Formatted";
	BlockFormats[6]  = "Heading 1";
	BlockFormats[7]  = "Heading 2";
	BlockFormats[8]  = "Heading 3";
	BlockFormats[9]  = "Heading 4";
	BlockFormats[10] = "Heading 5";
	BlockFormats[11] = "Heading 6";
	BlockFormats[12] = "Menu List";
	BlockFormats[13] = "Normal";
	BlockFormats[14] = "Numbered List";

// List of available font sizes
var FontSizes = new Array();
  FontSizes[0]  = "1";
  FontSizes[1]  = "2";
  FontSizes[2]  = "3";
	FontSizes[3]  = "4";
	FontSizes[4]  = "5";
	FontSizes[5]  = "6";
	FontSizes[6]  = "7";

// Order of available commands in toolbar one
var buttonName = new Array();
  buttonName[0]  = "bold";
  buttonName[1]  = "italic";
  buttonName[2]  = "underline";
	//buttonName[3]  = "strikethrough";
  buttonName[4]  = "seperator";
	buttonName[5]  = "subscript";
	buttonName[6]  = "superscript";
	buttonName[7]  = "seperator";
	buttonName[8]  = "justifyleft";
	buttonName[9]  = "justifycenter";
	buttonName[10] = "justifyright";
	buttonName[11] = "seperator";
	buttonName[12] = "unorderedlist";
	buttonName[13] = "orderedlist";
	buttonName[14] = "outdent";
	buttonName[15] = "indent";

// Order of available commands in toolbar two
var buttonName2 = new Array();
  buttonName2[0]  = "forecolor";
	buttonName2[1]  = "backcolor";
	buttonName2[2]  = "seperator";
	buttonName2[3]  = "cut";
	buttonName2[4]  = "copy";
	buttonName2[5]  = "paste";
	buttonName2[6]  = "seperator";
  buttonName2[7]  = "undo";
	buttonName2[8]  = "redo";
  buttonName2[9]  = "seperator";
	buttonName2[10]  = "inserttable";
  buttonName2[11]  = "insertimage";
  buttonName2[12]  = "createlink";
	buttonName2[13]  = "seperator";
	buttonName2[14]  = "viewSource";
	buttonName2[15]  = "seperator";
  buttonName2[16]  = "help";
    buttonName2[17]  = "WY";
	
// List of available actions and their respective ID and images
var ToolbarList = {
//Name              buttonID                 buttonTitle           buttonImage                            buttonImageRollover
  "bold":           ['Bold',                 'Bold',               imagesDir + 'bold.gif',               imagesDir + 'bold_on.gif'],
  "italic":         ['Italic',               'Italic',             imagesDir + 'italics.gif',            imagesDir + 'italics_on.gif'],
  "underline":      ['Underline',            'Underline',          imagesDir + 'underline.gif',          imagesDir + 'underline_on.gif'],
	"strikethrough":  ['Strikethrough',        'Strikethrough',      imagesDir + 'strikethrough.gif',      imagesDir + 'strikethrough_on.gif'],
	"seperator":      ['',                     '',                   imagesDir + 'seperator.gif',          imagesDir + 'seperator.gif'],
	"subscript":      ['Subscript',            'Subscript',          imagesDir + 'subscript.gif',          imagesDir + 'subscript_on.gif'],
	"superscript":    ['Superscript',          'Superscript',        imagesDir + 'superscript.gif',        imagesDir + 'superscript_on.gif'],
	"justifyleft":    ['Justifyleft',          'Justifyleft',        imagesDir + 'justify_left.gif',       imagesDir + 'justify_left_on.gif'],
	"justifycenter":  ['Justifycenter',        'Justifycenter',      imagesDir + 'justify_center.gif',     imagesDir + 'justify_center_on.gif'],
	"justifyright":   ['Justifyright',         'Justifyright',       imagesDir + 'justify_right.gif',      imagesDir + 'justify_right_on.gif'],
	"unorderedlist":  ['InsertUnorderedList',  'InsertUnorderedList',imagesDir + 'list_unordered.gif',     imagesDir + 'list_unordered_on.gif'],
	"orderedlist":    ['InsertOrderedList',    'InsertOrderedList',  imagesDir + 'list_ordered.gif',       imagesDir + 'list_ordered_on.gif'],
	"outdent":        ['Outdent',              'Outdent',            imagesDir + 'indent_left.gif',        imagesDir + 'indent_left_on.gif'],
	"indent":         ['Indent',               'Indent',             imagesDir + 'indent_right.gif',       imagesDir + 'indent_right_on.gif'],
	"cut":            ['Cut',                  'Cut',                imagesDir + 'cut.gif',                imagesDir + 'cut_on.gif'],
	"copy":           ['Copy',                 'Copy',               imagesDir + 'copy.gif',               imagesDir + 'copy_on.gif'],
  "paste":          ['Paste',                'Paste',              imagesDir + 'paste.gif',              imagesDir + 'paste_on.gif'],
	"forecolor":      ['ForeColor',            'ForeColor',          imagesDir + 'forecolor.gif',          imagesDir + 'forecolor_on.gif'],
	"backcolor":      ['BackColor',            'BackColor',          imagesDir + 'backcolor.gif',          imagesDir + 'backcolor_on.gif'],
	"undo":           ['Undo',                 'Undo',               imagesDir + 'undo.gif',               imagesDir + 'undo_on.gif'],
	"redo":           ['Redo',                 'Redo',               imagesDir + 'redo.gif',               imagesDir + 'redo_on.gif'],
	"inserttable":    ['InsertTable',          'InsertTable',        imagesDir + 'insert_table.gif',       imagesDir + 'insert_table_on.gif'],
	"insertimage":    ['InsertImage',          'InsertImage',        imagesDir + 'insert_picture.gif',     imagesDir + 'insert_picture_on.gif'],
	"createlink":     ['CreateLink',           'CreateLink',         imagesDir + 'insert_hyperlink.gif',   imagesDir + 'insert_hyperlink_on.gif'],
	"viewSource":     ['ViewSource',           'ViewSource',         imagesDir + 'view_source.gif',        imagesDir + 'view_source_on.gif'],
	"viewText":       ['ViewText',             'ViewText',           imagesDir + 'view_text.gif',          imagesDir + 'view_text_on.gif'],
	"help":           ['Help',                 'Help',               imagesDir + 'help.gif',               imagesDir + 'help_on.gif'],
	"WY":           ['WY',                 'WY',               imagesDir + 'creerfenetre.png',               imagesDir + 'creerfenetre.png'],
	"selectfont":     ['SelectFont',           'SelectFont',         imagesDir + 'select_font.gif',        imagesDir + 'select_font_on.gif'],
	"selectsize":     ['SelectSize',           'SelectSize',         imagesDir + 'select_size.gif',        imagesDir + 'select_size_on.gif']
};

if(typeof HTMLElement!="undefined" && !HTMLElement.prototype.insertAdjacentElement){
  HTMLElement.prototype.insertAdjacentElement = function
  (where,parsedNode)
	{
	  switch (where){
		case 'beforeBegin':
			this.parentNode.insertBefore(parsedNode,this)
			break;
		case 'afterBegin':
			this.insertBefore(parsedNode,this.firstChild);
			break;
		case 'beforeEnd':
			this.appendChild(parsedNode);
			break;
		case 'afterEnd':
			if (this.nextSibling) 
      this.parentNode.insertBefore(parsedNode,this.nextSibling);
			else this.parentNode.appendChild(parsedNode);
			break;
		}
	}

	HTMLElement.prototype.insertAdjacentHTML = function
  (where,htmlStr)
	{
		var r = this.ownerDocument.createRange();
		r.setStartBefore(this);
		var parsedHTML = r.createContextualFragment(htmlStr);
		this.insertAdjacentElement(where,parsedHTML)
	}


	HTMLElement.prototype.insertAdjacentText = function
  (where,txtStr)
	{
		var parsedText = document.createTextNode(txtStr)
		this.insertAdjacentElement(where,parsedText)
	}
};


// Create viewTextMode global variable and set to 0
// enabling all toolbar commands while in HTML mode
viewTextMode = 0;


 
 
function generate_wysiwyg(textareaID) {
 
  	// Hide the textarea 
	document.getElementById(textareaID).style.display = 'none'; 
	
  // Pass the textareaID to the "n" variable.
  var n = textareaID;
	
	// Toolbars width is 2 pixels wider than the wysiwygs
	toolbarWidth = parseFloat(wysiwygWidth) + 2;
	
  // Generate WYSIWYG toolbar one
  var toolbar;
  toolbar =  '<table cellpadding="0" cellspacing="0" border="0" class="toolbar1" style="width:' + toolbarWidth + 'px;"><tr><td style="width: 6px;"><img src="' +imagesDir+ 'seperator2.gif" alt="" hspace="3"></td>';
  
	// Create IDs for inserting Font Type and Size drop downs
	toolbar += '<td style="width: 90px;"><span id="FontSelect' + n + '"></span></td>';
	toolbar += '<td style="width: 60px;"><span id="FontSizes'  + n + '"></span></td>';
  
	// Output all command buttons that belong to toolbar one
	for (var i = 0; i <= buttonName.length;) { 
    if (buttonName[i]) {
	    var buttonObj            = ToolbarList[buttonName[i]];
		  var buttonID             = buttonObj[0];
	    var buttonTitle          = buttonObj[1];
      var buttonImage          = buttonObj[2];
		  var buttonImageRollover  = buttonObj[3];
	    
			if (buttonName[i] == "seperator") {
		    toolbar += '<td style="width: 12px;" align="center"><img src="' +buttonImage+ '" border=0 unselectable="on" width="2" height="18" hspace="2" unselectable="on"></td>';
			}
	    else {
		    toolbar += '<td style="width: 22px;"><img src="' +buttonImage+ '" border=0 unselectable="on" title="' +buttonTitle+ '" id="' +buttonID+ '" class="button" onClick="formatText(this.id,\'' + n + '\');" onmouseover="if(className==\'button\'){className=\'buttonOver\'}; this.src=\'' + buttonImageRollover + '\';" onmouseout="if(className==\'buttonOver\'){className=\'button\'}; this.src=\'' + buttonImage + '\';" unselectable="on" width="20" height="20"></td>';
	    }
    }
    i++;
  }

  toolbar += '<td>&nbsp;</td></tr></table>';  

  // Generate WYSIWYG toolbar two
  var toolbar2;
  toolbar2 = '<table cellpadding="0" cellspacing="0" border="0" class="toolbar2" style="width:' + toolbarWidth + 'px;"><tr><td style="width: 6px;"><img src="' +imagesDir+ 'seperator2.gif" alt="" hspace="3"></td>';
 
  // Output all command buttons that belong to toolbar two
  for (var j = 0; j <= buttonName2.length;) {
    if (buttonName2[j]) {
	    var buttonObj            = ToolbarList[buttonName2[j]];
		  var buttonID             = buttonObj[0];
	    var buttonTitle          = buttonObj[1];
      var buttonImage          = buttonObj[2];
		  var buttonImageRollover  = buttonObj[3];
	  
		  if (buttonName2[j] == "seperator") {
		    toolbar2 += '<td style="width: 12px;" align="center"><img src="' +buttonImage+ '" border=0 unselectable="on" width="2" height="18" hspace="2" unselectable="on"></td>';
			}
			else if (buttonName2[j] == "WY"){
			}
	    else if (buttonName2[j] == "viewSource"){
		    toolbar2 += '<td style="width: 22px;">';
				toolbar2 += '<span id="HTMLMode' + n + '"><img src="'  +buttonImage+  '" border=0 unselectable="on" title="' +buttonTitle+ '" id="' +buttonID+ '" class="button" onClick="formatText(this.id,\'' + n + '\');" onmouseover="if(className==\'button\'){className=\'buttonOver\'}; this.src=\'' +buttonImageRollover+ '\';" onmouseout="if(className==\'buttonOver\'){className=\'button\'}; this.src=\'' + buttonImage + '\';" unselectable="on"  width="20" height="20"></span>';
				toolbar2 += '<span id="textMode' + n + '"><img src="' +imagesDir+ 'view_text.gif" border=0 unselectable="on" title="viewText"          id="ViewText"       class="button" onClick="formatText(this.id,\'' + n + '\');" onmouseover="if(className==\'button\'){className=\'buttonOver\'}; this.src=\'' +imagesDir+ 'view_text_on.gif\';"    onmouseout="if(className==\'buttonOver\'){className=\'button\'}; this.src=\'' +imagesDir+ 'view_text.gif\';" unselectable="on"  width="20" height="20"></span>';
	      toolbar2 += '</td>';
			}
	    else {
		    toolbar2 += '<td style="width: 22px;"><img src="' +buttonImage+ '" border=0 unselectable="on" title="' +buttonTitle+ '" id="' +buttonID+ '" class="button" onClick="formatText(this.id,\'' + n + '\');" onmouseover="if(className==\'button\'){className=\'buttonOver\'}; this.src=\'' +buttonImageRollover+ '\';" onmouseout="if(className==\'buttonOver\'){className=\'button\'}; this.src=\'' + buttonImage + '\';" unselectable="on" width="20" height="20"></td>';
	    }
    }
    j++;
  }

  toolbar2 += '<td>&nbsp;</td></tr></table>';  
	
 	
	// Create iframe which will be used for rich text editing
	var iframe = '<table cellpadding="0" cellspacing="0" border="0" style="width:' + wysiwygWidth + 'px; height:' + wysiwygHeight + 'px;border: 1px inset #CCCCCC;"><tr><td valign="top">\n'
  + '<iframe frameborder="0" id="wysiwyg' + n + '"></iframe>\n'
  + '</td></tr></table>\n\n';
  
  var boutte = '<td style="width: 52px;"><img src="' +buttonImage+ '" border=0 unselectable="on" title="' +buttonTitle+ '" id="' +'WY'+ '"  onClick="formatText(this.id,\'' + n + '\');" onmouseover="if(className==\'button\'){className=\'buttonOver\'}; this.src=\'' +buttonImageRollover+ '\';" onmouseout="if(className==\'buttonOver\'){className=\'button\'}; this.src=\'' + buttonImage + '\';" unselectable="on" ></td>';



  // Insert after the textArea both toolbar one and two
  document.getElementById(n).insertAdjacentHTML("afterEnd", toolbar + toolbar2 + iframe + boutte);
	
  // Insert the Font Type and Size drop downs into the toolbar
	outputFontSelect(n);
	outputFontSizes(n); 
	
  // Hide the dynamic drop down lists for the Font Types and Sizes
  hideFonts(n);
	hideFontSizes(n);
	
	// Hide the "Text Mode" button
	document.getElementById("textMode" + n).style.display = 'none'; 
	
	// Give the iframe the global wysiwyg height and width
  document.getElementById("wysiwyg" + n).style.height = wysiwygHeight + "px";
  document.getElementById("wysiwyg" + n).style.width = wysiwygWidth + "px";
	
	// Pass the textarea's existing text over to the content variable
  var content = document.getElementById(n).value;
	
	var doc = document.getElementById("wysiwyg" + n).contentWindow.document;
	
	// Write the textarea's content into the iframe
  doc.open();
  doc.write(content);
  doc.close();
	
	// Make the iframe editable in both Mozilla and IE
  doc.body.contentEditable = true;
  doc.designMode = "on";
	
  	// Update the textarea with content in WYSIWYG when user submits form
  var browserName = navigator.appName;
  if (browserName == "Microsoft Internet Explorer") {
    for (var idx=0; idx < document.forms.length; idx++) {
      document.forms[idx].attachEvent('onsubmit', function() { updateTextArea(n); });
    }
  }
  else {
  	for (var idx=0; idx < document.forms.length; idx++) {
    	document.forms[idx].addEventListener('submit',function OnSumbmit() { updateTextArea(n); }, true);
    }
  }
 	

};



/* ---------------------------------------------------------------------- *\
  Function    : formatText()
  Description : replace textarea with wysiwyg editor
  Usage       : formatText(id, n, selected);
  Arguments   : id - The execCommand (e.g. Bold)
                n  - The editor identifier that the command 
								     affects (the textarea's ID)
                selected - The selected value when applicable (e.g. Arial)
\* ---------------------------------------------------------------------- */
function formatText(id, n, selected) {


  // When user clicks toolbar button make sure it always targets its respective WYSIWYG
  document.getElementById("wysiwyg" + n).contentWindow.focus();
	
	// When in Text Mode these execCommands are disabled
	var formatIDs = new Array("FontSize","FontName","Bold","Italic","Underline","Subscript","Superscript","Strikethrough","Justifyleft","Justifyright","Justifycenter","InsertUnorderedList","InsertOrderedList","Indent","Outdent","ForeColor","BackColor","InsertImage","InsertTable","CreateLink");
  
	// Check if button clicked is in disabled list
	for (var i = 0; i <= formatIDs.length;) {
		if (formatIDs[i] == id) {
			 var disabled_id = 1; 
		}
	  i++;
	}
	
	// Check if in Text Mode and disabled button was clicked
	if (viewTextMode == 1 && disabled_id == 1) {
	  alert ("You are in HTML Mode. This feature has been disabled.");	
	}
	
	else {
	
	  // FontSize
	  if (id == "FontSize") {
      document.getElementById("wysiwyg" + n).contentWindow.document.execCommand("FontSize", false, selected);
	  }
	  
		// FontName
	  else if (id == "FontName") {
      document.getElementById("wysiwyg" + n).contentWindow.document.execCommand("FontName", false, selected);
	  }
	
	  // ForeColor and BackColor
    else if (id == 'ForeColor' || id == 'BackColor') {
      var w = screen.availWidth;
      var h = screen.availHeight;
      var popW = 210, popH = 165;
      var leftPos = (w-popW)/2, topPos = (h-popH)/2;
      var currentColor = _dec_to_rgb(document.getElementById("wysiwyg" + n).contentWindow.document.queryCommandValue(id));
   
	    window.open(popupsDir + 'select_color.html?color=' + currentColor + '&command=' + id + '&wysiwyg=' + n,'popup','location=0,status=0,scrollbars=0,width=' + popW + ',height=' + popH + ',top=' + topPos + ',left=' + leftPos);
    }
	  
		// InsertImage
	  else if (id == "InsertImage") {
      window.open(popupsDir + 'insert_image.html?wysiwyg=' + n,'popup','location=0,status=0,scrollbars=0,resizable=0,width=400,height=190');
	  }
	  
		// InsertTable
	  else if (id == "InsertTable") {
	    window.open(popupsDir + 'create_table.html?wysiwyg=' + n,'popup','location=0,status=0,scrollbars=0,resizable=0,width=400,height=360');
	  }
	  
		// CreateLink
	  else if (id == "CreateLink") {
	    window.open(popupsDir + 'insert_hyperlink.html?wysiwyg=' + n,'popup','location=0,status=0,scrollbars=0,resizable=0,width=300,height=110');
	  }
	  
		// ViewSource
    else if (id == "ViewSource") {
	   viewSource(n);
	}
		
		// WY
		else if (id == "ViewText") {
	    viewText(n);
	  }
	  
	  // ViewText
		else if (id == "WY") {
	    WY(n);
	  }

		// Help
		else if (id == "Help") {
		//	window.open(popupsDir + 'insert_image.php?wysiwyg=' + n,'popup','location=0,status=0,scrollbars=0,resizable=0,width=400,height=408'); 
	    window.open(popupsDir + 'about.html','popup','location=0,status=0,scrollbars=0,resizable=0,width=400,height=330');
	  }
	  
		// Every other command
	  else {
      document.getElementById("wysiwyg" + n).contentWindow.document.execCommand(id, false, null);
		}
  }
};



/* ---------------------------------------------------------------------- *\
  Function    : insertHTML()
  Description : insert HTML into WYSIWYG in rich text
  Usage       : insertHTML(<b>hello</b>, "textareaID")
  Arguments   : html - The HTML being inserted (e.g. <b>hello</b>)
                n  - The editor identifier that the HTML 
								     will be inserted into (the textarea's ID)
\* ---------------------------------------------------------------------- */
function insertHTML(html, n) {

  var browserName = navigator.appName;
	 	 
	if (browserName == "Microsoft Internet Explorer") {	  
	  document.getElementById('wysiwyg' + n).contentWindow.document.selection.createRange().pasteHTML(html);   
	} 
	 
	else {
	  var div = document.getElementById('wysiwyg' + n).contentWindow.document.createElement("div");
		 
		div.innerHTML = html;
		var node = insertNodeAtSelection(div, n);		
	}
	
}


/* ---------------------------------------------------------------------- *\
  Function    : insertNodeAtSelection()
  Description : insert HTML into WYSIWYG in rich text (mozilla)
  Usage       : insertNodeAtSelection(insertNode, n)
  Arguments   : insertNode - The HTML being inserted (must be innerHTML 
	                           inserted within a div element)
                n          - The editor identifier that the HTML will be 
								             inserted into (the textarea's ID)
\* ---------------------------------------------------------------------- */
function insertNodeAtSelection(insertNode, n) {
  // get current selection
  var sel = document.getElementById('wysiwyg' + n).contentWindow.getSelection();

  // get the first range of the selection
  // (there's almost always only one range)
  var range = sel.getRangeAt(0);

  // deselect everything
  sel.removeAllRanges();

  // remove content of current selection from document
  range.deleteContents();

  // get location of current selection
  var container = range.startContainer;
  var pos = range.startOffset;

  // make a new range for the new selection
  range=document.createRange();

  if (container.nodeType==3 && insertNode.nodeType==3) {

    // if we insert text in a textnode, do optimized insertion
    container.insertData(pos, insertNode.nodeValue);

    // put cursor after inserted text
    range.setEnd(container, pos+insertNode.length);
    range.setStart(container, pos+insertNode.length);
  } 
	
	else {
    var afterNode;
    
		if (container.nodeType==3) {
      // when inserting into a textnode
      // we create 2 new textnodes
      // and put the insertNode in between

      var textNode = container;
      container = textNode.parentNode;
      var text = textNode.nodeValue;

      // text before the split
      var textBefore = text.substr(0,pos);
      // text after the split
      var textAfter = text.substr(pos);

      var beforeNode = document.createTextNode(textBefore);
      afterNode = document.createTextNode(textAfter);

      // insert the 3 new nodes before the old one
      container.insertBefore(afterNode, textNode);
      container.insertBefore(insertNode, afterNode);
      container.insertBefore(beforeNode, insertNode);

      // remove the old node
      container.removeChild(textNode);
    } 
	
	  else {
      // else simply insert the node
      afterNode = container.childNodes[pos];
      container.insertBefore(insertNode, afterNode);
    }

    range.setEnd(afterNode, 0);
    range.setStart(afterNode, 0);
  }

  sel.addRange(range);
};

	

/* ---------------------------------------------------------------------- *\
  Function    : _dec_to_rgb
  Description : convert a decimal color value to rgb hexadecimal
  Usage       : var hex = _dec_to_rgb('65535');   // returns FFFF00
  Arguments   : value   - dec value
\* ---------------------------------------------------------------------- */

function _dec_to_rgb(value) {
  var hex_string = "";
  for (var hexpair = 0; hexpair < 3; hexpair++) {
    var myByte = value & 0xFF;            // get low byte
    value >>= 8;                          // drop low byte
    var nybble2 = myByte & 0x0F;          // get low nybble (4 bits)
    var nybble1 = (myByte >> 4) & 0x0F;   // get high nybble
    hex_string += nybble1.toString(16);   // convert nybble to hex
    hex_string += nybble2.toString(16);   // convert nybble to hex
  }
  return hex_string.toUpperCase();
};



/* ---------------------------------------------------------------------- *\
  Function    : outputFontSelect()
  Description : creates the Font Select drop down and inserts it into 
	              the toolbar
  Usage       : outputFontSelect(n)
  Arguments   : n   - The editor identifier that the Font Select will update
	                    when making font changes (the textarea's ID)
\* ---------------------------------------------------------------------- */
function outputFontSelect(n) {

  var FontSelectObj        = ToolbarList['selectfont'];
  var FontSelect           = FontSelectObj[2];
  var FontSelectOn         = FontSelectObj[3];
  
	Fonts.sort();
	var FontSelectDropDown = new Array;
	FontSelectDropDown[n] = '<table border="0" cellpadding="0" cellspacing="0"><tr><td onMouseOver="document.getElementById(\'selectFont' + n + '\').src=\'' + FontSelectOn + '\';" onMouseOut="document.getElementById(\'selectFont' + n + '\').src=\'' + FontSelect + '\';"><img src="' + FontSelect + '" id="selectFont' + n + '" width="85" height="20" onClick="showFonts(\'' + n + '\');" unselectable="on"><br>';
	FontSelectDropDown[n] += '<span id="Fonts' + n + '" class="dropdown" style="width: 145px;">';

	for (var i = 0; i <= Fonts.length;) {
	  if (Fonts[i]) {
      FontSelectDropDown[n] += '<button type="button" onClick="formatText(\'FontName\',\'' + n + '\',\'' + Fonts[i] + '\')\; hideFonts(\'' + n + '\');" onMouseOver="this.className=\'mouseOver\'" onMouseOut="this.className=\'mouseOut\'" class="mouseOut" style="width: 120px;"><table cellpadding="0" cellspacing="0" border="0"><tr><td align="left" style="font-family:' + Fonts[i] + '; font-size: 12px;">' + Fonts[i] + '</td></tr></table></button><br>';	
    }	  
	  i++;
  }
	FontSelectDropDown[n] += '</span></td></tr></table>';
	document.getElementById('FontSelect' + n).insertAdjacentHTML("afterBegin", FontSelectDropDown[n]);
};



/* ---------------------------------------------------------------------- *\
  Function    : outputFontSizes()
  Description : creates the Font Sizes drop down and inserts it into 
	              the toolbar
  Usage       : outputFontSelect(n)
  Arguments   : n   - The editor identifier that the Font Sizes will update
	                    when making font changes (the textarea's ID)
\* ---------------------------------------------------------------------- */
function outputFontSizes(n) {

  var FontSizeObj        = ToolbarList['selectsize'];
  var FontSize           = FontSizeObj[2];
  var FontSizeOn         = FontSizeObj[3];

	FontSizes.sort();
	var FontSizesDropDown = new Array;
	FontSizesDropDown[n] = '<table border="0" cellpadding="0" cellspacing="0"><tr><td onMouseOver="document.getElementById(\'selectSize' + n + '\').src=\'' + FontSizeOn + '\';" onMouseOut="document.getElementById(\'selectSize' + n + '\').src=\'' + FontSize + '\';"><img src="' + FontSize + '" id="selectSize' + n + '" width="49" height="20" onClick="showFontSizes(\'' + n + '\');" unselectable="on"><br>';
  FontSizesDropDown[n] += '<span id="Sizes' + n + '" class="dropdown" style="width: 170px;">';

	for (var i = 0; i <= FontSizes.length;) {
	  if (FontSizes[i]) {
      FontSizesDropDown[n] += '<button type="button" onClick="formatText(\'FontSize\',\'' + n + '\',\'' + FontSizes[i] + '\')\;hideFontSizes(\'' + n + '\');" onMouseOver="this.className=\'mouseOver\'" onMouseOut="this.className=\'mouseOut\'" class="mouseOut" style="width: 145px;"><table cellpadding="0" cellspacing="0" border="0"><tr><td align="left" style="font-family: arial, verdana, helvetica;"><font size="' + FontSizes[i] + '">size ' + FontSizes[i] + '</font></td></tr></table></button><br>';	
    }	  
	  i++;
  }
	FontSizesDropDown[n] += '</span></td></tr></table>';
	document.getElementById('FontSizes' + n).insertAdjacentHTML("afterBegin", FontSizesDropDown[n]);
};



/* ---------------------------------------------------------------------- *\
  Function    : hideFonts()
  Description : Hides the list of font names in the font select drop down
  Usage       : hideFonts(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function hideFonts(n) {
  document.getElementById('Fonts' + n).style.display = 'none'; 
};



/* ---------------------------------------------------------------------- *\
  Function    : hideFontSizes()
  Description : Hides the list of font sizes in the font sizes drop down
  Usage       : hideFontSizes(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function hideFontSizes(n) {
  document.getElementById('Sizes' + n).style.display = 'none'; 
};



/* ---------------------------------------------------------------------- *\
  Function    : showFonts()
  Description : Shows the list of font names in the font select drop down
  Usage       : showFonts(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function showFonts(n) { 
  if (document.getElementById('Fonts' + n).style.display == 'block') {
    document.getElementById('Fonts' + n).style.display = 'none';
	}
  else {
    document.getElementById('Fonts' + n).style.display = 'block'; 
    document.getElementById('Fonts' + n).style.position = 'absolute';		
  }
};



/* ---------------------------------------------------------------------- *\
  Function    : showFontSizes()
  Description : Shows the list of font sizes in the font sizes drop down
  Usage       : showFonts(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function showFontSizes(n) { 
  if (document.getElementById('Sizes' + n).style.display == 'block') {
    document.getElementById('Sizes' + n).style.display = 'none';
	}
  else {
    document.getElementById('Sizes' + n).style.display = 'block'; 
    document.getElementById('Sizes' + n).style.position = 'absolute';		
  }
};



/* ---------------------------------------------------------------------- *\
  Function    : WY()
  Description : Shows the HTML source code generated by the WYSIWYG editor
  Usage       : showFonts(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function WY(n) {
	
	if (viewTextMode == 1)
	{viewText(n)}
	
	
  var getDocument = document.getElementById("wysiwyg" + n).contentWindow.document;
  
    var iHTML = getDocument.body.innerHTML;
   
   workspace.createNote({
      'text':iHTML});
	 
	
}

function viewSource(n) {
  var getDocument = document.getElementById("wysiwyg" + n).contentWindow.document;
  var browserName = navigator.appName;
	
	// View Source for IE 	 
  if (browserName == "Microsoft Internet Explorer") {
    var iHTML = getDocument.body.innerHTML;
    getDocument.body.innerText = iHTML;
	}
 
  // View Source for Mozilla/Netscape
  else {
    var html = document.createTextNode(getDocument.body.innerHTML);
    getDocument.body.innerHTML = "";
    getDocument.body.appendChild(html);
	}
  
	// Hide the HTML Mode button and show the Text Mode button
  document.getElementById('HTMLMode' + n).style.display = 'none'; 
	document.getElementById('textMode' + n).style.display = 'block';
	
	// set the font values for displaying HTML source
	getDocument.body.style.fontSize = "12px";
	getDocument.body.style.fontFamily = "Courier New"; 
	
  viewTextMode = 1;
};



/* ---------------------------------------------------------------------- *\
  Function    : viewTEXT()
  Description : Shows the HTML source code generated by the WYSIWYG editor
  Usage       : showFonts(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function viewText(n) { 
  var getDocument = document.getElementById("wysiwyg" + n).contentWindow.document;
  var browserName = navigator.appName;
	
	// View Text for IE 	  	 
  if (browserName == "Microsoft Internet Explorer") {
    var iText = getDocument.body.innerText;
    getDocument.body.innerHTML = iText;
	}
  
	// View Text for Mozilla/Netscape
  else {
    var html = getDocument.body.ownerDocument.createRange();
    html.selectNodeContents(getDocument.body);
    getDocument.body.innerHTML = html.toString();
	}
  
	// Hide the Text Mode button and show the HTML Mode button
  document.getElementById('textMode' + n).style.display = 'none'; 
	document.getElementById('HTMLMode' + n).style.display = 'block';
	
	// reset the font values
  getDocument.body.style.fontSize = "";
	getDocument.body.style.fontFamily = ""; 
	viewTextMode = 0;
};

/* ---------------------------------------------------------------------- *\
  Function    : updateTextArea()
  Description : Updates the text area value with the HTML source of the WYSIWYG
  Usage       : updateTextArea(n)
  Arguments   : n   - The editor identifier (the textarea's ID)
\* ---------------------------------------------------------------------- */
function updateTextArea(n) {
  document.getElementById(n).value = document.getElementById("wysiwyg" + n).contentWindow.document.body.innerHTML;
};