You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@camel.apache.org by js...@apache.org on 2009/03/19 12:24:20 UTC

svn commit: r755931 [7/9] - in /camel/trunk/components/camel-web/src/main/webapp/js/bespin: ./ client/ cmd/ editor/ mobwrite/ page/ page/dashboard/ page/editor/ page/index/ syntax/ user/ util/

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/mobwrite/form.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/mobwrite/form.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/mobwrite/form.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/mobwrite/form.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,638 @@
+/**
+ * MobWrite - Real-time Synchronization and Collaboration Service
+ *
+ * Copyright 2008 Neil Fraser
+ * http://code.google.com/p/google-mobwrite/
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *   http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+/**
+ * @fileoverview This client-side code interfaces with form elements.
+ * @author fraser@google.com (Neil Fraser)
+ */
+
+dojo.provide("bespin.mobwrite.form");
+
+// FORM
+
+
+/**
+ * Handler to accept forms as elements that can be shared.
+ * Share each of the form's elements.
+ * @param {*} node Object or ID of object to share
+ * @return {Object?} A sharing object or null.
+ */
+mobwrite.shareHandlerForm = function(form) {
+  if (typeof form == 'string') {
+    form = document.getElementById(form) || document.forms[form];
+  }
+  if (form && 'tagName' in form && form.tagName == 'FORM') {
+    for (var x = 0, el; el = form.elements[x]; x++) {
+      mobwrite.share(el);
+    }
+  }
+  return null;
+};
+
+
+// Register this shareHandler with MobWrite.
+mobwrite.shareHandlers.push(mobwrite.shareHandlerForm);
+
+
+// HIDDEN
+
+
+/**
+ * Constructor of shared object representing a hidden input.
+ * @param {Node} node A hidden element
+ * @constructor
+ */
+mobwrite.shareHiddenObj = function(node) {
+  // Call our prototype's constructor.
+  mobwrite.shareObj.apply(this, [node.id]);
+  this.element = node;
+};
+
+
+// The hidden input's shared object's parent is a shareObj.
+mobwrite.shareHiddenObj.prototype = new mobwrite.shareObj('');
+
+
+/**
+ * Retrieve the user's content.
+ * @return {string} Plaintext content.
+ */
+mobwrite.shareHiddenObj.prototype.getClientText = function() {
+  // Numeric data should use overwrite mode.
+  this.mergeChanges = !this.element.value.match(/^\s*-?[\d.]+\s*$/);
+  return this.element.value;
+};
+
+
+/**
+ * Set the user's content.
+ * @param {string} text New content
+ */
+mobwrite.shareHiddenObj.prototype.setClientText = function(text) {
+  this.element.value = text;
+};
+
+
+/**
+ * Handler to accept hidden fields as elements that can be shared.
+ * If the element is a hidden field, create a new sharing object.
+ * @param {*} node Object or ID of object to share
+ * @return {Object?} A sharing object or null.
+ */
+mobwrite.shareHiddenObj.shareHandler = function(node) {
+  if (typeof node == 'string') {
+    node = document.getElementById(node);
+  }
+  if (node && 'type' in node && node.type == 'hidden') {
+    return new mobwrite.shareHiddenObj(node);
+  }
+  return null;
+};
+
+
+// Register this shareHandler with MobWrite.
+mobwrite.shareHandlers.push(mobwrite.shareHiddenObj.shareHandler);
+
+
+// CHECKBOX
+
+
+/**
+ * Constructor of shared object representing a checkbox.
+ * @param {Node} node A checkbox element
+ * @constructor
+ */
+mobwrite.shareCheckboxObj = function(node) {
+  // Call our prototype's constructor.
+  mobwrite.shareObj.apply(this, [node.id]);
+  this.element = node;
+  this.mergeChanges = false;
+};
+
+
+// The checkbox shared object's parent is a shareObj.
+mobwrite.shareCheckboxObj.prototype = new mobwrite.shareObj('');
+
+
+/**
+ * Retrieve the user's check.
+ * @return {string} Plaintext content.
+ */
+mobwrite.shareCheckboxObj.prototype.getClientText = function() {
+  return this.element.checked ? this.element.value : '';
+};
+
+
+/**
+ * Set the user's check.
+ * @param {string} text New content
+ */
+mobwrite.shareCheckboxObj.prototype.setClientText = function(text) {
+  // Safari has a blank value if not set, all other browsers have 'on'.
+  var value = this.element.value || 'on';
+  this.element.checked = (text == value);
+  this.fireChange(this.element);
+};
+
+
+/**
+ * Handler to accept checkboxen as elements that can be shared.
+ * If the element is a checkbox, create a new sharing object.
+ * @param {*} node Object or ID of object to share
+ * @return {Object?} A sharing object or null.
+ */
+mobwrite.shareCheckboxObj.shareHandler = function(node) {
+  if (typeof node == 'string') {
+    node = document.getElementById(node);
+  }
+  if (node && 'type' in node && node.type == 'checkbox') {
+    return new mobwrite.shareCheckboxObj(node);
+  }
+  return null;
+};
+
+
+// Register this shareHandler with MobWrite.
+mobwrite.shareHandlers.push(mobwrite.shareCheckboxObj.shareHandler);
+
+
+// SELECT OPTION
+
+
+/**
+ * Constructor of shared object representing a select box.
+ * @param {Node} node A select box element
+ * @constructor
+ */
+mobwrite.shareSelectObj = function(node) {
+  // Call our prototype's constructor.
+  mobwrite.shareObj.apply(this, [node.id]);
+  this.element = node;
+  // If the select box is select-one, use overwrite mode.
+  // If it is select-multiple, use text merge mode.
+  this.mergeChanges = (node.type == 'select-multiple');
+};
+
+
+// The select box shared object's parent is a shareObj.
+mobwrite.shareSelectObj.prototype = new mobwrite.shareObj('');
+
+
+/**
+ * Retrieve the user's selection(s).
+ * @return {string} Plaintext content.
+ */
+mobwrite.shareSelectObj.prototype.getClientText = function() {
+  var selected = [];
+  for (var x = 0, option; option = this.element.options[x]; x++) {
+    if (option.selected) {
+      selected.push(option.value);
+    }
+  }
+  return selected.join('\00');
+};
+
+
+/**
+ * Set the user's selection(s).
+ * @param {string} text New content
+ */
+mobwrite.shareSelectObj.prototype.setClientText = function(text) {
+  text = '\00' + text + '\00';
+  for (var x = 0, option; option = this.element.options[x]; x++) {
+    option.selected = (text.indexOf('\00' + option.value + '\00') != -1);
+  }
+  this.fireChange(this.element);
+};
+
+
+/**
+ * Handler to accept select boxen as elements that can be shared.
+ * If the element is a select box, create a new sharing object.
+ * @param {*} node Object or ID of object to share
+ * @return {Object?} A sharing object or null.
+ */
+mobwrite.shareSelectObj.shareHandler = function(node) {
+  if (typeof node == 'string') {
+    node = document.getElementById(node);
+  }
+  if (node && 'type' in node && (node.type == 'select-one' || node.type == 'select-multiple')) {
+    return new mobwrite.shareSelectObj(node);
+  }
+  return null;
+};
+
+
+// Register this shareHandler with MobWrite.
+mobwrite.shareHandlers.push(mobwrite.shareSelectObj.shareHandler);
+
+
+// RADIO BUTTON
+
+
+/**
+ * Constructor of shared object representing a radio button.
+ * @param {Node} node A radio button element
+ * @constructor
+ */
+mobwrite.shareRadioObj = function(node) {
+  // Call our prototype's constructor.
+  mobwrite.shareObj.apply(this, [node.id]);
+  this.elements = [node];
+  this.form = node.form;
+  this.name = node.name;
+  this.mergeChanges = false;
+};
+
+
+// The radio button shared object's parent is a shareObj.
+mobwrite.shareRadioObj.prototype = new mobwrite.shareObj('');
+
+
+/**
+ * Retrieve the user's check.
+ * @return {string} Plaintext content.
+ */
+mobwrite.shareRadioObj.prototype.getClientText = function() {
+  // Group of radio buttons
+  for (var x = 0; x < this.elements.length; x++) {
+    if (this.elements[x].checked) {
+      return this.elements[x].value
+    }
+  }
+  // Nothing checked.
+  return '';
+};
+
+
+/**
+ * Set the user's check.
+ * @param {string} text New content
+ */
+mobwrite.shareRadioObj.prototype.setClientText = function(text) {
+  for (var x = 0; x < this.elements.length; x++) {
+    this.elements[x].checked = (text == this.elements[x].value);
+    this.fireChange(this.elements[x]);
+  }
+};
+
+
+/**
+ * Handler to accept radio buttons as elements that can be shared.
+ * If the element is a radio button, create a new sharing object.
+ * @param {*} node Object or ID of object to share
+ * @return {Object?} A sharing object or null.
+ */
+mobwrite.shareRadioObj.shareHandler = function(node) {
+  if (typeof node == 'string') {
+    node = document.getElementById(node);
+  }
+  if (node && 'type' in node && node.type == 'radio') {
+    // Check to see if this is another element of an existing radio button group.
+    for (var id in mobwrite.shared) {
+      if (mobwrite.shared[id].form == node.form && mobwrite.shared[id].name == node.name) {
+        mobwrite.shared[id].elements.push(node);
+        return null;
+      }
+    }
+    // Create new radio button object.
+    return new mobwrite.shareRadioObj(node);
+  }
+  return null;
+};
+
+
+// Register this shareHandler with MobWrite.
+mobwrite.shareHandlers.push(mobwrite.shareRadioObj.shareHandler);
+
+
+// TEXTAREA, TEXT & PASSWORD INPUTS
+
+
+/**
+ * Constructor of shared object representing a text field.
+ * @param {Node} node A textarea, text or password input
+ * @constructor
+ */
+mobwrite.shareTextareaObj = function(node) {
+  // Call our prototype's constructor.
+  mobwrite.shareObj.apply(this, [node.id]);
+  this.element = node;
+  if (node.type == 'password') {
+    // Use overwrite mode for password field, users can't see.
+    this.mergeChanges = false;
+  }
+};
+
+
+// The textarea shared object's parent is a shareObj.
+mobwrite.shareTextareaObj.prototype = new mobwrite.shareObj('');
+
+
+/**
+ * Retrieve the user's text.
+ * @return {string} Plaintext content.
+ */
+mobwrite.shareTextareaObj.prototype.getClientText = function() {
+  var text = mobwrite.shareTextareaObj.normalizeLinebreaks_(this.element.value);
+  if (this.element.type == 'text') {
+    // Numeric data should use overwrite mode.
+    this.mergeChanges = !text.match(/^\s*-?[\d.]+\s*$/);
+  }
+  return text;
+};
+
+
+/**
+ * Set the user's text.
+ * @param {string} text New text
+ */
+mobwrite.shareTextareaObj.prototype.setClientText = function(text) {
+  this.element.value = text;
+  this.fireChange(this.element);
+};
+
+
+/**
+ * Modify the user's plaintext by applying a series of patches against it.
+ * @param {Array<patch_obj>} patches Array of Patch objects
+ */
+mobwrite.shareTextareaObj.prototype.patchClientText = function(patches) {
+  // Set some constants which tweak the matching behaviour.
+  // Tweak the relative importance (0.0 = accuracy, 1.0 = proximity)
+  this.dmp.Match_Balance = 0.5;
+  // At what point is no match declared (0.0 = perfection, 1.0 = very loose)
+  this.dmp.Match_Threshold = 0.6;
+
+  var oldClientText = this.getClientText();
+  var result = this.dmp.patch_apply(patches, oldClientText);
+  // Set the new text only if there is a change to be made.
+  if (oldClientText != result[0]) {
+    var cursor = this.captureCursor_();
+    this.setClientText(result[0]);
+    if (cursor) {
+      this.restoreCursor_(cursor);
+    }
+  }
+  if (mobwrite.debug) {
+    for (var x = 0; x < result[1].length; x++) {
+      if (result[1][x]) {
+        console.info('Patch OK.');
+      } else {
+        console.warn('Patch failed: ' + patches[x]);
+      }
+   }
+  }
+};
+
+
+/**
+ * Record information regarding the current cursor.
+ * @return {Object?} Context information of the cursor.
+ * @private
+ */
+mobwrite.shareTextareaObj.prototype.captureCursor_ = function() {
+  if ('activeElement' in this.element && !this.element.activeElement) {
+    // Safari specific code.
+    // Restoring a cursor in an unfocused element causes the focus to jump.
+    return null;
+  }
+  var padLength = this.dmp.Match_MaxBits / 2;  // Normally 16.
+  var text = this.element.value;
+  var cursor = {};
+  if ('selectionStart' in this.element) {  // W3
+    var selectionStart = this.element.selectionStart;
+    var selectionEnd = this.element.selectionEnd;
+    cursor.startPrefix = text.substring(selectionStart - padLength, selectionStart);
+    cursor.startSuffix = text.substring(selectionStart, selectionStart + padLength);
+    cursor.startPercent = selectionStart / text.length;
+    cursor.collapsed = (selectionStart == selectionEnd);
+    if (!cursor.collapsed) {
+      cursor.endPrefix = text.substring(selectionEnd - padLength, selectionEnd);
+      cursor.endSuffix = text.substring(selectionEnd, selectionEnd + padLength);
+      cursor.endPercent = selectionEnd / text.length;
+    }
+  } else {  // IE
+    // Walk up the tree looking for this textarea's document node.
+    var doc = this.element;
+    while (doc.parentNode) {
+      doc = doc.parentNode;
+    }
+    if (!doc.selection || !doc.selection.createRange) {
+      // Not IE?
+      return null;
+    }
+    var range = doc.selection.createRange();
+    if (range.parentElement() != this.element) {
+      // Cursor not in this textarea.
+      return null;
+    }
+    var newRange = doc.body.createTextRange();
+
+    cursor.collapsed = (range.text == '');
+    newRange.moveToElementText(this.element);
+    if (!cursor.collapsed) {
+      newRange.setEndPoint('EndToEnd', range);
+      cursor.endPrefix = newRange.text;
+      cursor.endPercent = cursor.endPrefix.length / text.length;
+      cursor.endPrefix = cursor.endPrefix.substring(cursor.endPrefix.length - padLength);
+    }
+    newRange.setEndPoint('EndToStart', range);
+    cursor.startPrefix = newRange.text;
+    cursor.startPercent = cursor.startPrefix.length / text.length;
+    cursor.startPrefix = cursor.startPrefix.substring(cursor.startPrefix.length - padLength);
+
+    newRange.moveToElementText(this.element);
+    newRange.setEndPoint('StartToStart', range);
+    cursor.startSuffix = newRange.text.substring(0, padLength);
+    if (!cursor.collapsed) {
+      newRange.setEndPoint('StartToEnd', range);
+      cursor.endSuffix = newRange.text.substring(0, padLength);
+    }
+  }
+
+  // Record scrollbar locations
+  if ('scrollTop' in this.element) {
+    cursor.scrollTop = this.element.scrollTop / this.element.scrollHeight;
+    cursor.scrollLeft = this.element.scrollLeft / this.element.scrollWidth;
+  }
+  
+  // alert(cursor.startPrefix + '|' + cursor.startSuffix + ' ' +
+  //     cursor.startPercent + '\n' + cursor.endPrefix + '|' +
+  //     cursor.endSuffix + ' ' + cursor.endPercent + '\n' +
+  //     cursor.scrollTop + ' x ' + cursor.scrollLeft);
+  return cursor;
+};
+
+
+/**
+ * Attempt to restore the cursor's location.
+ * @param {Object} cursor Context information of the cursor.
+ * @private
+ */
+mobwrite.shareTextareaObj.prototype.restoreCursor_ = function(cursor) {
+  // Set some constants which tweak the matching behaviour.
+  // Tweak the relative importance (0.0 = accuracy, 1.0 = proximity)
+  this.dmp.Match_Balance = 0.4;
+  // At what point is no match declared (0.0 = perfection, 1.0 = very loose)
+  this.dmp.Match_Threshold = 0.9;
+
+  var padLength = this.dmp.Match_MaxBits / 2;  // Normally 16.
+  var newText = this.element.value;
+
+  // Find the start of the selection in the new text.
+  var pattern1 = cursor.startPrefix + cursor.startSuffix;
+  var cursorStartPoint = this.dmp.match_main(newText, pattern1,
+      Math.round(Math.max(0, Math.min(newText.length,
+          cursor.startPercent * newText.length - padLength))));
+  if (cursorStartPoint !== null) {
+    var pattern2 = newText.substring(cursorStartPoint,
+                                     cursorStartPoint + pattern1.length);
+    //alert(pattern1 + '\nvs\n' + pattern2);
+    // Run a diff to get a framework of equivalent indicies.
+    var diff = this.dmp.diff_main(pattern1, pattern2, false);
+    cursorStartPoint += this.dmp.diff_xIndex(diff, cursor.startPrefix.length);
+  }
+
+  var cursorEndPoint = null;
+  if (!cursor.collapsed) {
+    // Find the end of the selection in the new text.
+    pattern1 = cursor.endPrefix + cursor.endSuffix;
+    cursorEndPoint = this.dmp.match_main(newText, pattern1,
+        Math.round(Math.max(0, Math.min(newText.length,
+            cursor.endPercent * newText.length - padLength))));
+    if (cursorEndPoint !== null) {
+      var pattern2 = newText.substring(cursorEndPoint,
+                                       cursorEndPoint + pattern1.length);
+      //alert(pattern1 + '\nvs\n' + pattern2);
+      // Run a diff to get a framework of equivalent indicies.
+      var diff = this.dmp.diff_main(pattern1, pattern2, false);
+      cursorEndPoint += this.dmp.diff_xIndex(diff, cursor.endPrefix.length);
+    }
+  }
+  
+  // Deal with loose ends
+  if (cursorStartPoint === null && cursorEndPoint !== null) {
+    // Lost the start point of the selection, but we have the end point.
+    // Collapse to end point.
+    cursorStartPoint = cursorEndPoint;
+  } else if (cursorStartPoint === null && cursorEndPoint === null) {
+    // Lost both start and end points.
+    // Jump to the aproximate percentage point of start.
+    cursorStartPoint = Math.round(cursor.startPercent * newText.length);
+  }
+  if (cursorEndPoint == null) {
+    // End not known, collapse to start.
+    cursorEndPoint = cursorStartPoint;
+  }
+  
+  // Restore selection.
+  if ('selectionStart' in this.element) {  // W3
+    this.element.selectionStart = cursorStartPoint;
+    this.element.selectionEnd = cursorEndPoint;
+  } else {  // IE
+    // Walk up the tree looking for this textarea's document node.
+    var doc = this.element;
+    while (doc.parentNode) {
+      doc = doc.parentNode;
+    }
+    if (!doc.selection || !doc.selection.createRange) {
+      // Not IE?
+      return;
+    }
+    // IE's TextRange.move functions treat '\r\n' as one character.
+    var snippet = this.element.value.substring(0, cursorStartPoint);
+    var ieStartPoint = snippet.replace(/\r\n/g, '\n').length;
+
+    var newRange = doc.body.createTextRange();
+    newRange.moveToElementText(this.element);
+    newRange.collapse(true);
+    newRange.moveStart('character', ieStartPoint);
+    if (!cursor.collapsed) {
+      snippet = this.element.value.substring(cursorStartPoint, cursorEndPoint);
+      var ieMidLength = snippet.replace(/\r\n/g, '\n').length;
+      newRange.moveEnd('character', ieMidLength);
+    }
+    newRange.select();
+  }
+
+  // Restore scrollbar locations
+  if ('scrollTop' in cursor) {
+    this.element.scrollTop = cursor.scrollTop * this.element.scrollHeight;
+    this.element.scrollLeft = cursor.scrollLeft * this.element.scrollWidth;
+  }
+};
+
+
+/**
+ * Ensure that all linebreaks are CR+LF
+ * @param {string} text Text with unknown line breaks
+ * @return {string} Text with normalized linebreaks
+ * @private
+ */
+mobwrite.shareTextareaObj.normalizeLinebreaks_ = function(text) {
+  var oldtext = '';
+  if (text != '') {
+    // First, fix the first/last chars.
+    if (text.charAt(0) == '\n') {
+      text = '\r' + text;
+    }
+    if (text.charAt(text.length - 1) == '\r') {
+      text = text + '\n';
+    }
+  }
+  // Second, fix the middle chars.
+  while (oldtext != text) {
+    oldtext = text;
+    text = text.replace(/([^\r])\n/g, '$1\r\n');
+    text = text.replace(/\r([^\n])/g, '\r\n$1');
+  }
+  return text;
+};
+
+
+/**
+ * Handler to accept text fields as elements that can be shared.
+ * If the element is a textarea, text or password input, create a new
+ * sharing object.
+ * @param {*} node Object or ID of object to share
+ * @return {Object?} A sharing object or null.
+ */
+mobwrite.shareTextareaObj.shareHandler = function(node) {
+  if (typeof node == 'string') {
+    node = document.getElementById(node);
+  }
+  if (node && 'value' in node && 'type' in node && (node.type == 'textarea' ||
+      node.type == 'text' || node.type == 'password')) {
+    if (mobwrite.UA_webkit) {
+      // Safari needs to track which text element has the focus.
+      node.addEventListener('focus', function() {this.activeElement = true},
+          false);
+      node.addEventListener('blur', function() {this.activeElement = false},
+          false);
+      node.activeElement = false;
+    }
+    return new mobwrite.shareTextareaObj(node);
+  }
+  return null;
+};
+
+
+// Register this shareHandler with MobWrite.
+mobwrite.shareHandlers.push(mobwrite.shareTextareaObj.shareHandler);

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/mobwrite/integrate.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/mobwrite/integrate.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/mobwrite/integrate.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/mobwrite/integrate.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,126 @@
+
+dojo.provide("bespin.mobwrite.integrate");
+
+// BESPIN
+
+/**
+ * Constructor of shared object representing a text field.
+ * @param {Node} node A textarea, text or password input
+ * @constructor
+ */
+mobwrite.shareBespinObj = function(node) {
+    this._editSession = node;
+
+    var username = this._editSession.username || "[none]";
+    var project = this._editSession.project;
+    var path = this._editSession.path;
+    if (path.indexOf("/") != 0) {
+        path = "/" + path;
+    }
+
+    var id = username + "/" + project + path;
+    // Call our prototype's constructor.
+    mobwrite.shareObj.apply(this, [id]);
+};
+
+// The textarea shared object's parent is a shareObj.
+mobwrite.shareBespinObj.prototype = new mobwrite.shareObj('');
+
+/**
+ * Retrieve the user's text.
+ * @return {string} Plaintext content.
+ */
+mobwrite.shareBespinObj.prototype.getClientText = function() {
+    // Was:
+    // var text = this.element.value;
+    var text = this._editSession.editor.model.getDocument();
+    text = mobwrite.shareBespinObj.normalizeLinebreaks_(text);
+    return text;
+};
+
+/**
+ * Set the user's text.
+ * @param {string} text New text
+ */
+mobwrite.shareBespinObj.prototype.setClientText = function(text) {
+    // Was:
+    // this.element.value = text;
+    // this.fireChange(this.element);
+    this._editSession.editor.model.insertDocument(text);
+};
+
+/**
+ * Modify the user's plaintext by applying a series of patches against it.
+ * @param {Array<patch_obj>} patches Array of Patch objects
+ */
+mobwrite.shareBespinObj.prototype.patchClientText = function(patches) {
+  // Set some constants which tweak the matching behaviour.
+  // Tweak the relative importance (0.0 = accuracy, 1.0 = proximity)
+  this.dmp.Match_Balance = 0.5;
+  // At what point is no match declared (0.0 = perfection, 1.0 = very loose)
+  this.dmp.Match_Threshold = 0.6;
+
+  var oldClientText = this.getClientText();
+  var result = this.dmp.patch_apply(patches, oldClientText);
+  // Set the new text only if there is a change to be made.
+  if (oldClientText != result[0]) {
+    // var cursor = this.captureCursor_();
+    this.setClientText(result[0]);
+    // if (cursor) {
+    //   this.restoreCursor_(cursor);
+    // }
+  }
+  if (mobwrite.debug) {
+    for (var x = 0; x < result[1].length; x++) {
+      if (result[1][x]) {
+        console.info('Patch OK.');
+      } else {
+        console.warn('Patch failed: ' + patches[x]);
+      }
+   }
+  }
+};
+
+/**
+ * Ensure that all linebreaks are CR+LF
+ * @param {string} text Text with unknown line breaks
+ * @return {string} Text with normalized linebreaks
+ * @private
+ */
+mobwrite.shareBespinObj.normalizeLinebreaks_ = function(text) {
+  var oldtext = '';
+  if (text != '') {
+    // First, fix the first/last chars.
+    if (text.charAt(0) == '\n') {
+      text = '\r' + text;
+    }
+    if (text.charAt(text.length - 1) == '\r') {
+      text = text + '\n';
+    }
+  }
+  // Second, fix the middle chars.
+  while (oldtext != text) {
+    oldtext = text;
+    text = text.replace(/([^\r])\n/g, '$1\r\n');
+    text = text.replace(/\r([^\n])/g, '\r\n$1');
+  }
+  return text;
+};
+
+/**
+ * Handler to accept text fields as elements that can be shared.
+ * If the element is a textarea, text or password input, create a new
+ * sharing object.
+ * @param {*} node Object or ID of object to share
+ * @return {Object?} A sharing object or null.
+ */
+mobwrite.shareBespinObj.shareHandler = function(node) {
+    if (node.editor && node.username && node.project && node.path) {
+        return new mobwrite.shareBespinObj(node);
+    } else {
+        return null;
+    }
+};
+
+// Register this shareHandler with MobWrite.
+mobwrite.shareHandlers.push(mobwrite.shareBespinObj.shareHandler);

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/bespin/mobwrite/integrate.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/components.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/components.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/components.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/components.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,278 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The Original Code is Bespin.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bespin Team (bespin@mozilla.com)
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+dojo.provide("bespin.page.dashboard.components");
+
+dojo.declare("bespin.page.dashboard.components.BespinBorder", th.Border, {
+    getInsets: function() {
+        return { left: 1, right: 1, bottom: 1, top: 1 };
+    },
+
+    paint: function(ctx) {
+        var d = this.component.d();
+
+        ctx.fillStyle = "rgb(93, 91, 84)";
+        ctx.fillRect(0, 0, d.b.w, 1);
+
+        ctx.fillStyle = "rgb(51, 49, 44)";
+        ctx.fillRect(0, d.b.h - 1, d.b.w, 1);
+
+        ctx.fillStyle = "rgb(94, 91, 84)";
+        ctx.fillRect(0, 0, 1, d.b.h);
+
+        ctx.fillStyle = "rgb(54, 52, 46)";
+        ctx.fillRect(d.b.w - 1, 0, 1, d.b.h);
+    }
+});
+
+dojo.declare("bespin.page.dashboard.components.BespinSessionPanel", th.components.Panel, {
+    constructor: function(parms) {
+        this.filename = new th.components.Label({ style: { color: "white" } });
+        this.path = new th.components.Label({ style: { color: "rgb(210, 210, 210)" } });
+        this.opened = new th.components.Label({ style: { color: "rgb(160, 157, 147)" } });
+        this.details = new th.components.Label({ style: { color: "rgb(160, 157, 147)" } });
+        this.editTime = new th.components.Label({ style: { color: "rgb(160, 157, 147)" } });
+
+        var labels = [ this.filename, this.path, this.opened, this.details, this.editTime ];
+
+        this.add(labels);
+
+        var panel = this;
+        for (var i = 0; i < labels.length; i++) {
+            this.bus.bind("dblclick", labels[i], function(e) {
+                panel.bus.fire("dblclick", e, panel);
+            });
+        }
+
+        this.style.border = new bespin.page.dashboard.components.BespinBorder();
+        this.style.backgroundColor = "rgb(67, 65, 58)";
+
+        this.preferredSizes = [ 13, 9, 8, 8, 8 ];
+        this.minimumSizes = [ 9, 8, 7, 7, 7 ];
+
+        this.filename.attributes.text = parms.filename;
+        this.path.attributes.text = parms.project + ": /" + parms.path;
+
+        // dummy data
+        this.opened.attributes.text = "(opened info)";
+        this.details.attributes.text = "(edit details info)";
+        this.editTime.attributes.text = "(editing time)";
+
+        this.session = { filename: parms.filename, path: parms.path, project: parms.project };
+    },
+
+    layout: function() {
+        var d = this.d();
+        var w = d.b.w - d.i.w;
+        var labels = 5;
+        var sizes = this.preferredSizes.slice();
+        var y;
+
+        while (labels > 0) {
+            y = d.i.t;
+
+            // set the fonts and clear the bounds
+            for (var i = 0; i < this.children.length; i++) {
+                var font = sizes[i] + "pt Tahoma";
+                this.children[i].style.font = font;
+
+                delete this.children[i].bounds;
+            }
+
+            var current = 0;
+
+            var h = this.filename.getPreferredHeight(w);
+            h = Math.floor(h * 0.95); // pull in the line height a bit
+            this.filename.bounds = { x: d.i.l, y: y, width: w, height: h };
+            y += h;
+
+            if (++current < labels) {
+                h = this.path.getPreferredHeight(w);
+                h = Math.floor(h * 1.2); // add a bit of margin to separate from subsequent labels
+                this.path.bounds = { x: d.i.l, y: y, width: w, height: h };
+                y += h;
+            }
+
+            if (++current < labels) {
+                h = this.opened.getPreferredHeight(w);
+                this.opened.bounds = { x: d.i.l, y: y, width: w, height: h };
+                y += h;
+            }
+
+            if (++current < labels) {
+                h = this.details.getPreferredHeight(w);
+                this.details.bounds = { x: d.i.l, y: y, width: w, height: h };
+                y += h;
+            }
+
+            if (++current < labels) {
+                h = this.editTime.getPreferredHeight(w);
+                this.editTime.bounds = { x: d.i.l, y: y, width: w, height: h };
+                y += h;
+            }
+
+            y += d.i.b;
+            if (y <= d.b.h) break;
+
+            // we're too tall, make adjustments
+
+            var changeMade = false;
+            for (var z = 2; z < sizes.length; z++) {
+                if (sizes[z] > this.minimumSizes[z]) {
+                    sizes[z]--;
+                    changeMade = true;
+                }
+            }
+            if (changeMade) continue;
+
+            if (labels > 2) {
+                labels--;
+                continue;
+            }
+
+            changeMade = false;
+            for (y = 0; y < 2; y++) {
+                if (sizes[y] > this.minimumSizes[y]) {
+                    sizes[y]--;
+                    changeMade = true;
+                }
+            }
+            if (changeMade) continue;
+
+            labels--;
+        }
+    },
+
+    getInsets: function() {
+        return { top: 5, left: 5, bottom: 5, right: 5 };
+    } 
+});
+
+dojo.declare("bespin.page.dashboard.components.BespinProjectPanelFooter", th.components.Panel, {
+    constructor: function(parms) {
+        this.add = new th.components.Button();
+
+    },
+
+    getPreferredHeight: function(width) {
+        return 17;
+    },
+
+    paintSelf: function(ctx) {
+
+        // not ready to display this yet - bg
+
+//        var d = this.d();
+//
+//        ctx.fillStyle = "rgb(85, 80, 72)";
+//        ctx.fillRect(0, 0, d.b.w, 1);
+//
+//        ctx.fillStyle = "rgb(35, 31, 28)";
+//        ctx.fillRect(0, d.b.h - 1, d.b.w, 1);
+//
+//        var gradient = ctx.createLinearGradient(0, 1, 1, d.b.h - 2);
+//        gradient.addColorStop(0, "rgb(71, 66, 57)");
+//        gradient.addColorStop(1, "rgb(65, 61, 53)");
+//        ctx.fillStyle = gradient;
+//        ctx.fillRect(0, 1, d.b.w, d.b.h - 2);
+    }
+});
+
+dojo.declare("bespin.page.dashboard.components.BespinProjectPanel", th.components.Panel, {
+    constructor: function(parms) {
+        if (!parms) parms = {};
+
+        this.projectLabel = new th.components.Label({ text: "Projects", style: { color: "white", font: "8pt Tahoma" } });
+        this.projectLabel.oldPaint = this.projectLabel.paint;
+        this.projectLabel.paint = function(ctx) {
+            var d = this.d();
+
+            ctx.fillStyle = "rgb(51, 50, 46)";
+            ctx.fillRect(0, 0, d.b.w, 1);
+
+            ctx.fillStyle = "black";
+            ctx.fillRect(0, d.b.h - 1, d.b.w, 1);
+
+            var gradient = ctx.createLinearGradient(0, 1, 0, d.b.h - 2);
+            gradient.addColorStop(0, "rgb(39, 38, 33)");
+            gradient.addColorStop(1, "rgb(22, 22, 19)");
+            ctx.fillStyle = gradient;
+            ctx.fillRect(0, 1, d.b.w, d.b.h - 2);
+
+            this.oldPaint(ctx);
+        };
+
+        this.list = new th.components.List({ allowDeselection: false, style: { backgroundColor: "rgb(61, 59, 52)", color: "white", font: "8pt Tahoma" } });
+
+        this.splitter = new th.components.Splitter({ orientation: th.HORIZONTAL });
+
+        this.footer = new bespin.page.dashboard.components.BespinProjectPanelFooter();
+
+        this.add([ this.projectLabel, this.list, this.splitter, this.footer ]);
+
+        this.bus.bind("dragstart", this.splitter, this.ondragstart, this);
+        this.bus.bind("drag", this.splitter, this.ondrag, this);
+        this.bus.bind("dragstop", this.splitter, this.ondragstop, this);
+
+        // this is a closed container
+        delete this.add;
+        delete this.remove;
+    },
+
+    ondragstart: function(e) {
+        this.startWidth = this.bounds.width;
+    },
+
+    ondrag: function(e) {
+        var delta = e.currentPos.x - e.startPos.x;
+        this.prefWidth = this.startWidth + delta;
+        this.getScene().render();
+    },
+
+    ondragstop: function(e) {
+        delete this.startWidth;
+    },
+
+    getPreferredWidth: function(height) {
+        return this.prefWidth || 150;
+    },
+
+    layout: function() {
+        var d = this.d();
+
+        var y = d.i.t;
+        var lh = this.projectLabel.getPreferredHeight(d.b.w);
+        this.projectLabel.bounds = { y: y, x: d.i.l, height: lh, width: d.b.w };
+        y += lh;
+
+        var sw = this.splitter.getPreferredWidth()
+        this.splitter.bounds = { x: d.b.w - d.i.r - sw, height: d.b.h - d.i.b - y, y: y, width: sw };
+
+        var innerWidth = d.b.w - d.i.w - sw;
+        var ph = this.footer.getPreferredHeight(innerWidth);
+        this.footer.bounds = { x: d.i.l, y: d.b.h - ph, width: innerWidth, height: ph };  
+
+        this.list.bounds = { x: d.i.l, y: y, width: innerWidth, height: this.splitter.bounds.height };
+    }
+});
\ No newline at end of file

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/components.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/dependencies.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/dependencies.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/dependencies.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/dependencies.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,59 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The Original Code is Bespin.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bespin Team (bespin@mozilla.com)
+ *
+ * ***** END LICENSE BLOCK ***** */
+ 
+dojo.provide("bespin.page.dashboard.dependencies");
+
+dojo.require("dojo.cookie"); 
+
+dojo.require("bespin.bespin"); 
+dojo.require("bespin.events");
+
+dojo.require("bespin.util.canvas");
+dojo.require("bespin.util.keys"); 
+dojo.require("bespin.util.navigate");
+dojo.require("bespin.util.path");
+dojo.require("bespin.util.tokenobject");
+dojo.require("bespin.util.urlbar");
+
+dojo.require("bespin.client.filesystem");
+dojo.require("bespin.client.settings");
+dojo.require("bespin.client.server");
+dojo.require("bespin.client.session");
+
+dojo.require("bespin.cmd.commandline");
+dojo.require("bespin.cmd.commands");
+dojo.require("bespin.cmd.dashboardcommands");
+
+// -- Thunderhead hoooooo
+dojo.require("th.helpers");
+dojo.require("th.css");
+dojo.require("th.th");
+dojo.require("th.models");
+dojo.require("th.borders");
+dojo.require("th.components");
+
+// -- The main dashboard subsystems
+dojo.require("bespin.page.dashboard.components");
+dojo.require("bespin.page.dashboard.events");
+dojo.require("bespin.page.dashboard.init");

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/dependencies.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/events.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/events.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/events.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/events.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,79 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The Original Code is Bespin.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bespin Team (bespin@mozilla.com)
+ *
+ * ***** END LICENSE BLOCK ***** */
+ 
+dojo.provide("bespin.page.dashboard.events");
+
+// After a project is imported or created, do a list
+bespin.subscribe("bespin:project:imported", function(event) {
+    bespin.page.dashboard.refreshProjects(); // get projects
+});
+
+bespin.subscribe("bespin:project:set", function(event) {
+    bespin.get('editSession').project = event.project; // set it in the session
+    
+    if (!event.fromDashboardItemSelected) {
+        // selects the project in the tree and fire the itemselected event    
+        bespin.page.dashboard.tree.lists[0].selectItemByText(event.project);
+        bespin.page.dashboard.tree.itemSelected({thComponent: bespin.page.dashboard.tree.lists[0], item: bespin.page.dashboard.tree.lists[0].selected});
+    }
+});
+
+bespin.subscribe("bespin:project:create", function(event) {
+    bespin.page.dashboard.refreshProjects(); // get projects
+});
+
+bespin.subscribe("bespin:project:delete", function(event) {
+    bespin.page.dashboard.refreshProjects(); // get projects
+});
+
+// ** {{{ Event: bespin:session:status }}} **
+// 
+// Observe a request for session status
+bespin.subscribe("bespin:session:status", function(event) {
+    var editSession = bespin.get('editSession');
+    var msg = 'Hey ' + editSession.username;
+    
+    if (editSession.project) {
+        msg += ', you appear to be highlighting the project ' + editSession.project;
+    } else {
+        msg += ", you haven't select a project yet.";
+    }
+    
+    bespin.publish("bespin:cmdline:showinfo", { msg: msg });
+});
+
+// ** {{{ Event: bespin:editor:newfile }}} **
+// 
+// Observe a request for a new file to be created
+bespin.subscribe("bespin:editor:newfile", function(event) {
+    var project = event.project;
+    if (!project) {
+        bespin.publish("bespin:cmdline:showinfo", { msg: 'The new file action requires a project' });
+        return;
+    }
+    
+    var newfilename = event.newfilename || "new.txt";
+    
+    bespin.util.navigate.editor(project, newfilename);
+});

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/events.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/init.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/init.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/init.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/init.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,395 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The Original Code is Bespin.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bespin Team (bespin@mozilla.com)
+ *
+ * ***** END LICENSE BLOCK ***** */ 
+
+dojo.provide("bespin.page.dashboard.init");  
+
+// = Dashboard =
+//
+// This file is the dashboard code that is loaded via script src
+// from /dashboard.html.
+
+(function() {
+    var heightDiff;
+    var projects;
+    var scene;
+    var tree;
+    var infoPanel;
+    var currentProject;
+    var go = bespin.util.navigate; // short cut static method 
+    var bd = bespin.page.dashboard;
+
+    var server;
+    var settings;
+    var editSession;
+    var files;
+    var commandLine;
+    
+    dojo.mixin(bespin.page.dashboard, {
+        tree: null,
+        lastSelectedPath: null,
+        
+        sizeCanvas: function(canvas) {
+            if (!heightDiff) {
+                heightDiff = dojo.byId("header").clientHeight + dojo.byId("subheader").clientHeight + dojo.byId("footer").clientHeight;
+            }
+            var height = window.innerHeight - heightDiff + 11;
+            dojo.attr(canvas, { width: window.innerWidth, height: height });
+        },
+        
+        loggedIn: function(userinfo)  {
+            editSession.setUserinfo(userinfo);
+
+            server.list(null, null, bd.displayProjects); // get projects
+            server.listOpen(bd.displaySessions); // get sessions
+        },
+
+        notLoggedIn: function(xhr) {
+            go.home();
+        },
+
+        prepareFilesForTree: function(files) {
+            if (files.length == 0) return [];
+
+            var fdata = [];
+            for (var i = 0; i < files.length; i++) {
+                var name = files[i].name;
+                if (/\/$/.test(name)) {
+                    name = name.substring(0, name.length - 1);
+                    var contents = bd.fetchFiles;
+                    fdata.push({ name: name, contents: contents });
+                } else {
+                    fdata.push({ name: name });
+                }
+            }
+
+            return fdata;
+        },
+
+        getFilePath: function(treePath) {
+            var filepath = "";
+
+            for (var i = 0; i < treePath.length; i++) {
+                if (treePath[i] && treePath[i].name) {
+                    filepath += treePath[i].name + ((i < treePath.length - 1) ? "/" : "");
+                }
+            }
+            return filepath;
+        },
+        
+        fetchFiles: function(path, tree) {            
+            var filepath = bd.getFilePath(path);
+
+            server.list(filepath, null, function(files) {
+                tree.updateData(path[path.length - 1], bd.prepareFilesForTree(files));
+                tree.render();
+            });
+        },
+
+        displaySessions: function(sessions) {
+            infoPanel.removeAll();
+
+            for (var project in sessions) {
+                for (var file in sessions[project]) {
+                    var lastSlash = file.lastIndexOf("/");
+                    var path = (lastSlash == -1) ? "" : file.substring(0, lastSlash);
+                    var name = (lastSlash == -1) ? file : file.substring(lastSlash + 1);
+
+                    var panel = new bespin.page.dashboard.components.BespinSessionPanel({ filename: name, project: project, path: path });
+                    infoPanel.add(panel);
+                    panel.bus.bind("dblclick", panel, function(e) {
+                        var newTab = e.shiftKey;
+                        go.editor(e.thComponent.session.project, e.thComponent.session.path + (e.thComponent.session.path != '' ? '/' : '' ) + e.thComponent.session.filename, newTab);
+                    });
+                }
+            }
+            infoPanel.render();
+        },
+
+        restorePath: function(newPath) {            
+            bd.lastSelectedPath = bd.lastSelectedPath || '';
+            newPath = newPath || '';
+            var oldPath = bd.lastSelectedPath;
+            bd.lastSelectedPath = newPath;
+                        
+            if (newPath == oldPath && newPath != '') return;     // the path has not changed
+
+            newPath = newPath.split('/');
+            oldPath = oldPath.split('/');
+            currentProject = newPath[0];
+
+            tree.lists[0].selectItemByText(newPath[0]);    // this also perform a rendering of the project.list
+            scene.renderAllowed = false;
+
+            var sameLevel = 1;  // the value is 1 and not 0, as the first list (the project list) is not affected!
+            while (sameLevel < Math.min(newPath.length, oldPath.length) && newPath[sameLevel] == oldPath[sameLevel] && newPath[sameLevel] != '') {
+                sameLevel ++;
+            }
+                                                                                                  
+            var fakePath = new Array(newPath.length);
+            for (var x = 1; x < newPath.length; x++) {
+                var fakeItem = new Object();
+                fakeItem.name = newPath[x];
+                if (x != newPath.length - 1) {
+                    fakeItem.contents = 'fake';   
+                }
+                if (x > bd.tree.lists.length - 1) {
+                   bd.tree.showChildren(null, new Array(fakeItem)); 
+                }  
+                if (newPath[x] != '') {
+                    bd.tree.lists[x].selectItemByText(newPath[x]);   
+                }
+                fakePath[x] = fakeItem;
+            }
+            
+            if (newPath.length <= bd.tree.lists.length) {
+                bd.tree.removeListsFrom(newPath.length);
+            }
+                                            
+            var contentsPath = new Array(newPath.length);
+            var countSetupPaths = sameLevel;
+
+            // this function should stay here, as this funciton is accessing "pathContents" and "countSetupPaths"
+            var displayFetchedFiles = function(files) {
+                // "this" is the callbackData object!
+                var contents =  bd.prepareFilesForTree(files);
+                if (this.index != 0) {
+                    contentsPath[this.index] = contents;
+                }
+                
+                bd.tree.replaceList(this.index, contents);
+                bd.tree.lists[this.index].selectItemByText(fakePath[this.index].name);
+                countSetupPaths ++;
+                
+                if (countSetupPaths == newPath.length) {
+                    for (var x = 0; x < newPath.length - 1; x++) {
+                        // when the path is not restored from the root, then there are contents without contents!
+                        if (contentsPath[x + 1]) {
+                            bd.tree.lists[x].selected.contents = contentsPath[x + 1];                            
+                        }
+                    }
+                }
+            }
+            
+            // get the data for the lists
+            for (var x = sameLevel; x < newPath.length; x++) {                                                
+                var selected = bd.tree.lists[x - 1].selected;
+                if (selected && selected.contents && dojo.isArray(selected.contents)) {
+                    // restore filelist from local memory (the filelists was ones fetched)
+                    if (x > bd.tree.lists.length - 1) {
+                        bd.tree.showChildren(null, selected.contents)
+                    } else {
+                        bd.tree.replaceList(x, selected.contents);
+                    }
+                    bd.tree.lists[x].selectItemByText(fakePath[x].name);                        
+                    countSetupPaths ++;
+                } else {
+                    // load filelist form server                                                            
+                    var filepath = currentProject + "/" + bd.getFilePath(fakePath.slice(1, x));
+                    server.list(filepath, null, dojo.hitch({index: x}, displayFetchedFiles));                    
+                }
+            }
+            
+            // deselect lists if needed
+            for (var x = newPath.length; x < tree.lists.length; x++) {
+                delete tree.lists[x].selected;
+            }
+            
+            scene.renderAllowed = true;
+            scene.render();
+        },
+
+        displayProjects: function(projectItems) {
+            for (var i = 0; i < projectItems.length; i++) {
+                projectItems[i] = { name: projectItems[i].name.substring(0, projectItems[i].name.length - 1) , contents: bd.fetchFiles};
+            }
+            tree.replaceList(0, projectItems);
+                                    
+            // Restore the last selected file
+            var path =  (new bespin.client.settings.URL()).get('path');
+            if (!bd.lastSelectedPath) {
+                bd.restorePath(path);
+            } else {
+                scene.render();                
+            }
+        },
+
+        refreshProjects: function() {
+            server.list(null, null, bd.displayProjects);
+        }
+    }); 
+    
+    dojo.connect(window, "resize", function() {
+        bd.sizeCanvas(dojo.byId("canvas"));
+    });
+    
+    dojo.addOnLoad(function() {
+        bd.sizeCanvas(dojo.byId("canvas"));
+
+        dojo.forEach(['subheader', 'header'], function(i) { dojo.setSelectable(i, false); });
+
+        bespin.displayVersion(); // display the version on the page
+
+        scene = new th.Scene(dojo.byId("canvas"));  
+
+        tree = new th.components.HorizontalTree({ style: {
+            backgroundColor: "rgb(76, 74, 65)",
+            backgroundColorOdd: "rgb(82, 80, 71)",
+            font: "9pt Tahoma",
+            color: "white",
+            scrollTopImage: dojo.byId("vscroll_track_top"),
+            scrollMiddleImage: dojo.byId("vscroll_track_middle"),
+            scrollBottomImage: dojo.byId("vscroll_track_bottom"),
+            scrollHandleTopImage: dojo.byId("vscroll_top"),
+            scrollHandleMiddleImage: dojo.byId("vscroll_middle"),
+            scrollHandleBottomImage: dojo.byId("vscroll_bottom"),
+            scrollUpArrow: dojo.byId("vscroll_up_arrow"),
+            scrollDownArrow: dojo.byId("vscroll_down_arrow")
+        }});
+
+        bd.tree = tree;
+        
+        var renderer = new th.components.Label({ style: { border: new th.borders.EmptyBorder({ size: 3 }) } });
+        renderer.old_paint = renderer.paint;
+        renderer.paint = function(ctx) {
+            var d = this.d();
+
+            if (this.selected) {
+                ctx.fillStyle = "rgb(177, 112, 20)";
+                ctx.fillRect(0, 0, d.b.w, 1);
+
+                var gradient = ctx.createLinearGradient(0, 0, 0, d.b.h);
+                gradient.addColorStop(0, "rgb(172, 102, 1)");
+                gradient.addColorStop(1, "rgb(219, 129, 1)");
+                ctx.fillStyle = gradient;
+                ctx.fillRect(0, 1, d.b.w, d.b.h - 2);
+
+                ctx.fillStyle = "rgb(160, 95, 1)";
+                ctx.fillRect(0, d.b.h - 1, d.b.w, 1);
+            }
+
+            if (this.item.contents) {
+                renderer.styleContext(ctx);
+                var metrics = ctx.measureText(">");
+                ctx.fillText(">", d.b.w - metrics.width - 5, d.b.h / 2 + (metrics.ascent / 2) - 1);
+            }
+
+            this.old_paint(ctx);
+        };
+        tree.renderer = renderer;
+        
+        var projectLabel = new th.components.Label({ text: "Projects", style: { color: "white", font: "8pt Tahoma" } });
+        projectLabel.oldPaint = projectLabel.paint;
+        projectLabel.paint = function(ctx) {
+            var d = this.d();
+
+            ctx.fillStyle = "rgb(51, 50, 46)";
+            ctx.fillRect(0, 0, d.b.w, 1);
+
+            ctx.fillStyle = "black";
+            ctx.fillRect(0, d.b.h - 1, d.b.w, 1);
+
+            var gradient = ctx.createLinearGradient(0, 1, 0, d.b.h - 2);
+            gradient.addColorStop(0, "rgb(39, 38, 33)");
+            gradient.addColorStop(1, "rgb(22, 22, 19)");
+            ctx.fillStyle = gradient;
+            ctx.fillRect(0, 1, d.b.w, d.b.h - 2);
+
+            this.oldPaint(ctx);
+        };
+        
+        // add the the former project tree
+        bd.tree.showChildren(null, [{name: '<Projects>'}]);
+        tree.lists[0].label = projectLabel; 
+        tree.lists[0].label.height = 16;
+        tree.lists[0].allowDeselection = false;
+        tree.lists[0].style = { backgroundColor: "rgb(61, 59, 52)", color: "white", font: "8pt Tahoma" };
+
+        var topPanel = new th.components.Panel();
+        topPanel.add([ tree ]);
+        topPanel.layout = function() {
+            var d = this.d();
+            tree.bounds = { x: d.i.l, y: d.i.t, width: d.b.w - d.i.w, height: d.b.h - d.i.h };
+        };
+
+        infoPanel = new th.components.ExpandingInfoPanel({ style: { backgroundColor: "rgb(61, 59, 52)" } });
+
+        var splitPanel = new th.components.SplitPanel({ id: "splitPanel", attributes: {
+            orientation: th.VERTICAL,
+            regions: [ { size: "75%", contents: topPanel }, { size: "25%", contents: infoPanel } ]
+        } });
+
+        splitPanel.attributes.regions[0].label = new th.components.Label({
+                text: "Open Sessions",
+                style: {
+                    color: "white",
+                    font: "9pt Tahoma"
+                },
+                border: new th.borders.EmptyBorder({ size: 4 })
+        });
+
+        scene.root.add(splitPanel);
+
+        scene.render();
+
+        scene.bus.bind("dblclick", tree, function(e) {
+            var newTab = e.shiftKey;
+            var path = tree.getSelectedPath();
+            if (path.length == 0 || path[path.length - 1].contents) return; // don't allow directories either
+            go.editor(currentProject, bd.getFilePath(path.slice(1, path.length)), newTab);
+        });
+
+        scene.bus.bind("itemSelected", tree, function(e) {
+            var pathSelected = tree.getSelectedPath(true);
+            bespin.page.dashboard.lastSelectedPath = pathSelected;
+            location.hash = '#path=' + pathSelected;
+        })
+
+        scene.bus.bind("itemselected", tree.lists[0], function(e) {
+            currentProject = e.item.name;
+            bespin.publish("bespin:project:set", { project: currentProject, suppressPopup: true, fromDashboardItemSelected: true });
+        });
+
+        // setup the command line
+        server = bespin.register('server', new bespin.client.Server());
+        settings = bespin.register('settings', new bespin.client.settings.Core());
+        editSession = bespin.register('editSession', new bespin.client.session.EditSession());
+        files = bespin.register('files', new bespin.client.FileSystem());
+        commandLine = bespin.register('commandLine', new bespin.cmd.commandline.Interface('command', bespin.cmd.dashboardcommands.Commands));
+
+        // Handle jumping to the command line
+        dojo.connect(document, "onkeypress", function(e) {
+            var handled = commandLine.handleCommandLineFocus(e);
+            if (handled) return false;
+        });
+
+        // get logged in name; if not logged in, display an error of some kind
+        server.currentuser(bd.loggedIn, bd.notLoggedIn);   
+        
+        // provide history for the dashboard
+        bespin.subscribe("bespin:url:changed", function(e) {
+            var pathSelected =  (new bespin.client.settings.URL()).get('path');
+            bespin.page.dashboard.restorePath(pathSelected);
+        });
+    });
+})();
\ No newline at end of file

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/dashboard/init.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/editor/dependencies.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/editor/dependencies.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/editor/dependencies.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/editor/dependencies.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,81 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The Original Code is Bespin.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bespin Team (bespin@mozilla.com)
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+dojo.provide("bespin.page.editor.dependencies");	
+
+dojo.require("dojo.cookie");
+
+dojo.require("bespin.bespin");
+dojo.require("bespin.events");                                                                
+
+dojo.require("bespin.util.canvas");
+dojo.require("bespin.util.keys");
+dojo.require("bespin.util.navigate");
+dojo.require("bespin.util.path");
+dojo.require("bespin.util.tokenobject");
+dojo.require("bespin.util.util");
+dojo.require("bespin.util.mousewheelevent");
+dojo.require("bespin.util.urlbar");
+
+dojo.require("bespin.client.filesystem");
+dojo.require("bespin.client.settings");
+dojo.require("bespin.client.status");
+dojo.require("bespin.client.server");
+dojo.require("bespin.client.session");
+
+dojo.require("th.helpers"); // -- Thunderhead... hooooo
+dojo.require("th.css");
+dojo.require("th.th");
+dojo.require("th.models");
+dojo.require("th.borders");
+dojo.require("th.components");
+
+dojo.require("bespin.editor.actions");
+dojo.require("bespin.editor.clipboard");
+dojo.require("bespin.editor.cursor");
+dojo.require("bespin.editor.editor");
+dojo.require("bespin.editor.events");
+dojo.require("bespin.editor.model");
+dojo.require("bespin.editor.toolbar");
+dojo.require("bespin.editor.themes");
+dojo.require("bespin.editor.undo");
+dojo.require("bespin.editor.filelist");
+dojo.require("bespin.editor.quickopen");
+
+dojo.require("bespin.syntax.syntax");
+dojo.require("bespin.syntax.javascript");
+dojo.require("bespin.syntax.css");
+dojo.require("bespin.syntax.html");
+dojo.require("bespin.syntax.php");
+
+dojo.require("bespin.cmd.commandline");
+dojo.require("bespin.cmd.commands");
+dojo.require("bespin.cmd.editorcommands");
+
+dojo.require("bespin.mobwrite.core");
+dojo.require("bespin.mobwrite.diff");
+dojo.require("bespin.mobwrite.form");
+dojo.require("bespin.mobwrite.integrate");
+
+dojo.require("bespin.page.editor.init");
\ No newline at end of file

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/editor/dependencies.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/editor/init.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/editor/init.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/editor/init.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/editor/init.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,191 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The Original Code is Bespin.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bespin Team (bespin@mozilla.com)
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+dojo.provide("bespin.page.editor.init");
+
+// = Bootstrap =
+//
+// This file is the editor bootstrap code that is loaded via script src
+// from /editor.html.
+//
+// It handles setting up the objects that are to be used on the editor
+// and deals with layout changes.
+
+// ** {{{ Globals }}}
+//
+// One day we will get rid of all of these bar the core bespin object.
+
+// pieces in the scene
+(function() {
+    var projectLabel;
+    var fileLabel;
+    var scene;
+
+    dojo.mixin(bespin.page.editor, {
+        // ** {{{ whenLoggedIn(userinfo) }}} **
+        //
+        // * {{{userinfo}}} is an object containing user specific info (project etc)
+        //
+        // Save the users magic project into the session
+        whenLoggedIn: function(userinfo) {
+            bespin.get('editSession').setUserinfo(userinfo);
+
+            bespin.register('settings', new bespin.client.settings.Core());
+            bespin.register('commandLine', new bespin.cmd.commandline.Interface('command', bespin.cmd.editorcommands.Commands));
+        },
+
+        // ** {{{ whenNotLoggedIn() }}} **
+        //
+        // Send the user back to the front page as they aren't logged in.
+        // The server should stop this from happening, but JUST in case.
+        whenNotLoggedIn: function() {
+            bespin.util.navigate.home(); // go back
+        },
+
+        // ** {{{ recalcLayout() }}} **
+        //
+        // When a change to the UI is needed due to opening or closing a feature
+        // (e.g. file view, session view) move the items around
+        recalcLayout: function() {
+            var subheader = dojo.byId("subheader");
+            var footer = dojo.byId("footer");
+            var editor = dojo.byId("editor");
+            var files = dojo.byId("files");
+            var collab = dojo.byId("collab");
+            var target = dojo.byId("target_browsers");
+
+            var move = [ subheader, footer, editor ];
+
+            if (bespin.get('toolbar').showFiles) {
+                files.style.display = "block";
+                dojo.forEach(move, function(item) { item.style.left = "201px"; });
+            } else {
+                files.style.display = "none";
+                dojo.forEach(move, function(item) { item.style.left = "0"; });
+            }
+
+            move.pop();   // editor shouldn't have its right-hand side set
+
+            if (bespin.get('toolbar').showCollab) {
+                collab.style.display = "block";
+                dojo.forEach(move, function(item) { item.style.right = "201px"; });
+            } else {
+                collab.style.display = "none";
+                dojo.forEach(move, function(item) { item.style.right = "0"; });
+            }
+
+            if (bespin.get('toolbar').showTarget) {
+                target.style.display = "block";
+            } else {
+                target.style.display = "none";
+            }
+
+            this.doResize();
+        },
+
+        // ** {{{ doResize() }}} **
+        //
+        // When a user resizes the window, deal with resizing the canvas and repaint
+        doResize: function() {
+            var d = dojo.coords('status');
+            dojo.attr('projectLabel', { width: d.w, height: d.h });
+
+            bespin.get('editor').paint();
+        }
+    })
+
+    // ** {{{ window.load time }}} **
+    //
+    // Loads and configures the objects that the editor needs
+    dojo.addOnLoad(function() {
+        bespin.register('quickopen', new bespin.editor.quickopen.API());
+        var editor = bespin.register('editor', new bespin.editor.API('editor'));
+        var editSession = bespin.register('editSession', new bespin.client.session.EditSession(editor));
+        var server = bespin.register('server', new bespin.client.Server());
+        var files = bespin.register('files', new bespin.client.FileSystem());
+
+        bespin.register('toolbar', new bespin.editor.Toolbar(editor, { setupDefault: true }));
+
+        // Force a login just in case the user session isn't around
+        server.currentuser(bespin.page.editor.whenLoggedIn, bespin.page.editor.whenNotLoggedIn);
+
+        // Set the version info
+        bespin.displayVersion();
+
+        // Get going when settings are loaded
+        bespin.subscribe("bespin:settings:loaded", function(event) {
+            bespin.get('settings').loadSession();  // load the last file or what is passed in
+            bespin.page.editor.doResize();
+        });
+
+        dojo.connect(window, 'resize', bespin.page.editor, "doResize");
+
+        scene = new th.Scene(dojo.byId("projectLabel"));
+
+        var panel = new th.components.Panel();
+        scene.root.add(panel);
+
+        projectLabel = new th.components.Label({ style: {
+            color: "white",
+            font: "12pt Calibri, Arial, sans-serif"
+        }});
+        var symbolThingie = new th.components.Label({ text: ":", style: {
+            color: "gray",
+            font: "12pt Calibri, Arial, sans-serif"
+        }});
+        fileLabel = new th.components.Label({ style: {
+            color: "white",
+            font: "12pt Calibri, Arial, sans-serif"
+        }});
+
+        panel.add([ projectLabel, symbolThingie, fileLabel ]);
+        panel.layout = function() {
+            var d = this.d();
+
+            var x = 0;
+            for (var i = 0; i < 2; i++) {
+                var width = this.children[i].getPreferredWidth(d.b.h);
+                this.children[i].bounds = { x: x, y: 0, width: width, height: d.b.h };
+                x += width;
+            }
+
+            this.children[2].bounds = { x: x, y: 0, width: d.b.w - d.i.w - x, height: d.b.h };
+        };
+
+        scene.render();
+    });
+
+    // ** {{{ Event: bespin:editor:openfile:opensuccess }}} **
+    // 
+    // When a file is opened successfully change the project and file status area.
+    // Then change the window title, and change the URL hash area
+    bespin.subscribe("bespin:editor:openfile:opensuccess", function(event) {
+        var project = event.project || bespin.get('editSession').project; 
+        var filename = event.file.name;
+
+        projectLabel.attributes.text = bespin.get('editSession').project;
+        fileLabel.attributes.text = filename;
+        scene.render();
+    });
+})();

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/editor/init.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/index/dependencies.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/index/dependencies.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/index/dependencies.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/index/dependencies.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,36 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The Original Code is Bespin.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bespin Team (bespin@mozilla.com)
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+dojo.provide("bespin.page.index.dependencies");
+
+dojo.require("dojo.cookie");
+dojo.require("dijit._base.place");
+
+dojo.require("bespin.bespin");
+dojo.require("bespin.util.navigate");
+dojo.require("bespin.client.server");
+dojo.require("bespin.user.utils");
+dojo.require("bespin.user.register");
+
+dojo.require("bespin.page.index.init");
\ No newline at end of file

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/index/dependencies.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/index/init.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/index/init.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/index/init.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/index/init.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,45 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The Original Code is Bespin.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bespin Team (bespin@mozilla.com)
+ *
+ * ***** END LICENSE BLOCK ***** */ 
+
+dojo.provide("bespin.page.index.init");  
+
+// = Index / Home page =
+//
+// This file is the code to load up the index.html / home page
+
+(function() {
+    var server = bespin.register('server', new bespin.client.Server());
+    var utils = bespin.user.utils;
+    var webpieces = bespin.util.webpieces;
+
+    dojo.addOnLoad(function() {
+        bespin.displayVersion();
+        server.currentuser(utils.whenAlreadyLoggedIn, utils.whenNotAlreadyLoggedIn);
+		webpieces.fillScreenOverlay();
+    });
+
+    dojo.connect(window, "resize", function() {
+        webpieces.fillScreenOverlay();
+    });
+})();

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/bespin/page/index/init.js
------------------------------------------------------------------------------
    svn:eol-style = native

Added: camel/trunk/components/camel-web/src/main/webapp/js/bespin/syntax/arduino.js
URL: http://svn.apache.org/viewvc/camel/trunk/components/camel-web/src/main/webapp/js/bespin/syntax/arduino.js?rev=755931&view=auto
==============================================================================
--- camel/trunk/components/camel-web/src/main/webapp/js/bespin/syntax/arduino.js (added)
+++ camel/trunk/components/camel-web/src/main/webapp/js/bespin/syntax/arduino.js Thu Mar 19 11:24:18 2009
@@ -0,0 +1,197 @@
+/* ***** BEGIN LICENSE BLOCK *****
+ * Version: MPL 1.1
+ *
+ * The contents of this file are subject to the Mozilla Public License
+ * Version 1.1 (the "License"); you may not use this file except in
+ * compliance with the License. You may obtain a copy of the License at
+ * http://www.mozilla.org/MPL/
+ *
+ * Software distributed under the License is distributed on an "AS IS"
+ * basis, WITHOUT WARRANTY OF ANY KIND, either express or implied.
+ * See the License for the specific language governing rights and
+ * limitations under the License.
+ *
+ * The Original Code is Bespin.
+ *
+ * The Initial Developer of the Original Code is Mozilla.
+ * Portions created by the Initial Developer are Copyright (C) 2009
+ * the Initial Developer. All Rights Reserved.
+ *
+ * Contributor(s):
+ *   Bespin Team (bespin@mozilla.com)
+ *   Olle Jonsson (olle.jonsson@gmail.com)
+ *   Peter Neubauer (peter@neubauer.se)
+ *
+ * ***** END LICENSE BLOCK ***** */
+
+// = Arduino Syntax Highlighting Implementation =
+//
+// Module for syntax highlighting Arduino PDE files.
+
+dojo.provide("bespin.syntax.arduino");
+
+// ** {{{ bespin.syntax.ArduinoSyntaxEngine }}} **
+//
+// Tracks syntax highlighting data on a per-line basis. This is a quick-and-dirty implementation that
+// supports five basic highlights: keywords, punctuation, strings, comments, and "everything else", all
+// lumped into one last bucket.
+
+bespin.syntax.ArduinoConstants = {
+    C_STYLE_COMMENT: "c-comment",
+    LINE_COMMENT: "comment",
+    STRING: "string",
+    KEYWORD: "keyword",
+    PUNCTUATION: "punctuation",
+    OTHER: "plain"
+};
+
+dojo.declare("bespin.syntax.ArduinoSyntaxEngine", null, {
+    keywords: 'HIGH LOW INPUT OUTPUT SERIAL DISPLAY  DEC BIN HEX OCT BYTE PI HALF_PI  TWO_PI LSBFIRST MSBFIRST CHANGE FALLING  RISING DEFAULT  EXTERNAL INTERAL ' +
+    'boolean  byte case char class default  do double else false float for if int long new null private  protected public return short signed static switch this throw try true unsigned void while word ' +
+    'abs acos asin atan atan2 ceil constrain cos degrees exp floor log map max min radians  random randomSeed round sin sq sqrt tan ' +
+    'bitRead bitWrite bitSet bitClear bit highByte lowByte ' +
+    'analogReference  analogRead analogWrite attachInterrupt  detachInterrupt  delay delayMicroseconds digitalWrite digitalRead interrupts millis micros noInterrupts pinMode  pulseIn  shiftOut ' +
+    'Serial begin read print println  available flush ' +
+    'setup loop'.split(" "),
+
+    punctuation: '{ } > < / + - % * . , ; ( ) ? : = " \''.split(" "),
+
+    highlight: function(line, meta) {           
+        if (!meta) meta = {};
+
+        var K = bespin.syntax.ArduinoConstants;    // aliasing the constants for shorter reference ;-)
+
+        var regions = {};                               // contains the individual style types as keys, with array of start/stop positions as value
+
+        // current state, maintained as we parse through each character in the line; values at any time should be consistent
+        var currentStyle = (meta.inMultilineComment) ? K.C_STYLE_COMMENT : undefined;
+        var currentRegion = {}; // should always have a start property for a non-blank buffer
+        var buffer = "";
+
+        // these properties are related to the parser state above but are special cases
+        var stringChar = "";    // the character used to start the current string
+        var multiline = meta.inMultilineComment;
+
+        for (var i = 0; i < line.length; i++) {
+            var c = line.charAt(i);
+
+            // check if we're in a comment and whether this character ends the comment
+            if (currentStyle == K.C_STYLE_COMMENT) {
+                if (c == "/" && /\*$/.test(buffer)) { // has the c-style comment just ended?
+                    currentRegion.stop = i + 1;
+                    this.addRegion(regions, currentStyle, currentRegion);
+                    currentRegion = {};
+                    currentStyle = undefined;
+                    multiline = false;
+                    buffer = "";
+                } else {
+                    if (buffer == "") currentRegion = { start: i };
+                    buffer += c;
+                }
+
+                continue;
+            }
+
+            if (this.isWhiteSpaceOrPunctuation(c)) {
+                // check if we're in a string
+                if (currentStyle == K.STRING) {
+                    // if this is not an unescaped end quote (either a single quote or double quote to match how the string started) then keep going
+                    if ( ! (c == stringChar && !/\\$/.test(buffer))) { 
+                        if (buffer == "") currentRegion = { start: i };
+                        buffer += c;
+                        continue;
+                    }
+                }
+
+                // if the buffer is full, add it to the regions
+                if (buffer != "") {
+                    currentRegion.stop = i;
+
+                    if (currentStyle != K.STRING) {   // if this is a string, we're all set to add it; if not, figure out if its a keyword
+                        if (this.keywords.indexOf(buffer) != -1) {
+                            // the buffer contains a keyword
+                            currentStyle = K.KEYWORD;
+                        } else {
+                            currentStyle = K.OTHER;
+                        }
+                    }
+                    this.addRegion(regions, currentStyle, currentRegion);
+                    currentRegion = {};
+                    stringChar = "";
+                    buffer = "";
+                    // i don't clear the current style here so I can check if it was a string below
+                }
+
+                if (this.isPunctuation(c)) {
+                    if (c == "*" && i > 0 && (line.charAt(i - 1) == "/")) {
+                        // remove the previous region in the punctuation bucket, which is a forward slash
+                        regions[K.PUNCTUATION].pop();
+
+                        // we are in a c-style comment
+                        multiline = true;
+                        currentStyle = K.C_STYLE_COMMENT;
+                        currentRegion = { start: i - 1 };
+                        buffer = "/*";
+                        continue;
+                    }
+
+                    // check for a line comment; this ends the parsing for the rest of the line
+                    if (c == '/' && i > 0 && (line.charAt(i - 1) == '/')) {
+                        currentRegion = { start: i - 1, stop: line.length };
+                        currentStyle = K.LINE_COMMENT;
+                        this.addRegion(regions, currentStyle, currentRegion);
+                        buffer = "";
+                        currentStyle = undefined;
+                        currentRegion = {};
+                        break;      // once we get a line comment, we're done!
+                    }
+
+                    // add an ad-hoc region for just this one punctuation character
+                    this.addRegion(regions, K.PUNCTUATION, { start: i, stop: i + 1 });
+                }
+
+                // find out if the current quote is the end or the beginning of the string
+                if ((c == "'" || c == '"') && (currentStyle != K.STRING)) {
+                    currentStyle = K.STRING;
+                    stringChar = c;
+                } else {
+                    currentStyle = undefined;
+                }
+
+                continue;
+            }
+
+            if (buffer == "") currentRegion = { start: i };
+            buffer += c;
+        }
+
+        // check for a trailing character inside of a string or a comment
+        if (buffer != "") {
+            if (!currentStyle) currentStyle = K.OTHER;
+            currentRegion.stop = line.length;
+            this.addRegion(regions, currentStyle, currentRegion);
+        }
+
+        return { regions: regions, meta: { inMultilineComment: multiline } };
+    },
+
+    addRegion: function(regions, type, data) {
+        if (!regions[type]) regions[type] = [];
+        regions[type].push(data);
+    },
+
+    isWhiteSpaceOrPunctuation: function(ch) {
+        return this.isPunctuation(ch) || this.isWhiteSpace(ch);
+    },
+
+    isPunctuation: function(ch) {
+        return this.punctuation.indexOf(ch) != -1;
+    },
+
+    isWhiteSpace: function(ch) {
+        return ch == " ";
+    }
+});
+
+// Register
+bespin.syntax.EngineResolver.register(new bespin.syntax.ArduinoSyntaxEngine(), ['pde']);

Propchange: camel/trunk/components/camel-web/src/main/webapp/js/bespin/syntax/arduino.js
------------------------------------------------------------------------------
    svn:eol-style = native