From d5c656ba5788a71bb86cfffe593fdbdbf596c4ae Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 30 Oct 2012 15:22:07 +0800
Subject: [PATCH 01/36] convert datatables to ls

---
 package.json            |    7 +-
 src/js/datatables.ls    | 1497 ++++++++++++++++++++++++++++++
 static/js/datatables.js | 1927 ---------------------------------------
 3 files changed, 1503 insertions(+), 1928 deletions(-)
 create mode 100644 src/js/datatables.ls
 delete mode 100644 static/js/datatables.js

diff --git a/package.json b/package.json
index 931b323..1d613d4 100644
--- a/package.json
+++ b/package.json
@@ -10,11 +10,16 @@
     "type": "git",
     "url": "git://github.com/gedion/ep_tables.git"
   },
+  "scripts": {
+      "prepublish": "./node_modules/.bin/livescript -bc -o static/js src/js"
+  },
   "engines": {
     "node": "*"
   },
   "dependencies": {},
-  "devDependencies": {},
+  "devDependencies": {
+    "LiveScript": "1.1.x"
+  },
   "optionalDependencies": {},
   "_id": "ep_tables@0.1.1",
   "_engineSupported": true,
diff --git a/src/js/datatables.ls b/src/js/datatables.ls
new file mode 100644
index 0000000..b878f56
--- /dev/null
+++ b/src/js/datatables.ls
@@ -0,0 +1,1497 @@
+_ = require 'ep_etherpad-lite/static/js/underscore'
+
+if not (typeof require is 'undefined')
+  Ace2Common = require 'ep_etherpad-lite/static/js/ace2_common' if typeof Ace2Common is 'undefined'
+  if typeof Changeset is 'undefined' then Changeset = require 'ep_etherpad-lite/static/js/Changeset'
+
+exports.aceInitInnerdocbodyHead = (hook_name, args, cb) ->
+  args.iframeHTML.push '<link rel="stylesheet" type="text/css" href="/static/plugins/ep_tables/static/css/dataTables.css"/>'
+
+exports.postAceInit = (hook, context) ->
+  $.createTableMenu = (init) ->
+    showTblPropPanel = ->
+      if not $.tblPropDialog
+        $.tblPropDialog = new YAHOO.widget.Dialog 'yui-tbl-prop-panel', {
+          width: '600px'
+          height: '450px'
+          close: true
+          visible: false
+          zindex: 1001
+          constraintoviewport: true
+        }
+        $.tblPropDialog.setBody $.getTblPropertiesHTML!
+        $.tblPropDialog.render!
+        $.alignMenu $.tblPropDialog, @id
+        initTableProperties!
+      $.tblPropDialog.show!
+    createColorPicker = ->
+      createOColorPicker = ->
+        $.oColorPicker = new YAHOO.widget.ColorPicker 'color-picker-menu', {
+          showhsvcontrols: false
+          showrgbcontrols: false
+          showwebsafe: false
+          showhexsummary: false
+          showhexcontrols: true
+          images: {
+            PICKER_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/picker_thumb.png'
+            HUE_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/hue_thumb.png'
+          }
+        }
+        $.oColorPicker.on 'rgbChange', colorPickerButtonClick
+        $.colorPickerAligned = true
+      handleColorPickerSubmit = -> colorPickerButtonClick $.oColorPicker.get 'hex'
+      handleDialogCancel = -> @cancel!
+      $.oColorPickerDialog = new YAHOO.widget.Dialog 'yui-picker-panel', {
+        width: '500px'
+        close: true
+        visible: false
+        zindex: 1002
+        constraintoviewport: true
+        buttons: [{
+          text: 'Exit'
+          handler: @handleDialogCancel
+        }]
+      }
+      $.oColorPickerDialog.renderEvent.subscribe (-> createOColorPicker! if not $.oColorPicker)
+      $.oColorPickerDialog.render!
+      $.oColorPickerDialog.show!
+    colorPickerButtonClick = (sColor) ->
+      if typeof sColor is 'string' and sColor? and (sColor.indexOf '#') is -1
+        sColor = '#' + sColor
+      else
+        if typeof sColor is 'object' then sColor = if not (@get 'hex')? then @get 'value' else '#' + @get 'hex'
+      selParams = {
+        borderWidth: null
+        tblPropertyChange: true
+      }
+      switch $.tblfocusedProperty
+      case 'tbl_border_color'
+        selParams.tblBorderColor = true
+        selParams.attrName = 'borderColor'
+        $.borderColorPickerButton.set 'value', sColor
+        ($ '#current-color').css 'backgroundColor', sColor
+        ($ '#current-color').innerHTML = 'Current color is ' + sColor
+      case 'tbl_cell_bg_color'
+        selParams.tblCellBgColor = true
+        selParams.attrName = 'bgColor'
+        $.cellBgColorPickerButton.set 'value', sColor
+        ($ '#current-cell-bg-color').css 'backgroundColor', sColor
+        ($ '#current-cell-bg-color').innerHTML = 'Current color is ' + sColor
+      case 'tbl_even_row_bg_color'
+        selParams.tblEvenRowBgColor = true
+        selParams.attrName = 'evenBgColor'
+        $.evenRowBgColorPickerButton.set 'value', sColor
+        ($ '#even-row-bg-color').css 'backgroundColor', sColor
+        ($ '#even-row-bg-color').innerHTML = 'Current color is ' + sColor
+      case 'tbl_odd_row_bg_color'
+        selParams.tblOddRowBgColor = true
+        selParams.attrName = 'oddBgColor'
+        $.oddRowBgColorPickerButton.set 'value', sColor
+        ($ '#odd-row-bg-color').css 'backgroundColor', sColor
+        ($ '#odd-row-bg-color').innerHTML = 'Current color is ' + sColor
+      case 'tbl_single_row_bg_color'
+        selParams.tblSingleRowBgColor = true
+        selParams.attrName = 'bgColor'
+        $.singleRowBgColorPickerButton.set 'value', sColor
+        ($ '#single-row-bg-color').css 'backgroundColor', sColor
+        ($ '#single-row-bg-color').innerHTML = 'Current color is ' + sColor
+      case 'tbl_single_col_bg_color'
+        selParams.tblSingleColBgColor = true
+        selParams.attrName = 'bgColor'
+        $.singleColBgColorPickerButton.set 'value', sColor
+        ($ '#single-col-bg-color').css 'backgroundColor', sColor
+        ($ '#single-col-bg-color').innerHTML = 'Current color is ' + sColor
+      selParams.attrValue = sColor
+      context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
+    top.templatesMenu.hide! if not (typeof top.templatesMenu is 'undefined')
+    if $.tblContextMenu
+      $.alignMenu $.tblContextMenu, 'tbl-menu'
+      $.tblContextMenu.show!
+      return 
+    $.handleTableBorder = (selectValue) ->
+      selParams = {
+        tblBorderWidth: true
+        attrName: 'borderWidth'
+        attrValue: selectValue
+        tblPropertyChange: true
+      }
+      context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
+    $.getTblPropertiesHTML = ->
+      '<span id=\'table_properties\'><span class=\'tbl-prop-menu-header\'></span><br><span id=\'tbl-prop-menu\'class=\'tbl-prop-menu\'>' + '<table class=\'left-tbl-props tbl-inline-block\'>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>Table border</span></td></tr>' + '<tr><td><span class=\'tbl-inline-block\' id=\'tbl_border_color\'> </span><span id=\'tbl_border_width\'class=\'tbl-inline-block tbl_border_width\'></span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Cell background color</span></td></tr><tr><td><span id=\'tbl_cell_bg_color\'></td></tr><tr><td></span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Even/Odd Row background color</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_even_row_bg_color\'>Even   </span><span id=\'tbl_odd_row_bg_color\' class=\'tbl-inline-block\'>Odd</span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Single Row/Col background color</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_single_row_bg_color\'>Single Row   </span><span id=\'tbl_single_col_bg_color\' class=\'tbl-inline-block\'>Single Col</span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Row/Col alignment</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_row_v_align\'>Row align </span><span id=\'tbl_col_v_align\' class=\'tbl-inline-block\'>Col align</span></td></tr>' + '</table>' + '\t<span class=\' tbl-inline-block\'>' + '\t\t<span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + 'Dimensions(Inches) ' + '\t\t</span>  <span id=\'text_input_message\'></span>' + '\t\t<table class=\'tbl-prop-dim\'>' + '\t\t\t<tbody>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Table width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Table height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Column width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_col_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Minimum row height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_row_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label >Cell padding</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_cell_padding\' type=\'text\' size=\'4\' class=\'text-input\'>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t</tbody>' + '\t\t</table>' + '\t\t<br> ' + '\t\t<span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + '\t\t\tFonts ' + '\t\t</span>' + '\t\t<table class=\'tbl-prop-dim\'>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label >Cell font size</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'select-font-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_cell_font_size\' type=\'text\' size=\'4\' class=\'text-input\'>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t</tbody>' + '\t\t</table>' + '\t</span>' + '</span>' + '</span>' + '<span id=\'img_properties\'>' + '<span class=\'tbl-prop-menu-header\'></span><span id=\'img-prop-menu\'class=\'tbl-prop-menu\'>' + '<table class=\'left-tbl-props tbl-inline-block\'>' + '\t\t<caption><span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + '\t\t\tDimensions(Intches) ' + '\t\t</span></caption>' + '\t\t\t<tbody>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Image width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'img_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Image height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'img_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '</table>' + '</span>' + '</span>'
+    if typeof $.tblContextMenu is 'undefined'
+      initTableProperties = ->
+        colVAligns = [
+          'Left'
+          'Center'
+          'Right'
+        ]
+        $.colVAlignsMenu = new YAHOO.widget.ContextMenu 'tbl_col_v_align_menu', {
+          iframe: true
+          zindex: 1003
+          shadow: false
+          position: 'dynamic'
+          keepopen: true
+          clicktohide: true
+        }
+        $.colVAlignsMenu.addItems colVAligns
+        $.colVAlignsMenu.render document.body
+        $.colVAlignsMenu.subscribe 'click', (p_sType, p_aArgs) ->
+          oEvent = p_aArgs.0
+          oMenuItem = p_aArgs.1
+          if oMenuItem
+            align = oMenuItem.cfg.getProperty 'text'
+            selParams = {
+              tblColVAlign: true
+              attrName: 'colVAlign'
+              attrValue: align
+              tblPropertyChange: true
+            }
+            $.colVAlignsMenuButton.set 'value', selParams.attrValue
+            ($ '#current-col-v-alignment').html align
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
+        $.colVAlignsMenuButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em id="current-col-v-alignment">Left</em>'
+          container: 'tbl_col_v_align'
+        }
+        ($ '#tbl_col_v_align').click (->
+          aligned = false
+          $.alignMenu $.colVAlignsMenu, 'tbl_col_v_align' if not aligned
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          if $.oColorPickerDialog then $.oColorPickerDialog.hide!
+          $.colVAlignsMenu.show!
+          vAlignValue = $.colVAlignsMenuButton.get 'value'
+          if vAlignValue
+            selParams = {
+              tblColVAlign: true
+              attrName: 'colVAlign'
+              attrValue: vAlignValue
+              tblPropertyChange: true
+            }
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
+        rowVAligns = [
+          'Top'
+          'Center'
+          'Bottom'
+        ]
+        $.rowVAlignsMenu = new YAHOO.widget.ContextMenu 'tbl_row_v_align_menu', {
+          iframe: true
+          zindex: 1003
+          shadow: false
+          position: 'dynamic'
+          keepopen: true
+          clicktohide: true
+        }
+        $.rowVAlignsMenu.addItems rowVAligns
+        $.rowVAlignsMenu.render document.body
+        $.rowVAlignsMenu.subscribe 'click', (p_sType, p_aArgs) ->
+          oEvent = p_aArgs.0
+          oMenuItem = p_aArgs.1
+          if oMenuItem
+            align = oMenuItem.cfg.getProperty 'text'
+            selParams = {
+              tblRowVAlign: true
+              attrName: 'rowVAlign'
+              attrValue: align
+              tblPropertyChange: true
+            }
+            $.rowVAlignsMenuButton.set 'value', selParams.attrValue
+            ($ '#current-v-alignment').html align
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
+        $.rowVAlignsMenuButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em id="current-v-alignment">Top</em>'
+          container: 'tbl_row_v_align'
+        }
+        ($ '#tbl_row_v_align').click (->
+          aligned = false
+          $.alignMenu $.rowVAlignsMenu, 'tbl_row_v_align' if not aligned
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          if $.oColorPickerDialog then $.oColorPickerDialog.hide!
+          $.rowVAlignsMenu.show!
+          vAlignValue = $.rowVAlignsMenuButton.get 'value'
+          if vAlignValue
+            selParams = {
+              tblRowVAlign: true
+              attrName: 'rowVAlign'
+              attrValue: vAlignValue
+              tblPropertyChange: true
+            }
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
+        borderWidths = [
+          '0px'
+          '1px'
+          '2px'
+          '3px'
+          '4px'
+          '5px'
+          '6px'
+          '7px'
+          '8px'
+        ]
+        $.borderWidthsMenu = new YAHOO.widget.ContextMenu 'tbl_border_width_menu', {
+          iframe: true
+          zindex: 1003
+          shadow: false
+          position: 'dynamic'
+          keepopen: true
+          clicktohide: true
+        }
+        $.borderWidthsMenu.addItems borderWidths
+        $.borderWidthsMenu.render document.body
+        $.borderWidthsMenu.subscribe 'click', (p_sType, p_aArgs) ->
+          oEvent = p_aArgs.0
+          oMenuItem = p_aArgs.1
+          if oMenuItem
+            borderReq = oMenuItem.cfg.getProperty 'text'
+            selParams = {
+              tblBorderWidth: true
+              attrName: 'borderWidth'
+              attrValue: borderReq.substring 0, borderReq.indexOf 'px'
+              tblPropertyChange: true
+            }
+            $.borderWidthPickerButton.set 'value', selParams.attrValue
+            ($ '#current-width').html borderReq
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
+        $.borderWidthPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em id="current-width">1px</em>'
+          container: 'tbl_border_width'
+        }
+        ($ '#tbl_border_width').click (->
+          aligned = false
+          $.alignMenu $.borderWidthsMenu, 'tbl_border_width' if not aligned
+          if $.oColorPickerDialog then $.oColorPickerDialog.hide!
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          $.borderWidthsMenu.show!
+          widthValue = $.borderWidthPickerButton.get 'value'
+          if widthValue
+            selParams = {
+              tblBorderWidth: true
+              attrName: 'borderWidth'
+              attrValue: widthValue
+              tblPropertyChange: true
+            }
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
+        $.tblfocusedProperty = ''
+        ($ '#tbl_properties').click (->
+          $.borderWidthsMenu.hide! if not (typeof $.borderWidthsMenu is 'undefined')
+          if not (typeof $.oColorPickerDialog is 'undefined') then $.oColorPickerDialog.hide!
+          if not (typeof $.rowVAlignsMenu is 'undefined') then $.rowVAlignsMenu.hide!)
+        $.colorPickerAligned = false
+        ($ '#tbl_border_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_border_color'
+          $.tblfocusedProperty = 'tbl_border_color'
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Table Border color'
+          $.oColorPickerDialog.show!
+          hexValue = $.borderColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        $.borderColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em  class=\'color-picker-button\' id="current-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_border_color'
+        }
+        $.cellBgColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em class=\'color-picker-button\' id="current-cell-bg-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_cell_bg_color'
+        }
+        ($ '#tbl_cell_bg_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_cell_bg_color'
+          $.tblfocusedProperty = 'tbl_cell_bg_color'
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Cell Background color'
+          $.oColorPickerDialog.show!
+          hexValue = $.cellBgColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        $.evenRowBgColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em class=\'color-picker-button\' id="even-row-bg-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_even_row_bg_color'
+        }
+        ($ '#tbl_even_row_bg_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_even_row_bg_color'
+          $.tblfocusedProperty = 'tbl_even_row_bg_color'
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Even Row Background color'
+          $.oColorPickerDialog.show!
+          hexValue = $.evenRowBgColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        $.oddRowBgColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em class=\'color-picker-button\' id="odd-row-bg-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_odd_row_bg_color'
+        }
+        ($ '#tbl_odd_row_bg_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_odd_row_bg_color'
+          $.tblfocusedProperty = 'tbl_odd_row_bg_color'
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Odd Row Background color'
+          $.oColorPickerDialog.show!
+          hexValue = $.oddRowBgColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        $.singleRowBgColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em class=\'color-picker-button\' id="single-row-bg-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_single_row_bg_color'
+        }
+        ($ '#tbl_single_row_bg_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_single_row_bg_color'
+          $.tblfocusedProperty = 'tbl_single_row_bg_color'
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Single Row Background color'
+          $.oColorPickerDialog.show!
+          hexValue = $.singleRowBgColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        $.singleColBgColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em class=\'color-picker-button\' id="single-col-bg-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_single_col_bg_color'
+        }
+        ($ '#tbl_single_col_bg_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_single_col_bg_color'
+          $.tblfocusedProperty = 'tbl_single_col_bg_color'
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Single Column Background color'
+          $.oColorPickerDialog.show!
+          hexValue = $.singleColBgColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        ($ '.text-input').change (->
+          selParams = {tblPropertyChange: true}
+          if @id is 'tbl_width'
+            selParams.tblWidth = true
+            selParams.attrName = 'width'
+          else
+            if @id is 'tbl_height'
+              selParams.tblHeight = true
+              selParams.attrName = 'height'
+            else
+              if @id is 'tbl_col_width'
+                selParams.tblColWidth = true
+                selParams.attrName = 'width'
+              else
+                if @id is 'tbl_row_height'
+                  selParams.tblCellHeight = true
+                  selParams.attrName = 'height'
+                else
+                  if @id is 'tbl_cell_padding'
+                    selParams.tblCellPadding = true
+                    selParams.attrName = 'padding'
+                  else
+                    if @id is 'tbl_cell_font_size'
+                      selParams.tblCellFontSize = true
+                      selParams.attrName = 'fontSize'
+                    else
+                      if @id is 'img_width'
+                        selParams.imgWidth = true
+                        selParams.attrName = 'width'
+                      else
+                        if @id is 'img_height'
+                          selParams.imgHeight = true
+                          selParams.attrName = 'height'
+          selParams.attrValue = @value
+          @value = ''
+          ($ '#text_input_message').text 'Ok'
+          ($ '#text_input_message').removeAttr 'style'
+          ($ '#text_input_message').fadeOut 'slow'
+          context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
+      matrixTable = '<table id=\'matrix_table\'class=\'matrix-table\'><caption></caption>    <tr value=1><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=2 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=3 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=4><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=5 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=6><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=7><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=8><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=9><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=10><td height=10 value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr></table>'
+      $.tblContextMenu = new YAHOO.widget.ContextMenu 'tbl_context_menu', {
+        iframe: true
+        zindex: 500
+        shadow: false
+        position: 'dynamic'
+        keepopen: true
+        clicktohide: true
+      }
+      $.tblContextMenu.addItems [
+        [{
+          text: 'Insert Table'
+          submenu: {
+            id: 'tbl_insert'
+            itemData: ['<div id=\'select_matrix\'>0 X 0</div>']
+          }
+        }]
+        [
+          'Insert Row Above'
+          'Insert Row Below'
+          'Insert Column Right'
+          'Insert Column Left'
+        ]
+        [
+          'Delete Row'
+          'Delete Column'
+          'Delete Table'
+        ]
+        [{
+          id: 'tbl_prop_menu_item'
+          text: 'Table Properties'
+          onclick: {fn: showTblPropPanel}
+        }]
+      ]
+      subMenus = $.tblContextMenu.getSubmenus!
+      subMenus.0.setFooter matrixTable
+      $.tblContextMenu.render document.body
+      $.alignMenu = (menu, id, addX, addY, scrollY) ->
+        region = YAHOO.util.Dom.getRegion id
+        if typeof id is 'string' and (id is 'tbl-menu' or id is 'upload_image_cont')
+          menu.cfg.setProperty 'xy', [region.left, region.bottom]
+        else
+          if typeof id is 'string' then menu.cfg.setProperty 'xy', [region.right, region.top] else menu.cfg.setProperty 'xy', [30 + addX, 36 + addY - scrollY]
+      ($ 'table td').hover (->
+        x = 0
+        while x <= ($ this).index!
+          y = 0
+          while y <= ($ this).parent!.index!
+            ((($ this).parent!.parent!.children!.eq y).children!.eq x).addClass 'selected'
+            y++
+          x++), -> ($ 'table td').removeClass 'selected'
+      ($ 'table td').hover (->
+        xVal = @getAttribute 'value'
+        yVal = (($ this).closest 'tr').0.getAttribute 'value'
+        ($ '#select_matrix').html xVal + ' X ' + yVal)
+      ($ 'td', '#matrix_table').click ((e) ->
+        context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions 'addTbl', 'addTblX' + ($ '#select_matrix').text!), 'tblOptions', true
+        false)
+      $.tblContextMenu.subscribe 'click', (p_sType, p_aArgs) ->
+        oEvent = p_aArgs.0
+        oMenuItem = p_aArgs.1
+        if oMenuItem
+          tblReq = oMenuItem.cfg.getProperty 'text'
+          disabled = oMenuItem.cfg.getProperty 'disabled'
+          return  if disabled
+          id = ''
+          switch tblReq
+          case 'Insert Table'
+            id = 'addTbl'
+          case 'Insert Row Above'
+            id = 'addTblRowA'
+          case 'Insert Row Below'
+            id = 'addTblRowB'
+          case 'Insert Column Left'
+            id = 'addTblColL'
+          case 'Insert Column Right'
+            id = 'addTblColR'
+          case 'Delete Table'
+            id = 'delTbl'
+          case 'Delete Image'
+            id = 'delImg'
+          case 'Delete Row'
+            id = 'delTblRow'
+          case 'Delete Column'
+            id = 'delTblCol'
+          context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions id), 'tblOptions', true
+          false
+    if not init
+      $.alignMenu $.tblContextMenu, 'tbl-menu'
+      $.tblContextMenu.show!
+  ($ '#tbl-menu').click $.createTableMenu
+  YAHOO.util.Dom.addClass document.body, 'yui-skin-sam'
+  ($ 'body').append $ '<div id="yui-picker-panel" class="yui-picker-panel">' + '<div class="hd">Please choose a color:</div>' + '<div class="bd">' + '\t<div class="yui-picker" id="color-picker-menu"></div>' + '</div>' + '<div class="ft"></div>' + '</div>'
+  ($ 'body').append $ '<div id="yui-tbl-prop-panel" class="yui-picker-panel">' + '<div class="hd">Table/Image Properties</div>' + '<div class="bd">' + '\t<div class="yui-picker" id="tbl-props"></div>' + '</div>' + '<div class="ft"></div>' + '</div>'
+  $.createTableMenu true
+
+exports.aceInitialized = (hook, context) ->
+  editorInfo = context.editorInfo
+  editorInfo.ace_doDatatableOptions = (_ Datatables.doDatatableOptions).bind context
+
+exports.acePostWriteDomLineHTML = (hook_name, args, cb) ->
+  children = args.node.children
+  i = 0
+  while i < children.length
+    continue if (args.node.children[i].className.indexOf 'list') isnt -1 or (args.node.children[i].className.indexOf 'tag') isnt -1 or (args.node.children[i].className.indexOf 'url') isnt -1
+    lineText = ''
+    if args.node.children[i].innerText then lineText = args.node.children[i].innerText else lineText = args.node.children[i].textContent
+    if lineText and (lineText.indexOf 'data-tables') isnt -1
+      dtAttrs = if typeof exports.Datatables isnt 'undefined' then exports.Datatables.attributes else null
+      dtAttrs = dtAttrs or ''
+      DatatablesRenderer.render {}, args.node.children[i], dtAttrs
+      exports.Datatables.attributes = null
+    i++
+
+exports.eejsBlock_scripts = (hook_name, args, cb) ->
+  args.content = args.content + (require 'ep_etherpad-lite/node/eejs/').require 'ep_tables/templates/datatablesScripts.ejs'
+
+exports.eejsBlock_editbarMenuLeft = (hook_name, args, cb) ->
+  args.content = args.content + (require 'ep_etherpad-lite/node/eejs/').require 'ep_tables/templates/datatablesEditbarButtons.ejs'
+
+exports.eejsBlock_styles = (hook_name, args, cb) ->
+  args.content = ((require 'ep_etherpad-lite/node/eejs/').require 'ep_tables/templates/styles.ejs') + args.content
+
+exports.aceAttribsToClasses = (hook, context) ->
+  Datatables.attributes = null
+  if context.key is 'tblProp'
+    Datatables.attributes = context.value
+    ['tblProp:' + context.value]
+
+exports.aceStartLineAndCharForPoint = (hook, context) ->
+  selStart = null
+  try
+    Datatables.context = context
+    selStart = Datatables.getLineAndCharForPoint! if Datatables.isFocused!
+  catch error
+    top.console.log 'error ' + error
+    top.console.log 'context rep' + Datatables.context.rep
+  selStart
+
+exports.aceEndLineAndCharForPoint = (hook, context) ->
+  selEndLine = null
+  try
+    Datatables.context = context
+    selEndLine = Datatables.getLineAndCharForPoint! if Datatables.isFocused!
+  catch error
+    top.console.log 'error ' + error
+    top.console.log 'context rep' + Datatables.context.rep
+  selEndLine
+
+exports.aceKeyEvent = (hook, context) ->
+  specialHandled = false
+  try
+    Datatables.context = context
+    if Datatables.isFocused!
+      evt = context.evt
+      type = evt.type
+      keyCode = evt.keyCode
+      isTypeForSpecialKey = if Ace2Common.browser.msie or Ace2Common.browser.safari then type is 'keydown' else type is 'keypress'
+      isTypeForCmdKey = if Ace2Common.browser.msie or Ace2Common.browser.safari then type is 'keydown' else type is 'keypress'
+      which = evt.which
+      if not specialHandled and isTypeForSpecialKey and keyCode is 9 and not (evt.metaKey or evt.ctrlKey)
+        context.editorInfo.ace_fastIncorp 5
+        evt.preventDefault!
+        Datatables.performDocumentTableTabKey!
+        specialHandled = true
+      if not specialHandled and isTypeForSpecialKey and keyCode is 13
+        context.editorInfo.ace_fastIncorp 5
+        evt.preventDefault!
+        Datatables.doReturnKey!
+        specialHandled = true
+      if not specialHandled and isTypeForSpecialKey and (keyCode is Datatables.vars.JS_KEY_CODE_DEL or keyCode is Datatables.vars.JS_KEY_CODE_BS or (String.fromCharCode which).toLowerCase! is 'h' and evt.ctrlKey)
+        context.editorInfo.ace_fastIncorp 20
+        evt.preventDefault!
+        specialHandled = true
+        Datatables.doDeleteKey! if Datatables.isCellDeleteOk keyCode
+  catch
+  specialHandled
+
+if typeof Datatables is 'undefined'
+  Datatables = do ->
+    nodeText = (n) ->
+      text = []
+      self = arguments_.callee
+      el = void
+      els = n.childNodes
+      excluded = {
+        noscript: 'noscript'
+        script: 'script'
+      }
+      i = 0
+      iLen = els.length
+      while i < iLen
+        el = els[i]
+        if el.nodeType is 1 and el.tagName.toLowerCase! of excluded then text.push self el else if el.nodeType is 3 then text.push el.data
+        i++
+      text.join ''
+    dt = {
+      defaults: {tblProps: {
+        borderWidth: '1'
+        cellAttrs: []
+        width: '6'
+        rowAttrs: {}
+        colAttrs: []
+        authors: {}
+      }}
+      config: {}
+      vars: {
+        OVERHEAD_LEN_PRE: '{"payload":[["'.length
+        OVERHEAD_LEN_MID: '","'.length
+        OVERHEAD_LEN_ROW_START: '["'.length
+        OVERHEAD_LEN_ROW_END: '"],'.length
+        JS_KEY_CODE_BS: 8
+        JS_KEY_CODE_DEL: 46
+        TBL_OPTIONS: [
+          'addTbl'
+          'addTblRowA'
+          'addTblRowB'
+          'addTblColL'
+          'addTblColR'
+          'delTbl'
+          'delTblRow'
+          'delTblCol'
+          'delImg'
+        ]
+      }
+      context: null
+    }
+    dt.isFocused = ->
+      return false if not @context.rep.selStart or not @context.rep.selEnd
+      line = @context.rep.lines.atIndex @context.rep.selStart.0
+      if not line then return false
+      currLineText = line.text or ''
+      if (currLineText.indexOf 'data-tables') is -1 then return false
+      true
+    dt._getRowEndOffset = (rowStartOffset, tds) ->
+      rowEndOffset = rowStartOffset + @vars.OVERHEAD_LEN_ROW_START
+      i = 0
+      len = tds.length
+      while i < len
+        overHeadLen = @vars.OVERHEAD_LEN_MID
+        overHeadLen = @vars.OVERHEAD_LEN_ROW_END if i is len - 1
+        rowEndOffset += tds[i].length + overHeadLen
+        i++
+      rowEndOffset
+    dt.getFocusedTdInfo = (payload, colStart) ->
+      payloadOffset = colStart - @vars.OVERHEAD_LEN_PRE
+      rowStartOffset = 0
+      payloadSum = 0
+      rIndex = 0
+      rLen = payload.length
+      while rIndex < rLen
+        tds = payload[rIndex]
+        tIndex = 0
+        tLen = tds.length
+        while tIndex < tLen
+          overHeadLen = @vars.OVERHEAD_LEN_MID
+          overHeadLen = @vars.OVERHEAD_LEN_ROW_END if tIndex is tLen - 1
+          payloadSum += tds[tIndex].length + overHeadLen
+          if payloadSum >= payloadOffset
+            tIndex++ if payloadSum is payloadOffset
+            leftOverTdTxtLen = if payloadSum - payloadOffset is 0 then payload[rIndex][tIndex].length + @vars.OVERHEAD_LEN_MID else payloadSum - payloadOffset
+            cellCaretPos = tds[tIndex].length - leftOverTdTxtLen - overHeadLen
+            rowEndOffset = @_getRowEndOffset rowStartOffset, tds
+            return {
+              row: rIndex
+              td: tIndex
+              leftOverTdTxtLen: leftOverTdTxtLen
+              rowStartOffset: rowStartOffset
+              rowEndOffset: rowEndOffset
+              cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen
+              cellEndOffset: payloadSum
+              cellCaretPos: cellCaretPos
+            }
+          tIndex++
+        rowStartOffset = payloadSum
+        payloadSum += @vars.OVERHEAD_LEN_ROW_START
+        rIndex++
+    dt.printCaretPos = (start, end) ->
+      top.console.log JSON.stringify start
+      top.console.log JSON.stringify end
+    dt.doDatatableOptions = (cmd, xByY) ->
+      Datatables.context = this
+      if typeof cmd is 'object' and cmd.tblPropertyChange
+        Datatables.updateTableProperties cmd
+      else
+        switch cmd
+        case Datatables.vars.TBL_OPTIONS.0
+          Datatables.addTable xByY
+        case Datatables.vars.TBL_OPTIONS.1
+          Datatables.insertTblRow 'addA'
+        case Datatables.vars.TBL_OPTIONS.2
+          Datatables.insertTblRow 'addB'
+        case Datatables.vars.TBL_OPTIONS.3
+          Datatables.insertTblColumn 'addL'
+        case Datatables.vars.TBL_OPTIONS.4
+          Datatables.insertTblColumn 'addR'
+        case Datatables.vars.TBL_OPTIONS.5
+          Datatables.deleteTable!
+        case Datatables.vars.TBL_OPTIONS.6
+          Datatables.deleteTblRow!
+        case Datatables.vars.TBL_OPTIONS.7
+          Datatables.deleteTblColumn!
+    dt.addTable = (tableObj) ->
+      rep = @context.rep
+      start = rep.selStart
+      end = rep.selEnd
+      line = rep.lines.atIndex rep.selStart.0
+      hasMoreRows = null
+      isRowAddition = null
+      if tableObj
+        hasMoreRows = tableObj.hasMoreRows
+        isRowAddition = tableObj.isRowAddition
+      if isRowAddition
+        table = JSON.parse tableObj.tblString
+        insertTblRowBelow 0, table
+        performDocApplyTblAttrToRow rep.selStart, JSON.stringify table.tblProperties
+        return 
+      if line
+        currLineText = line.text
+        if not ((currLineText.indexOf 'data-tables') is -1)
+          while true
+            rep.selStart.0 = rep.selStart.0 + 1
+            currLineText = (rep.lines.atIndex rep.selStart.0).text
+            break if not ((currLineText.indexOf 'data-tables') isnt -1)
+          rep.selEnd.1 = rep.selStart.1 = currLineText.length
+          @context.editorInfo.ace_doReturnKey!
+          @context.editorInfo.ace_doReturnKey!
+        else
+          rep.selEnd.1 = rep.selStart.1 = currLineText.length
+          @context.editorInfo.ace_doReturnKey!
+      if not tableObj?
+        authors = {}
+        @insertTblRowBelow 3
+        @performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties!
+        @insertTblRowBelow 3
+        @performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties authors
+        @insertTblRowBelow 3
+        @performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties authors
+        @context.editorInfo.ace_doReturnKey!
+        @updateAuthorAndCaretPos rep.selStart.0 - 3
+        return 
+      xByYSelect = if typeof tableObj is 'object' then null else tableObj.split 'X'
+      if xByYSelect? and xByYSelect.length is 3
+        cols = parseInt xByYSelect.1
+        rows = parseInt xByYSelect.2
+        jsoStrTblProp = JSON.stringify @createDefaultTblProperties!
+        authors = {}
+        i = 0
+        while i < rows
+          @insertTblRowBelow cols
+          if i is 0 then @performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties! else @performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties authors
+          i++
+        @updateAuthorAndCaretPos rep.selStart.0 - rows + 1
+        return 
+      newText
+    dt.insertTblRow = (aboveOrBelow) ->
+      func = 'insertTblRow()'
+      rep = @context.rep
+      try
+        newText = ''
+        currLineText = (rep.lines.atIndex rep.selStart.0).text
+        payload = (JSON.parse currLineText).payload
+        currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
+        currRow = currTdInfo.row
+        lastRowOffSet = 0
+        start = []
+        end = []
+        start.0 = rep.selStart.0
+        start.1 = rep.selStart.1
+        end.0 = rep.selStart.0
+        end.1 = rep.selStart.1
+        if aboveOrBelow is 'addA'
+          rep.selStart.0 = rep.selEnd.0 = rep.selStart.0 - 1
+          @insertTblRowBelow payload.0.length
+        else
+          @insertTblRowBelow payload.0.length
+        @context.editorInfo.ace_performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties!
+        @updateAuthorAndCaretPos rep.selStart.0
+        updateEvenOddBgColor = true
+        @sanitizeTblProperties rep.selStart, updateEvenOddBgColor
+      catch
+    dt.deleteTable = ->
+      rep = @context.rep
+      func = 'deleteTable()'
+      start = rep.seStart
+      end = rep.seEnd
+      try
+        line = rep.selStart.0 - 1
+        numOfLinesAbove = 0
+        numOfLinesBelow = 0
+        while not (((rep.lines.atIndex line).text.indexOf 'data-tables') is -1)
+          numOfLinesAbove++
+          line--
+        line = rep.selEnd.0 + 1
+        while not (((rep.lines.atIndex line).text.indexOf 'data-tables') is -1)
+          numOfLinesBelow++
+          line++
+        rep.selStart.1 = 0
+        rep.selStart.0 = rep.selStart.0 - numOfLinesAbove
+        rep.selEnd.0 = rep.selEnd.0 + numOfLinesBelow
+        rep.selEnd.1 = (rep.lines.atIndex rep.selEnd.0).text.length
+        @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
+      catch
+    dt.deleteTblRow = ->
+      func = 'deleteTblRow()'
+      rep = @context.rep
+      try
+        currLineText = (rep.lines.atIndex rep.selStart.0).text
+        return  if (currLineText.indexOf 'data-tables') is -1
+        rep.selEnd.0 = rep.selStart.0 + 1
+        rep.selStart.1 = 0
+        rep.selEnd.1 = 0
+        @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
+        currLineText = (rep.lines.atIndex rep.selStart.0).text
+        if (currLineText.indexOf 'data-tables') is -1 then return 
+        @updateAuthorAndCaretPos rep.selStart.0, 0, 0
+        updateEvenOddBgColor = true
+        @sanitizeTblProperties rep.selStart, updateEvenOddBgColor
+      catch
+    dt.updateTableProperties = (props) ->
+      rep = @context.rep
+      currTd = null
+      if props.tblColWidth or props.tblSingleColBgColor or props.tblColVAlign
+        currLine = rep.lines.atIndex rep.selStart.0
+        currLineText = currLine.text
+        tblJSONObj = JSON.parse currLineText
+        payload = tblJSONObj.payload
+        currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
+        currTd = currTdInfo.td
+      if props.tblWidth or props.tblHeight or props.tblBorderWidth or props.tblBorderColor or props.tblColWidth or props.tblSingleColBgColor or props.tblEvenRowBgColor or props.tblOddRowBgColor or props.tblColVAlign
+        start = []
+        start.0 = rep.selStart.0
+        start.1 = rep.selStart.1
+        numOfLinesAbove = @getTblAboveRowsFromCurFocus start
+        tempStart = []
+        tempStart.0 = start.0 - numOfLinesAbove
+        tempStart.1 = start.1
+        while tempStart.0 < rep.lines.length! and ((rep.lines.atIndex tempStart.0).text.indexOf 'data-tables') isnt -1
+          if props.tblEvenRowBgColor and tempStart.0 % 2 isnt 0
+            tempStart.0 = tempStart.0 + 1
+            continue
+          else
+            if props.tblOddRowBgColor and tempStart.0 % 2 is 0
+              tempStart.0 = tempStart.0 + 1
+              continue
+          @updateTablePropertiesHelper props, tempStart, currTd
+          tempStart.0 = tempStart.0 + 1
+      else
+        start = []
+        start.0 = rep.selStart.0
+        start.1 = rep.selStart.1
+        @updateTablePropertiesHelper props, start, currTd
+    dt.addCellAttr = (start, tblJSONObj, tblProperties, attrName, attrValue) ->
+      rep = @context.rep
+      payload = tblJSONObj.payload
+      currTdInfo = @getFocusedTdInfo payload, start.1
+      currRow = currTdInfo.row
+      currTd = currTdInfo.td
+      cellAttrs = tblProperties.cellAttrs
+      row = cellAttrs[currRow]
+      row = [] if not row? or typeof row is 'undefined'
+      cell = row[currTd]
+      if not cell? or typeof cell is 'undefined' then cell = {}
+      if attrName is 'fontWeight' or attrName is 'fontStyle' or attrName is 'textDecoration' then attrValue = '' if cell[attrName] is attrValue else if cell[attrName] is attrValue then return false
+      cell[attrName] = attrValue
+      row[currTd] = cell
+      cellAttrs[currRow] = row
+      tblProperties.cellAttrs = cellAttrs
+      tblProperties
+    dt.addRowAttr = (tblJSONObj, tblProperties, attrName, attrValue) ->
+      rep = @context.rep
+      rowAttrs = tblProperties.rowAttrs
+      if attrName is 'bgColor'
+        payload = tblJSONObj.payload
+        currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
+        currRow = currTdInfo.row
+        singleRowAttrs = rowAttrs.singleRowAttrs
+        singleRowAttrs = [] if not singleRowAttrs? or typeof singleRowAttrs is 'undefined'
+        if not singleRowAttrs[currRow]? or typeof singleRowAttrs[currRow] is 'undefined' then singleRowAttrs[currRow] = {} else if singleRowAttrs[currRow][attrName] is attrValue then return false
+        singleRowAttrs[currRow][attrName] = attrValue
+        rowAttrs.singleRowAttrs = singleRowAttrs
+      else
+        return false if rowAttrs[attrName] is attrValue
+        rowAttrs[attrName] = attrValue
+      tblProperties.rowAttrs = rowAttrs
+      tblProperties
+    dt.addColumnAttr = (start, tblJSONObj, tblProperties, attrName, attrValue, currTd) ->
+      payload = tblJSONObj.payload
+      currTdInfo = @getFocusedTdInfo payload, start.1
+      colAttrs = tblProperties.colAttrs
+      colAttrs = [] if not colAttrs? or typeof colAttrs is 'undefined'
+      if not colAttrs[currTd]? or typeof colAttrs[currTd] is 'undefined' then colAttrs[currTd] = {} else if colAttrs[currTd][attrName] is attrValue then return false
+      colAttrs[currTd][attrName] = attrValue
+      tblProperties.colAttrs = colAttrs
+      tblProperties
+    dt.updateTablePropertiesHelper = (props, start, currTd) ->
+      rep = @context.rep
+      lastTblPropertyUsed = 'updateTableProperties'
+      start = start or rep.selStart
+      return  if not start
+      currLine = rep.lines.atIndex start.0
+      currLineText = currLine.text
+      if (currLineText.indexOf 'data-tables') is -1 then return true
+      (try
+        tblJSONObj = JSON.parse currLineText
+        tblProperties = @getLineTableProperty start.0
+        update = false
+        if props.tblWidth or props.tblHeight or props.tblBorderWidth or props.tblBorderColor
+          currAttrValue = tblProperties[props.attrName]
+          if props.attrValue? and (typeof currAttrValue is 'undefined' or currAttrValue isnt props.attrValue)
+            tblProperties[props.attrName] = props.attrValue
+            update = true
+        if props.tblCellFontWeight or props.tblCellFontStyle or props.tblCellTextDecoration
+          tblProps = @addCellAttr start, tblJSONObj, tblProperties, props.attrName, props.attrValue
+          if tblProps
+            tblProperties = tblProps
+            update = true
+        if props.tblCellFontSize or props.tblCellBgColor or props.tblCellHeight or props.tblCellPadding or props.tblcellVAlign
+          tblProps = @addCellAttr start, tblJSONObj, tblProperties, props.attrName, props.attrValue
+          if tblProps
+            tblProperties = tblProps
+            update = true
+        if props.tblEvenRowBgColor or props.tblOddRowBgColor
+          tblProps = @addRowAttr tblJSONObj, tblProperties, props.attrName, props.attrValue
+          if tblProps
+            tblProperties = tblProps
+            update = true
+        if props.tblSingleRowBgColor or props.tblRowVAlign
+          tblProps = @addRowAttr tblJSONObj, tblProperties, props.attrName, props.attrValue
+          if tblProps
+            tblProperties = tblProps
+            update = true
+        if props.tblColWidth or props.tblSingleColBgColor or props.tblColVAlign
+          tblProps = @addColumnAttr start, tblJSONObj, tblProperties, props.attrName, props.attrValue, currTd
+          if tblProps
+            tblProperties = tblProps
+            update = true
+        if update then @updateTblPropInAPool -1, -1, tblProperties, start
+      catch)
+    dt.updateAuthorAndCaretPos = (magicDomLineNum, tblRowNum, tblColNum) ->
+      rep = @context.rep
+      rep.selStart.1 = rep.selEnd.1 = @vars.OVERHEAD_LEN_PRE
+      rep.selStart.0 = rep.selEnd.0 = magicDomLineNum
+      row = if typeof tblRowNum is 'undefined' or not tblRowNum? then 0 else tblRowNum
+      col = if typeof tblColNum is 'undefined' or not tblRowNum? then 0 else tblColNum
+      @updateTblPropInAPool row, col, null, rep.selStart
+      rep.selStart.1 = rep.selEnd.1 = @vars.OVERHEAD_LEN_PRE
+      @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
+    dt.insertTblRowBelow = (numOfRows, table) ->
+      rep = @rep
+      currLineText = (rep.lines.atIndex rep.selStart.0).text
+      payload = [[]]
+      if not numOfRows and numOfRows isnt 0
+        tblPayload = (JSON.parse currLineText).payload
+        numOfRows = tblPayload.0.length
+      tblRows = new Array numOfRows
+      if not (numOfRows is 0)
+        i = 0
+        while i < tblRows.length
+          tblRows[i] = ' '
+          i++
+      payload = [tblRows]
+      if table then payload = table.payload
+      tableObj = {
+        payload: payload
+        tblId: 1
+        tblClass: 'data-tables'
+        trClass: 'alst'
+        tdClass: 'hide-el'
+      }
+      rep.selEnd.1 = rep.selStart.1 = currLineText.length
+      @context.editorInfo.ace_doReturnKey!
+      @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, JSON.stringify tableObj
+    dt.createDefaultTblProperties = (authors) ->
+      rep = @context.rep
+      defTblProp = {
+        borderWidth: '1'
+        cellAttrs: []
+        width: '6'
+        rowAttrs: {}
+        colAttrs: []
+        authors: {}
+      }
+      defTblProp.'authors' = authors if authors
+      prevLine = rep.lines.atIndex rep.selEnd.0 - 1
+      jsoTblProp = null
+      if prevLine
+        prevLineText = prevLine.text
+        jsoTblProp = @getLineTableProperty rep.selStart.0 - 1 if not ((prevLineText.indexOf 'data-tables') is -1)
+      if not jsoTblProp
+        nextLine = rep.lines.atIndex rep.selEnd.0 - 1
+        if nextLine
+          nextLineText = nextLine.text
+          jsoTblProp = @getLineTableProperty rep.selStart.0 + 1 if not ((nextLineText.indexOf 'data-tables') is -1)
+      if jsoTblProp
+        defTblProp.borderWidth = jsoTblProp.borderWidth
+        defTblProp.borderColor = jsoTblProp.borderColor
+        defTblProp.width = jsoTblProp.width
+        defTblProp.height = jsoTblProp.height
+        defTblProp.colAttrs = jsoTblProp.colAttrs
+      jsoStrTblProp = JSON.stringify defTblProp
+      jsoStrTblProp
+    dt.performDocApplyTblAttrToRow = (start, jsoStrTblProp) ->
+      tempStart = []
+      tempEnd = []
+      tempStart.0 = start.0
+      tempEnd.0 = start.0
+      tempStart.1 = 0
+      tempEnd.1 = (@context.rep.lines.atIndex start.0).text.length
+      @context.editorInfo.ace_performDocumentApplyAttributesToRange tempStart, tempEnd, [['tblProp', jsoStrTblProp]]
+    dt.performDocumentTableTabKey = ->
+      try
+        context = @context
+        rep = context.rep
+        currLine = rep.lines.atIndex rep.selStart.0
+        currLineText = currLine.text
+        tblJSONObj = JSON.parse currLineText
+        payload = tblJSONObj.payload
+        currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
+        leftOverTdTxtLen = currTdInfo.leftOverTdTxtLen
+        currRow = currTdInfo.row
+        currTd = currTdInfo.td
+        if typeof payload[currRow][currTd + 1] is 'undefined'
+          currRow += 1
+          nextLine = rep.lines.atIndex rep.selStart.0 + 1
+          nextLineText = nextLine.text
+          updateEvenOddBgColor = false
+          if not nextLineText? or nextLineText is '' or (nextLineText.indexOf 'data-tables') is -1
+            @insertTblRowBelow null, null
+            @performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties!
+            rep.selEnd.1 = rep.selStart.1 = @vars.OVERHEAD_LEN_PRE
+            updateEvenOddBgColor = true
+          else
+            currTd = -1
+            rep.selStart.0 = rep.selEnd.0 = rep.selStart.0 + 1
+            tblJSONObj = JSON.parse nextLineText
+            payload = tblJSONObj.payload
+            leftOverTdTxtLen = payload.0.0.length
+            rep.selEnd.1 = rep.selStart.1 = @vars.OVERHEAD_LEN_PRE + leftOverTdTxtLen
+          context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
+          start = []
+          start.0 = rep.selStart.0
+          start.1 = rep.selStart.1
+          dt.updateTblCellAuthor 0, 0, null, start, updateEvenOddBgColor
+        else
+          nextTdTxtLen = if typeof payload[currRow] is 'undefined' then -leftOverTdTxtLen else payload[currRow][currTd + 1].length
+          payload = tblJSONObj.payload
+          rep.selStart.1 = rep.selEnd.1 = rep.selEnd.1 + nextTdTxtLen + leftOverTdTxtLen
+          context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
+          dt.updateTblPropInAPool currRow, currTd + 1, null, rep.selStart
+      catch
+    dt.getTdInfo = (payload, tdIndex) ->
+      rep = @context.rep
+      startOffset = @vars.OVERHEAD_LEN_PRE
+      rowStartOffset = startOffset
+      payloadSum = startOffset
+      tds = payload.0
+      tIndex = 0
+      tLen = tds.length
+      while tIndex < tLen
+        overHeadLen = @vars.OVERHEAD_LEN_MID
+        overHeadLen = @vars.OVERHEAD_LEN_ROW_END if tIndex is tLen - 1
+        payloadSum += tds[tIndex].length + overHeadLen
+        if tIndex >= tdIndex
+          return {
+            cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen
+            cellEndOffset: payloadSum
+          }
+        tIndex++
+    dt.getNextTdInfo = (payload, currTdInfo) ->
+      rep = @context.rep
+      startOffset = currTdInfo.rowEndOffset
+      rowStartOffset = startOffset
+      payloadSum = startOffset
+      tds = payload[currTdInfo.row]
+      tIndex = 0
+      tLen = tds.length
+      while tIndex < tLen
+        overHeadLen = @vars.OVERHEAD_LEN_MID
+        overHeadLen = @vars.OVERHEAD_LEN_ROW_END if tIndex is tLen - 1
+        payloadSum += tds[tIndex].length + overHeadLen
+        if tIndex >= currTdInfo.td
+          leftOverTdTxtLen = if payloadSum - startOffset is 0 then payload[currTdInfo.row + 1][tIndex].length + @vars.OVERHEAD_LEN_MID else payloadSum - startOffset
+          rowEndOffset = @_getRowEndOffset rowStartOffset, tds
+          tdInfo = {
+            row: currTdInfo.row + 1
+            td: tIndex
+            leftOverTdTxtLen: leftOverTdTxtLen
+            rowStartOffset: rowStartOffset
+            rowEndOffset: rowEndOffset
+            cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen
+            cellEndOffset: payloadSum
+          }
+          return tdInfo
+        tIndex++
+    dt.insertTblColumn = (leftOrRight, start, end) ->
+      rep = @context.rep
+      func = 'insertTblColumn()'
+      try
+        currLineText = (rep.lines.atIndex rep.selStart.0).text
+        tblJSONObj = JSON.parse currLineText
+        payload = tblJSONObj.payload
+        currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
+        currTd = currTdInfo.td
+        start = []
+        end = []
+        start.0 = rep.selStart.0
+        start.1 = rep.selStart.1
+        end.0 = rep.selEnd.0
+        end.1 = rep.selEnd.1
+        currTd -= 1 if leftOrRight is 'addL'
+        numOfLinesAbove = @getTblAboveRowsFromCurFocus start
+        rep.selEnd.0 = rep.selStart.0 = rep.selStart.0 - numOfLinesAbove
+        while rep.selStart.0 < rep.lines.length! and ((rep.lines.atIndex rep.selStart.0).text.indexOf 'data-tables') isnt -1
+          currLineText = (rep.lines.atIndex rep.selStart.0).text
+          tblJSONObj = JSON.parse currLineText
+          payload = tblJSONObj.payload
+          cellPos = (@getTdInfo payload, currTd).cellEndOffset
+          newText = '" ",'
+          if currTd is payload.0.length - 1
+            rep.selStart.1 = rep.selEnd.1 = cellPos - @vars.OVERHEAD_LEN_ROW_END + 1
+            newText = '," "'
+          else
+            if currTd is -1 then rep.selStart.1 = rep.selEnd.1 = @vars.OVERHEAD_LEN_PRE - 1 else rep.selStart.1 = rep.selEnd.1 = cellPos - 1
+          @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, newText
+          rep.selEnd.0 = rep.selStart.0 = rep.selStart.0 + 1
+        rep.selStart = start
+        rep.selEnd = end
+        if leftOrRight is 'addL'
+          rep.selStart.1 = rep.selEnd.1 = @vars.OVERHEAD_LEN_PRE
+          rep.selStart.0 = rep.selEnd.0 = rep.selStart.0
+          @updateTblPropInAPool 0, 0, null, rep.selStart
+          rep.selStart.1 = rep.selEnd.1 = @vars.OVERHEAD_LEN_PRE
+        currTd++
+        updateEvenOddBgColor = false
+        updateColAttrs = true
+        @sanitizeTblProperties start, updateEvenOddBgColor, updateColAttrs, currTd, 'add'
+        @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
+      catch
+    dt.deleteTblColumn = ->
+      func = 'deleteTblColumn()'
+      rep = @context.rep
+      try
+        currLineText = (rep.lines.atIndex rep.selStart.0).text
+        tblJSONObj = JSON.parse currLineText
+        payload = tblJSONObj.payload
+        deleteTable! if payload.0.length is 1
+        currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
+        currTd = currTdInfo.td
+        start = []
+        end = []
+        start.0 = rep.selStart.0
+        start.1 = rep.selStart.1
+        end.0 = rep.selEnd.0
+        end.1 = rep.selEnd.1
+        numOfLinesAbove = @getTblAboveRowsFromCurFocus start
+        rep.selEnd.0 = rep.selStart.0 = rep.selStart.0 - numOfLinesAbove
+        while rep.selStart.0 < rep.lines.length! and ((rep.lines.atIndex rep.selStart.0).text.indexOf 'data-tables') isnt -1
+          currLineText = (rep.lines.atIndex rep.selStart.0).text
+          tblJSONObj = JSON.parse currLineText
+          payload = tblJSONObj.payload
+          cellTdInfo = @getTdInfo payload, currTd
+          newText = '" ",'
+          if currTd is payload.0.length - 1
+            rep.selStart.1 = cellTdInfo.cellStartOffset - 2
+            rep.selEnd.1 = cellTdInfo.cellEndOffset - 2
+          else
+            if currTd is 0
+              rep.selStart.1 = @vars.OVERHEAD_LEN_PRE - 1
+              rep.selEnd.1 = cellTdInfo.cellEndOffset - 1
+            else
+              rep.selStart.1 = cellTdInfo.cellStartOffset - 1
+              rep.selEnd.1 = cellTdInfo.cellEndOffset - 1
+          @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
+          rep.selEnd.0 = rep.selStart.0 = rep.selStart.0 + 1
+        rep.selStart = start
+        rep.selEnd = end
+        updateEvenOddBgColor = false
+        updateColAttrs = true
+        @sanitizeTblProperties start, updateEvenOddBgColor, updateColAttrs, currTd, 'del'
+        @updateAuthorAndCaretPos rep.selStart.0, 0, 0
+      catch
+    dt.insertTblRowBelow = (numOfRows, table) ->
+      context = @context
+      rep = context.rep
+      currLineText = (rep.lines.atIndex rep.selStart.0).text
+      payload = [[]]
+      if not numOfRows and numOfRows isnt 0
+        tblPayload = (JSON.parse currLineText).payload
+        numOfRows = tblPayload.0.length
+      tblRows = new Array numOfRows
+      if not (numOfRows is 0)
+        i = 0
+        while i < tblRows.length
+          tblRows[i] = ' '
+          i++
+      payload = [tblRows]
+      if table then payload = table.payload
+      tableObj = {
+        payload: payload
+        tblId: 1
+        tblClass: 'data-tables'
+        trClass: 'alst'
+        tdClass: 'hide-el'
+      }
+      rep.selEnd.1 = rep.selStart.1 = currLineText.length
+      @context.editorInfo.ace_inCallStackIfNecessary 'newline', @context.editorInfo.ace_doReturnKey
+      context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, JSON.stringify tableObj
+    dt.doReturnKey = ->
+      context = @context
+      rep = context.rep
+      start = rep.seStart
+      end = rep.selEnd
+      lastTblPropertyUsed = 'doTableReturnKey'
+      currLine = rep.lines.atIndex rep.selStart.0
+      currLineText = currLine.text
+      if not ((currLineText.indexOf 'data-tables') is -1)
+        func = 'doTableReturnKey()'
+        try
+          currCarretPos = rep.selStart.1
+          if (currLineText.substring currCarretPos - 1, currCarretPos + 2) is '","'
+            return true
+          else
+            if (currLineText.substring currCarretPos - 2, currCarretPos + 1) is '","'
+              return true
+            else
+              if currCarretPos < @vars.OVERHEAD_LEN_PRE then return true else if currCarretPos > currLineText.length then return true
+          start = rep.selStart
+          end = rep.selEnd
+          newText = ' /r/n '
+          start.1 = currCarretPos
+          end.1 = currCarretPos
+          (try
+            jsonObj = JSON.parse (currLineText.substring 0, start.1) + newText + currLineText.substring start.1
+            payloadStr = JSON.stringify jsonObj.payload
+            return true if currCarretPos > payloadStr.length + @vars.OVERHEAD_LEN_PRE - 2
+          catch error
+            return true)
+          context.editorInfo.ace_performDocumentReplaceRange start, end, newText
+        catch
+        true
+    dt.isCellDeleteOk = (keyCode) ->
+      context = @context
+      rep = context.rep
+      start = rep.selStart
+      end = rep.selEnd
+      currLine = rep.lines.atIndex rep.selStart.0
+      currLineText = currLine.text
+      return true if (currLineText.indexOf 'data-tables') is -1
+      isDeleteAccepted = false
+      (try
+        tblJSONObj = JSON.parse currLineText
+        table = tblJSONObj.payload
+        currTdInfo = @getFocusedTdInfo table, rep.selStart.1
+        cellEntryLen = table[currTdInfo.row][currTdInfo.td].length
+        currCarretPos = rep.selStart.1
+        if (currLineText.substring currCarretPos - 1, currCarretPos + 2) is '","'
+          return false
+        else
+          if (currLineText.substring currCarretPos - 2, currCarretPos + 1) is '","' then return false
+        switch keyCode
+        case @vars.JS_KEY_CODE_BS
+          isDeleteAccepted = true if cellEntryLen isnt 0 and cellEntryLen > currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID
+        case @vars.JS_KEY_CODE_DEL
+          return false
+          isDeleteAccepted = true if cellEntryLen isnt 0 and currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID > 0
+        default
+          isDeleteAccepted = true if cellEntryLen isnt 0 and cellEntryLen > currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID
+      catch error
+        isDeleteAccepted = false)
+      isDeleteAccepted
+    dt.nodeTextPlain = (n) -> n.innerText or n.textContent or n.nodeValue or ''
+    dt.toString = -> 'ep_tables'
+    dt.getLineAndCharForPoint = ->
+      context = @context
+      point = context.point
+      root = context.root
+      if point.node is root
+        if point.index is 0
+          [0, 0]
+        else
+          N = @context.rep.lines.length!
+          ln = @context.rep.lines.atIndex N - 1
+          [N - 1, ln.text.length]
+      else
+        n = point.node
+        col = 0
+        col = point.index if (nodeText n) or point.index > 0
+        parNode = void
+        prevSib = void
+        while not ((parNode = n.parentNode) is root)
+          if prevSib = n.previousSibling
+            n = prevSib
+            textLen = if (nodeText n).length is 0 then (@nodeTextPlain n).length else (nodeText n).length
+            col += textLen
+          else
+            n = parNode
+        if n.id is '' then console.debug 'BAD'
+        if n.firstChild and context.editorInfo.ace_isBlockElement n.firstChild then col += 1
+        lineEntry = @context.rep.lines.atKey n.id
+        lineNum = @context.rep.lines.indexOfEntry lineEntry
+        [lineNum, col]
+    dt.doDeleteKey = ->
+      context = @context
+      evt = context.evt or {}
+      handled = false
+      rep = @context.rep
+      editorInfo = context.editorInfo
+      if rep.selStart
+        if editorInfo.ace_isCaret!
+          lineNum = editorInfo.ace_caretLine!
+          col = editorInfo.ace_caretColumn!
+          lineEntry = rep.lines.atIndex lineNum
+          lineText = lineEntry.text
+          lineMarker = lineEntry.lineMarker
+          if /^ +$/.exec lineText.substring lineMarker, col
+            col2 = col - lineMarker
+            tabSize = ''.length
+            toDelete = (col2 - 1) % tabSize + 1
+            editorInfo.ace_performDocumentReplaceRange [lineNum, col - toDelete], [lineNum, col], ''
+            handled = true
+        if not handled
+          if editorInfo.ace_isCaret!
+            theLine = editorInfo.ace_caretLine!
+            lineEntry = rep.lines.atIndex theLine
+            if editorInfo.ace_caretColumn! <= lineEntry.lineMarker
+              action = 'delete_newline'
+              prevLineListType = if theLine > 0 then editorInfo.ace_getLineListType theLine - 1 else ''
+              thisLineListType = editorInfo.ace_getLineListType theLine
+              prevLineEntry = theLine > 0 and rep.lines.atIndex theLine - 1
+              prevLineBlank = prevLineEntry and prevLineEntry.text.length is prevLineEntry.lineMarker
+              if thisLineListType
+                if prevLineBlank and not prevLineListType
+                  editorInfo.ace_performDocumentReplaceRange [theLine - 1, prevLineEntry.text.length], [theLine, 0], ''
+                else
+                  editorInfo.ace_performDocumentReplaceRange [theLine, 0], [theLine, lineEntry.lineMarker], ''
+              else
+                if theLine > 0
+                  editorInfo.ace_performDocumentReplaceRange [theLine - 1, prevLineEntry.text.length], [theLine, 0], ''
+            else
+              docChar = editorInfo.ace_caretDocChar!
+              if docChar > 0
+                if evt.metaKey or evt.ctrlKey or evt.altKey
+                  deleteBackTo = docChar - 1
+                  while deleteBackTo > lineEntry.lineMarker and editorInfo.ace_isWordChar rep.alltext.charAt deleteBackTo - 1
+                    deleteBackTo--
+                  editorInfo.ace_performDocumentReplaceCharRange deleteBackTo, docChar, ''
+                else
+                  returnKeyWitinTblOffset = 0
+                  returnKeyWitinTblOffset = 4 if (lineText.substring col - 5, col) is '/r/n '
+                  editorInfo.ace_performDocumentReplaceCharRange docChar - 1 - returnKeyWitinTblOffset, docChar, ''
+          else
+            editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
+      line = editorInfo.ace_caretLine!
+      if line isnt -1 and (editorInfo.ace_renumberList line + 1) is null then editorInfo.ace_renumberList line
+    dt.getLineTableProperty = (lineNum) ->
+      rep = @context.rep
+      aline = rep.alines[lineNum]
+      if aline
+        opIter = Changeset.opIterator aline
+        if opIter.hasNext!
+          tblJSString = Changeset.opAttributeValue opIter.next!, 'tblProp', rep.apool
+          try
+            return JSON.parse tblJSString
+          catch error
+            return @defaults.tblProps
+      @defaults.tblProps
+    dt.updateTblPropInAPool = (row, td, jsoTblProp, start) ->
+      try
+        rep = @context.rep
+        tblProps = void
+        editorInfo = @context.editorInfo
+        thisAuthor = editorInfo.ace_getAuthor!
+        authorInfos = editorInfo.ace_getAuthorInfos!
+        jsoTblProp = @getLineTableProperty start.0 if typeof jsoTblProp is 'undefined' or not jsoTblProp?
+        if row isnt -1 and td isnt -1
+          jsoTblProp.'authors'[thisAuthor] = {
+            row: row
+            cell: td
+            colorId: authorInfos[thisAuthor].bgcolor
+          }
+        jsoStrTblProp = JSON.stringify jsoTblProp
+        attrStart = []
+        attrEnd = []
+        attrStart.0 = start.0
+        attrStart.1 = 0
+        attrEnd.0 = start.0
+        attrEnd.1 = (rep.lines.atIndex start.0).text.length
+        editorInfo.ace_performDocumentApplyAttributesToRange attrStart, attrEnd, [['tblProp', jsoStrTblProp]]
+      catch
+    dt.getCurrTblOddEvenRowBgColor = (startRowNum, currRowNum) ->
+      rowBgColors = {
+        oddBgColor: null
+        evenBgColor: null
+      }
+      if not (startRowNum is currRowNum)
+        jsoTblProp1 = @getLineTableProperty startRowNum
+        jsoTblProp2 = @getLineTableProperty startRowNum + 1
+        rowBgColors.evenBgColor = jsoTblProp1.'rowAttrs'.'evenBgColor' or jsoTblProp2.'rowAttrs'.'evenBgColor'
+        rowBgColors.oddBgColor = jsoTblProp1.'rowAttrs'.'oddBgColor' or jsoTblProp2.'rowAttrs'.'oddBgColor'
+      rowBgColors
+    dt.getTblAboveRowsFromCurFocus = (start) ->
+      rep = @context.rep
+      numOfLinesAbove = 0
+      line = start.0 - 1
+      while not (((rep.lines.atIndex line).text.indexOf 'data-tables') is -1)
+        numOfLinesAbove++
+        line--
+      numOfLinesAbove
+    dt.updateTableIndices = (tblProperties, currTd, addOrDel) ->
+      cellAttrs = tblProperties.cellAttrs
+      rIndex = 0
+      rLen = cellAttrs.length
+      while rIndex < rLen
+        cellAttr = cellAttrs[rIndex]
+        if addOrDel is 'add' then cellAttr.splice currTd, 0, null if cellAttr else cellAttr.splice currTd, 1 if cellAttr
+        rIndex++
+      colAttrs = tblProperties.colAttrs
+      if addOrDel is 'add' then colAttrs.splice currTd, 0, null if colAttrs else colAttrs.splice currTd, 1 if colAttrs
+      tblProperties
+    dt.sanitizeTblProperties = (start, updateEvenOddBgColor, updateColAttrs, currTd, addOrDel) ->
+      rep = @context.rep
+      editorInfo = @context.editorInfo
+      thisAuthor = editorInfo.ace_getAuthor!
+      numOfLinesAbove = @getTblAboveRowsFromCurFocus start
+      tempStart = []
+      tempStart.0 = start.0 - numOfLinesAbove
+      evenOddRowBgColors = {}
+      updateEvenOddBgColor
+      while tempStart.0 < rep.lines.length! and ((rep.lines.atIndex tempStart.0).text.indexOf 'data-tables') isnt -1
+        jsoTblProp = @getLineTableProperty tempStart.0
+        update = false
+        if tempStart.0 isnt start.0 and jsoTblProp.'authors' and jsoTblProp.'authors'[thisAuthor]
+          delete jsoTblProp.'authors'[thisAuthor]
+          update = true
+        if updateColAttrs
+          jsoTblProp = @updateTableIndices jsoTblProp, currTd, addOrDel
+          update = true
+        if tempStart.0 isnt start.0 and updateEvenOddBgColor
+          delete jsoTblProp.'rowAttrs'.'oddBgColor'
+          delete jsoTblProp.'rowAttrs'.'evenBgColor'
+          update = true
+        if update then @updateTblPropInAPool -1, -1, jsoTblProp, tempStart
+        tempStart.0 = tempStart.0 + 1
+    dt.updateTblPropInAPool = (row, td, jsoTblProp, start) ->
+      try
+        rep = @context.rep
+        editorInfo = @context.editorInfo
+        thisAuthor = editorInfo.ace_getAuthor!
+        authorInfos = editorInfo.ace_getAuthorInfos!
+        tblProps = void
+        jsoTblProp = @getLineTableProperty start.0 if typeof jsoTblProp is 'undefined' or not jsoTblProp?
+        if row isnt -1 and td isnt -1
+          jsoTblProp.'authors'[thisAuthor] = {
+            row: row
+            cell: td
+            colorId: authorInfos[thisAuthor].bgcolor
+          }
+        jsoStrTblProp = JSON.stringify jsoTblProp
+        attrStart = []
+        attrEnd = []
+        attrStart.0 = start.0
+        attrStart.1 = 0
+        attrEnd.0 = start.0
+        attrEnd.1 = (rep.lines.atIndex start.0).text.length
+        editorInfo.ace_performDocumentApplyAttributesToRange attrStart, attrEnd, [['tblProp', jsoStrTblProp]]
+      catch
+    dt.updateTblCellAuthor = (row, td, tblProperties, start, updateEvenOddBgColor) ->
+      try
+        @updateTblPropInAPool row, td, tblProperties, start
+        tempStart = []
+        tempStart.0 = start.0
+        tempStart.1 = start.1
+        @sanitizeTblProperties tempStart, updateEvenOddBgColor
+      catch
+    dt
+
+if typeof exports isnt 'undefined' then exports.Datatables = Datatables else null
diff --git a/static/js/datatables.js b/static/js/datatables.js
deleted file mode 100644
index 06f83f6..0000000
--- a/static/js/datatables.js
+++ /dev/null
@@ -1,1927 +0,0 @@
-var _ = require('ep_etherpad-lite/static/js/underscore');
-// CommonJS
-if (typeof (require) != 'undefined') {
-    if (typeof (Ace2Common) == 'undefined') {
-        Ace2Common = require('ep_etherpad-lite/static/js/ace2_common');
-    }
-    if (typeof (Changeset) == 'undefined') {
-        Changeset = require('ep_etherpad-lite/static/js/Changeset');
-    }
-}
-exports.aceInitInnerdocbodyHead = function (hook_name, args, cb) {
-    args.iframeHTML.push('<link rel="stylesheet" type="text/css" href="/static/plugins/ep_tables/static/css/dataTables.css"/>');
-}
-// Bind the event handler to the toolbar buttons
-exports.postAceInit = function (hook, context) {
-    $.createTableMenu = function (init) {
-        if (typeof (top.templatesMenu) != 'undefined') {
-            top.templatesMenu.hide();
-        }
-        if ($.tblContextMenu) {
-            $.alignMenu($.tblContextMenu, 'tbl-menu');
-            $.tblContextMenu.show();
-            return;
-        }
-
-        function showTblPropPanel() {
-            if (!$.tblPropDialog) {
-                $.tblPropDialog = new YAHOO.widget.Dialog("yui-tbl-prop-panel", {
-                    width: "600px",
-                    height: "450px",
-                    close: true,
-                    visible: false,
-                    zindex: 1001,
-                    constraintoviewport: true
-                });
-                $.tblPropDialog.setBody($.getTblPropertiesHTML());
-                $.tblPropDialog.render();
-                $.alignMenu($.tblPropDialog, this.id);
-                initTableProperties();
-            }
-            $.tblPropDialog.show();
-        }
-
-        function createColorPicker() {
-            handleColorPickerSubmit = function () {
-                colorPickerButtonClick($.oColorPicker.get('hex'));
-            }
-            handleDialogCancel = function () {
-                this.cancel();
-            }
-            $.oColorPickerDialog = new YAHOO.widget.Dialog("yui-picker-panel", {
-                width: "500px",
-                close: true,
-                visible: false,
-                zindex: 1002,
-                constraintoviewport: true,
-                buttons: [{
-                    text: "Exit",
-                    handler: this.handleDialogCancel
-                }]
-            });
-            $.oColorPickerDialog.renderEvent.subscribe(function () {
-                if (!$.oColorPicker) { //make sure that we haven't already created our Color Picker					
-                    createOColorPicker();
-                }
-            });
-            $.oColorPickerDialog.render();
-            $.oColorPickerDialog.show();
-
-            function createOColorPicker() {
-                $.oColorPicker = new YAHOO.widget.ColorPicker('color-picker-menu', {
-                    showhsvcontrols: false,
-                    showrgbcontrols: false,
-                    showwebsafe: false,
-                    showhexsummary: false,
-                    showhexcontrols: true,
-                    images: {
-                        PICKER_THUMB: "http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/picker_thumb.png",
-                        HUE_THUMB: "http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/hue_thumb.png"
-                    }
-                });
-                $.oColorPicker.on("rgbChange", colorPickerButtonClick);
-                $.colorPickerAligned = true;
-            }
-        }
-
-        function colorPickerButtonClick(sColor) {
-            if (typeof (sColor) == 'string' && sColor != null && sColor.indexOf("#") == -1) {
-                sColor = "#" + sColor;
-            } else if (typeof (sColor) == "object") {
-                sColor = this.get("hex") == null ? this.get("value") : "#" + this.get("hex");
-            }
-            var selParams = {
-                borderWidth: null,
-                tblPropertyChange: true
-            };
-            switch ($.tblfocusedProperty) {
-            case "tbl_border_color":
-                selParams.tblBorderColor = true;
-                selParams.attrName = "borderColor";
-                $.borderColorPickerButton.set("value", sColor);
-                $("#current-color").css("backgroundColor", sColor);
-                $("#current-color").innerHTML = "Current color is " + sColor;
-                break;
-            case 'tbl_cell_bg_color':
-                selParams.tblCellBgColor = true;
-                selParams.attrName = "bgColor";
-                $.cellBgColorPickerButton.set("value", sColor);
-                $("#current-cell-bg-color").css("backgroundColor", sColor);
-                $("#current-cell-bg-color").innerHTML = "Current color is " + sColor;
-                break;
-            case "tbl_even_row_bg_color":
-                selParams.tblEvenRowBgColor = true;
-                selParams.attrName = "evenBgColor";
-                $.evenRowBgColorPickerButton.set("value", sColor);
-                $("#even-row-bg-color").css("backgroundColor", sColor);
-                $("#even-row-bg-color").innerHTML = "Current color is " + sColor;
-                break;
-            case "tbl_odd_row_bg_color":
-                selParams.tblOddRowBgColor = true;
-                selParams.attrName = "oddBgColor";
-                $.oddRowBgColorPickerButton.set("value", sColor);
-                $("#odd-row-bg-color").css("backgroundColor", sColor);
-                $("#odd-row-bg-color").innerHTML = "Current color is " + sColor;
-                break;
-            case "tbl_single_row_bg_color":
-                selParams.tblSingleRowBgColor = true;
-                selParams.attrName = "bgColor";
-                $.singleRowBgColorPickerButton.set("value", sColor);
-                $("#single-row-bg-color").css("backgroundColor", sColor);
-                $("#single-row-bg-color").innerHTML = "Current color is " + sColor;
-                break;
-            case "tbl_single_col_bg_color":
-                selParams.tblSingleColBgColor = true;
-                selParams.attrName = "bgColor";
-                $.singleColBgColorPickerButton.set("value", sColor);
-                $("#single-col-bg-color").css("backgroundColor", sColor);
-                $("#single-col-bg-color").innerHTML = "Current color is " + sColor;
-                break;
-            }
-            selParams.attrValue = sColor;
-            context.ace.callWithAce(function (ace) {
-                ace.ace_doDatatableOptions(selParams);
-            }, 'tblOptions', true);
-        }
-        $.handleTableBorder = function (selectValue) {
-            var selParams = {
-                tblBorderWidth: true,
-                attrName: 'borderWidth',
-                attrValue: selectValue,
-                tblPropertyChange: true
-            };
-            context.ace.callWithAce(function (ace) {
-                ace.ace_doDatatableOptions(selParams);
-            }, 'tblOptions', true);
-        }
-        $.getTblPropertiesHTML = function () {
-            return "<span id='table_properties'><span class='tbl-prop-menu-header'></span><br><span id='tbl-prop-menu'class='tbl-prop-menu'>" + "<table class='left-tbl-props tbl-inline-block'>" + "<tr><td class='tbl-prop-label-td'><span class='tbl-prop-label' style='padding-top: 8px;'>Table border</span></td></tr>" + "<tr><td><span class='tbl-inline-block' id='tbl_border_color'>&nbsp;</span><span id='tbl_border_width'class='tbl-inline-block tbl_border_width'></span></td></tr>" + "<tr><td class='tbl-prop-label-td'><span class='tbl-prop-label'>Cell background color</span></td></tr><tr><td><span id='tbl_cell_bg_color'></td></tr><tr><td></span></td></tr>" + "<tr><td class='tbl-prop-label-td'><span class='tbl-prop-label'>Even/Odd Row background color</span></td></tr>" + "	<tr><td><span class='tbl-inline-block' id='tbl_even_row_bg_color'>Even  &nbsp;</span><span id='tbl_odd_row_bg_color' class='tbl-inline-block'>Odd</span></td></tr>" + "<tr><td class='tbl-prop-label-td'><span class='tbl-prop-label'>Single Row/Col background color</span></td></tr>" + "	<tr><td><span class='tbl-inline-block' id='tbl_single_row_bg_color'>Single Row  &nbsp;</span><span id='tbl_single_col_bg_color' class='tbl-inline-block'>Single Col</span></td></tr>" + "<tr><td class='tbl-prop-label-td'><span class='tbl-prop-label'>Row/Col alignment</span></td></tr>" + "	<tr><td><span class='tbl-inline-block' id='tbl_row_v_align'>Row align&nbsp;</span><span id='tbl_col_v_align' class='tbl-inline-block'>Col align</span></td></tr>" + "</table>" + "	<span class=' tbl-inline-block'>" + "		<span class='tbl-prop-label' style='padding-top: 8px;'>" + "Dimensions(Inches) " + "		</span>&nbsp;&nbsp;<span id='text_input_message'></span>" + "		<table class='tbl-prop-dim'>" + "			<tbody>" + "				<tr>" + "					<td>							" + "						<span class='tbl-prop-dim-label tbl-inline-block'>" + "							<label  >Table width</label>" + "						</span>" + "					</td>" + "					<td class='td-spacer'></td>" + "					<td>" + "						<span class=' tbl-inline-block'>" + "							<input id='tbl_width' type='text' size='4' class='text-input' >" + "						</span>" + "					</td>" + "				</tr>" + "				<tr>" + "					<td>							" + "						<span class='tbl-prop-dim-label tbl-inline-block'>" + "							<label  >Table height</label>" + "						</span>" + "					</td>" + "					<td class='td-spacer'></td>" + "					<td>" + "						<span class=' tbl-inline-block'>" + "							<input id='tbl_height' type='text' size='4' class='text-input' >" + "						</span>" + "					</td>" + "				</tr>" + "				<tr>" + "					<td>							" + "						<span class='tbl-prop-dim-label tbl-inline-block'>" + "							<label  >Column width</label>" + "						</span>" + "					</td>" + "					<td class='td-spacer'></td>" + "					<td>" + "						<span class=' tbl-inline-block'>" + "							<input id='tbl_col_width' type='text' size='4' class='text-input' >" + "						</span>" + "					</td>" + "				</tr>" + "				<tr>" + "					<td>	" + "						<span class='tbl-prop-dim-label tbl-inline-block'>" + "							<label  >Minimum row height</label>" + "						</span>" + "					</td>" + "					<td class='td-spacer'></td>" + "					<td>" + "						<span class=' tbl-inline-block'>" + "							<input id='tbl_row_height' type='text' size='4' class='text-input' >" + "						</span>" + "					</td>" + "				</tr>" + "				<tr>" + "					<td>" + "						<span class='tbl-prop-dim-label tbl-inline-block'>" + "							<label >Cell padding</label>" + "						</span>" + "					</td>" + "					<td class='td-spacer'></td>" + "					<td>" + "						<span class=' tbl-inline-block'>" + "							<input id='tbl_cell_padding' type='text' size='4' class='text-input'>" + "						</span>" + "					</td>" + "				</tr>" + "			</tbody>" + "		</table>" + "		<br> " + "		<span class='tbl-prop-label' style='padding-top: 8px;'>" + "			Fonts " + "		</span>" + "		<table class='tbl-prop-dim'>" + "				<tr>" + "					<td>" + "						<span class='tbl-prop-dim-label tbl-inline-block'>" + "							<label >Cell font size</label>" + "						</span>" + "					</td>" + "					<td class='select-font-spacer'></td>" + "					<td>" + "						<span class=' tbl-inline-block'>" + "							<input id='tbl_cell_font_size' type='text' size='4' class='text-input'>" + "						</span>" + "					</td>" + "				</tr>" + "			</tbody>" + "		</table>" + "	</span>" + "</span>" + "</span>" + "<span id='img_properties'>" + "<span class='tbl-prop-menu-header'></span><span id='img-prop-menu'class='tbl-prop-menu'>" + "<table class='left-tbl-props tbl-inline-block'>" + "		<caption><span class='tbl-prop-label' style='padding-top: 8px;'>" + "			Dimensions(Intches) " + "		</span></caption>" + "			<tbody>" + "				<tr>" + "					<td>							" + "						<span class='tbl-prop-dim-label tbl-inline-block'>" + "							<label  >Image width</label>" + "						</span>" + "					</td>" + "					<td class='td-spacer'></td>" + "					<td>" + "						<span class=' tbl-inline-block'>" + "							<input id='img_width' type='text' size='4' class='text-input' >" + "						</span>" + "					</td>" + "				</tr>" + "				<tr>" + "					<td>							" + "						<span class='tbl-prop-dim-label tbl-inline-block'>" + "							<label  >Image height</label>" + "						</span>" + "					</td>" + "					<td class='td-spacer'></td>" + "					<td>" + "						<span class=' tbl-inline-block'>" + "							<input id='img_height' type='text' size='4' class='text-input' >" + "						</span>" + "					</td>" + "				</tr>" + "</table>" + "</span>" + "</span>";
-        }
-        //initilizer
-        if (typeof ($.tblContextMenu) == 'undefined') {
-            var matrixTable = "<table id='matrix_table'class='matrix-table'><caption></caption>    <tr value=1><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=2 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=3 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=4><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=5 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=6><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=7><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=8><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=9><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=10><td height=10 value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr></table>";
-            $.tblContextMenu = new YAHOO.widget.ContextMenu("tbl_context_menu", {
-                iframe: true,
-                zindex: 500,
-                shadow: false,
-                position: "dynamic",
-                keepopen: true,
-                clicktohide: true
-            });
-            $.tblContextMenu.addItems([
-                [{
-                    text: "Insert Table",
-                    submenu: {
-                        id: 'tbl_insert',
-                        itemData: ["<div id='select_matrix'>0 X 0</div>"]
-                    }
-                }],
-                ["Insert Row Above", "Insert Row Below", "Insert Column Right", "Insert Column Left"],
-                ["Delete Row", "Delete Column", "Delete Table"],
-                [{
-                    id: 'tbl_prop_menu_item',
-                    text: "Table Properties",
-                    onclick: {
-                        fn: showTblPropPanel
-                    }
-                }]
-            ]);
-            var subMenus = $.tblContextMenu.getSubmenus();
-            subMenus[0].setFooter(matrixTable);
-            $.tblContextMenu.render(document.body);
-            $.alignMenu = function (menu, id, addX, addY, scrollY) {
-                var region = YAHOO.util.Dom.getRegion(id);
-                if (typeof (id) == 'string' && (id == 'tbl-menu' || id == 'upload_image_cont')) {
-                    menu.cfg.setProperty("xy", [region.left, region.bottom]);
-                } else if (typeof (id) == 'string') {
-                    menu.cfg.setProperty("xy", [region.right, region.top]);
-                } else {
-                    menu.cfg.setProperty("xy", [30 + addX, 36 + addY - scrollY]);
-                }
-            }
-            $('table td').hover(function () {
-                for (var x = 0; x <= $(this).index(); x++) {
-                    for (var y = 0; y <= $(this).parent().index(); y++) {
-                        $(this).parent().parent().children().eq(y).children().eq(x).addClass('selected');
-                    }
-                }
-            }, function () {
-                $('table td').removeClass('selected');
-            });
-            $('table td').hover(function () {
-                xVal = this.getAttribute('value')
-                yVal = $(this).closest("tr")[0].getAttribute("value");
-                $("#select_matrix").html(xVal + " X " + yVal);
-            });
-            $("td", "#matrix_table").click(function (e) {
-                context.ace.callWithAce(function (ace) {
-                    ace.ace_doDatatableOptions('addTbl', 'addTblX' + $("#select_matrix").text());
-                }, 'tblOptions', true);
-                return false;
-            });
-            $.tblContextMenu.subscribe("click", function (p_sType, p_aArgs) {
-                var oEvent = p_aArgs[0],
-                    oMenuItem = p_aArgs[1]; // YAHOO.widget.MenuItem instance
-                if (oMenuItem) {
-                    tblReq = oMenuItem.cfg.getProperty("text");
-                    disabled = oMenuItem.cfg.getProperty("disabled");
-                    if (disabled) return;
-                    var id = "";
-                    switch (tblReq) {
-                    case "Insert Table":
-                        id = 'addTbl';
-                        break;
-                    case "Insert Row Above":
-                        id = 'addTblRowA';
-                        break;
-                    case "Insert Row Below":
-                        id = 'addTblRowB';
-                        break;
-                    case "Insert Column Left":
-                        id = 'addTblColL';
-                        break;
-                    case "Insert Column Right":
-                        id = 'addTblColR';
-                        break;
-                    case "Delete Table":
-                        id = 'delTbl';
-                        break;
-                    case "Delete Image":
-                        id = 'delImg';
-                        break;
-                    case "Delete Row":
-                        id = 'delTblRow';
-                        break;
-                    case "Delete Column":
-                        id = 'delTblCol';
-                        break;
-                    }
-                    context.ace.callWithAce(function (ace) {
-                        ace.ace_doDatatableOptions(id);
-                    }, 'tblOptions', true);
-                    return false;
-                }
-            });
-
-            function initTableProperties() {
-                //tbl col horizontal align		
-                var colVAligns = ['Left', 'Center', 'Right'];
-                $.colVAlignsMenu = new YAHOO.widget.ContextMenu("tbl_col_v_align_menu", {
-                    iframe: true,
-                    zindex: 1003,
-                    shadow: false,
-                    position: "dynamic",
-                    keepopen: true,
-                    clicktohide: true
-                });
-                $.colVAlignsMenu.addItems(colVAligns);
-                $.colVAlignsMenu.render(document.body);
-                $.colVAlignsMenu.subscribe("click", function (p_sType, p_aArgs) {
-                    var oEvent = p_aArgs[0],
-                        oMenuItem = p_aArgs[1]; // YAHOO.widget.MenuItem instance
-                    if (oMenuItem) {
-                        align = oMenuItem.cfg.getProperty("text");
-                        var selParams = {
-                            tblColVAlign: true,
-                            attrName: 'colVAlign',
-                            attrValue: align,
-                            tblPropertyChange: true
-                        };
-                        $.colVAlignsMenuButton.set("value", selParams.attrValue);
-                        $("#current-col-v-alignment").html(align);
-                        context.ace.callWithAce(function (ace) {
-                            ace.ace_doDatatableOptions(selParams);
-                        }, 'tblOptions', true);
-                    }
-                });
-                $.colVAlignsMenuButton = new YAHOO.widget.Button({
-                    disabled: false,
-                    type: "split",
-                    label: "<em id=\"current-col-v-alignment\">Left</em>",
-                    container: "tbl_col_v_align"
-                });
-                $('#tbl_col_v_align').click(function () {
-                    var aligned = false;
-                    if (!aligned) {
-                        $.alignMenu($.colVAlignsMenu, 'tbl_col_v_align');
-                    }
-                    if ($.borderWidthsMenu) $.borderWidthsMenu.hide();
-                    if ($.oColorPickerDialog) $.oColorPickerDialog.hide();
-                    $.colVAlignsMenu.show();
-                    var vAlignValue = $.colVAlignsMenuButton.get("value");
-                    if (vAlignValue) {
-                        var selParams = {
-                            tblColVAlign: true,
-                            attrName: 'colVAlign',
-                            attrValue: vAlignValue,
-                            tblPropertyChange: true
-                        };
-                        context.ace.callWithAce(function (ace) {
-                            ace.ace_doDatatableOptions(selParams);
-                        }, 'tblOptions', true);
-                    }
-                });
-                //tbl row vertical align		
-                var rowVAligns = ['Top', 'Center', 'Bottom'];
-                $.rowVAlignsMenu = new YAHOO.widget.ContextMenu("tbl_row_v_align_menu", {
-                    iframe: true,
-                    zindex: 1003,
-                    shadow: false,
-                    position: "dynamic",
-                    keepopen: true,
-                    clicktohide: true
-                });
-                $.rowVAlignsMenu.addItems(rowVAligns);
-                $.rowVAlignsMenu.render(document.body);
-                $.rowVAlignsMenu.subscribe("click", function (p_sType, p_aArgs) {
-                    var oEvent = p_aArgs[0],
-                        oMenuItem = p_aArgs[1]; // YAHOO.widget.MenuItem instance
-                    if (oMenuItem) {
-                        align = oMenuItem.cfg.getProperty("text");
-                        var selParams = {
-                            tblRowVAlign: true,
-                            attrName: 'rowVAlign',
-                            attrValue: align,
-                            tblPropertyChange: true
-                        };
-                        $.rowVAlignsMenuButton.set("value", selParams.attrValue);
-                        $("#current-v-alignment").html(align);
-                        context.ace.callWithAce(function (ace) {
-                            ace.ace_doDatatableOptions(selParams);
-                        }, 'tblOptions', true);
-                    }
-                });
-                $.rowVAlignsMenuButton = new YAHOO.widget.Button({
-                    disabled: false,
-                    type: "split",
-                    label: "<em id=\"current-v-alignment\">Top</em>",
-                    container: "tbl_row_v_align"
-                });
-                $('#tbl_row_v_align').click(function () {
-                    var aligned = false;
-                    if (!aligned) {
-                        $.alignMenu($.rowVAlignsMenu, 'tbl_row_v_align');
-                    }
-                    if ($.borderWidthsMenu) $.borderWidthsMenu.hide();
-                    if ($.oColorPickerDialog) $.oColorPickerDialog.hide();
-                    $.rowVAlignsMenu.show();
-                    var vAlignValue = $.rowVAlignsMenuButton.get("value");
-                    if (vAlignValue) {
-                        var selParams = {
-                            tblRowVAlign: true,
-                            attrName: 'rowVAlign',
-                            attrValue: vAlignValue,
-                            tblPropertyChange: true
-                        };
-                        context.ace.callWithAce(function (ace) {
-                            ace.ace_doDatatableOptions(selParams);
-                        }, 'tblOptions', true);
-                    }
-                });
-                //tbl border width
-                var borderWidths = ['0px', '1px', '2px', '3px', '4px', '5px', '6px', '7px', '8px'];
-                $.borderWidthsMenu = new YAHOO.widget.ContextMenu("tbl_border_width_menu", {
-                    iframe: true,
-                    zindex: 1003,
-                    shadow: false,
-                    position: "dynamic",
-                    keepopen: true,
-                    clicktohide: true
-                });
-                $.borderWidthsMenu.addItems(borderWidths);
-                $.borderWidthsMenu.render(document.body);
-                $.borderWidthsMenu.subscribe("click", function (p_sType, p_aArgs) {
-                    var oEvent = p_aArgs[0],
-                        oMenuItem = p_aArgs[1]; // YAHOO.widget.MenuItem instance
-                    if (oMenuItem) {
-                        borderReq = oMenuItem.cfg.getProperty("text");
-                        var selParams = {
-                            tblBorderWidth: true,
-                            attrName: 'borderWidth',
-                            attrValue: borderReq.substring(0, borderReq.indexOf("px")),
-                            tblPropertyChange: true
-                        };
-                        $.borderWidthPickerButton.set("value", selParams.attrValue);
-                        $("#current-width").html(borderReq);
-                        context.ace.callWithAce(function (ace) {
-                            ace.ace_doDatatableOptions(selParams);
-                        }, 'tblOptions', true);
-                    }
-                });
-                $.borderWidthPickerButton = new YAHOO.widget.Button({
-                    disabled: false,
-                    type: "split",
-                    label: "<em id=\"current-width\">1px</em>",
-                    container: "tbl_border_width"
-                });
-                $('#tbl_border_width').click(function () {
-                    var aligned = false;
-                    if (!aligned) {
-                        $.alignMenu($.borderWidthsMenu, 'tbl_border_width');
-                    }
-                    if ($.oColorPickerDialog) $.oColorPickerDialog.hide();
-                    if ($.rowVAlignsMenu) $.rowVAlignsMenu.hide();
-                    $.borderWidthsMenu.show();
-                    var widthValue = $.borderWidthPickerButton.get("value");
-                    if (widthValue) {
-                        var selParams = {
-                            tblBorderWidth: true,
-                            attrName: 'borderWidth',
-                            attrValue: widthValue,
-                            tblPropertyChange: true
-                        };
-                        context.ace.callWithAce(function (ace) {
-                            ace.ace_doDatatableOptions(selParams);
-                        }, 'tblOptions', true);
-                    }
-                });
-                $.tblfocusedProperty = "";
-                $('#tbl_properties').click(function () {
-                    if (typeof ($.borderWidthsMenu) != 'undefined') $.borderWidthsMenu.hide();
-                    if (typeof ($.oColorPickerDialog) != 'undefined') $.oColorPickerDialog.hide();
-                    if (typeof ($.rowVAlignsMenu) != 'undefined') $.rowVAlignsMenu.hide();
-                });
-                $.colorPickerAligned = false;
-                $('#tbl_border_color').click(function () {
-                    if (!$.colorPickerAligned) {
-                        createColorPicker();
-                    }
-                    $.alignMenu($.oColorPickerDialog, 'tbl_border_color');
-                    $.tblfocusedProperty = "tbl_border_color";
-                    if ($.rowVAlignsMenu) $.rowVAlignsMenu.hide();
-                    if ($.borderWidthsMenu) $.borderWidthsMenu.hide();
-                    $.oColorPickerDialog.setHeader("Please choose a color for: Table Border color");
-                    $.oColorPickerDialog.show();
-                    var hexValue = $.borderColorPickerButton.get("value");
-                    if (hexValue) {
-                        colorPickerButtonClick(hexValue);
-                    }
-                });
-                $.borderColorPickerButton = new YAHOO.widget.Button({
-                    disabled: false,
-                    type: "split",
-                    label: "<em  class='color-picker-button' id=\"current-color\">Current color is #FFFFFF.</em>",
-                    container: "tbl_border_color"
-                });
-                //tbl cell bg color		
-                $.cellBgColorPickerButton = new YAHOO.widget.Button({
-                    disabled: false,
-                    type: "split",
-                    label: "<em class='color-picker-button' id=\"current-cell-bg-color\">Current color is #FFFFFF.</em>",
-                    container: "tbl_cell_bg_color"
-                });
-                $('#tbl_cell_bg_color').click(function () {
-                    if (!$.colorPickerAligned) {
-                        createColorPicker();
-                    }
-                    $.alignMenu($.oColorPickerDialog, 'tbl_cell_bg_color');
-                    $.tblfocusedProperty = "tbl_cell_bg_color";
-                    if ($.rowVAlignsMenu) $.rowVAlignsMenu.hide();
-                    if ($.borderWidthsMenu) $.borderWidthsMenu.hide();
-                    $.oColorPickerDialog.setHeader("Please choose a color for: Cell Background color");
-                    $.oColorPickerDialog.show();
-                    var hexValue = $.cellBgColorPickerButton.get("value");
-                    if (hexValue) {
-                        colorPickerButtonClick(hexValue);
-                    }
-                });
-                //tbl even rows bg color		
-                $.evenRowBgColorPickerButton = new YAHOO.widget.Button({
-                    disabled: false,
-                    type: "split",
-                    label: "<em class='color-picker-button' id=\"even-row-bg-color\">Current color is #FFFFFF.</em>",
-                    container: "tbl_even_row_bg_color"
-                });
-                $('#tbl_even_row_bg_color').click(function () {
-                    if (!$.colorPickerAligned) {
-                        createColorPicker();
-                    }
-                    $.alignMenu($.oColorPickerDialog, 'tbl_even_row_bg_color');
-                    $.tblfocusedProperty = "tbl_even_row_bg_color";
-                    if ($.borderWidthsMenu) $.borderWidthsMenu.hide();
-                    if ($.rowVAlignsMenu) $.rowVAlignsMenu.hide();
-                    $.oColorPickerDialog.setHeader("Please choose a color for: Even Row Background color");
-                    $.oColorPickerDialog.show();
-                    var hexValue = $.evenRowBgColorPickerButton.get("value");
-                    if (hexValue) {
-                        colorPickerButtonClick(hexValue);
-                    }
-                });
-                //tbl odd rows bg color		
-                $.oddRowBgColorPickerButton = new YAHOO.widget.Button({
-                    disabled: false,
-                    type: "split",
-                    label: "<em class='color-picker-button' id=\"odd-row-bg-color\">Current color is #FFFFFF.</em>",
-                    container: "tbl_odd_row_bg_color"
-                });
-                $('#tbl_odd_row_bg_color').click(function () {
-                    if (!$.colorPickerAligned) {
-                        createColorPicker();
-                    }
-                    $.alignMenu($.oColorPickerDialog, 'tbl_odd_row_bg_color');
-                    $.tblfocusedProperty = "tbl_odd_row_bg_color";
-                    if ($.rowVAlignsMenu) $.rowVAlignsMenu.hide();
-                    if ($.borderWidthsMenu) $.borderWidthsMenu.hide();
-                    $.oColorPickerDialog.setHeader("Please choose a color for: Odd Row Background color");
-                    $.oColorPickerDialog.show();
-                    var hexValue = $.oddRowBgColorPickerButton.get("value");
-                    if (hexValue) {
-                        colorPickerButtonClick(hexValue);
-                    }
-                });
-                //tbl single row bg color		
-                $.singleRowBgColorPickerButton = new YAHOO.widget.Button({
-                    disabled: false,
-                    type: "split",
-                    label: "<em class='color-picker-button' id=\"single-row-bg-color\">Current color is #FFFFFF.</em>",
-                    container: "tbl_single_row_bg_color"
-                });
-                $('#tbl_single_row_bg_color').click(function () {
-                    if (!$.colorPickerAligned) {
-                        createColorPicker();
-                    }
-                    $.alignMenu($.oColorPickerDialog, 'tbl_single_row_bg_color');
-                    $.tblfocusedProperty = "tbl_single_row_bg_color";
-                    if ($.borderWidthsMenu) $.borderWidthsMenu.hide();
-                    if ($.rowVAlignsMenu) $.rowVAlignsMenu.hide();
-                    $.oColorPickerDialog.setHeader("Please choose a color for: Single Row Background color");
-                    $.oColorPickerDialog.show();
-                    var hexValue = $.singleRowBgColorPickerButton.get("value");
-                    if (hexValue) {
-                        colorPickerButtonClick(hexValue);
-                    }
-                });
-                //tbl single col bg color		
-                $.singleColBgColorPickerButton = new YAHOO.widget.Button({
-                    disabled: false,
-                    type: "split",
-                    label: "<em class='color-picker-button' id=\"single-col-bg-color\">Current color is #FFFFFF.</em>",
-                    container: "tbl_single_col_bg_color"
-                });
-                $('#tbl_single_col_bg_color').click(function () {
-                    if (!$.colorPickerAligned) {
-                        createColorPicker();
-                    }
-                    $.alignMenu($.oColorPickerDialog, 'tbl_single_col_bg_color');
-                    $.tblfocusedProperty = "tbl_single_col_bg_color";
-                    if ($.rowVAlignsMenu) $.rowVAlignsMenu.hide();
-                    if ($.borderWidthsMenu) $.borderWidthsMenu.hide();
-                    $.oColorPickerDialog.setHeader("Please choose a color for: Single Column Background color");
-                    $.oColorPickerDialog.show();
-                    var hexValue = $.singleColBgColorPickerButton.get("value");
-                    if (hexValue) {
-                        colorPickerButtonClick(hexValue);
-                    }
-                });
-                //tbl property text inputs
-                $('.text-input').change(function () {
-                    var selParams = {
-                        tblPropertyChange: true
-                    };
-                    if (this.id == "tbl_width") {
-                        selParams.tblWidth = true;
-                        selParams.attrName = "width";
-                    } else if (this.id == "tbl_height") {
-                        selParams.tblHeight = true;
-                        selParams.attrName = "height";
-                    } else if (this.id == "tbl_col_width") {
-                        selParams.tblColWidth = true;
-                        selParams.attrName = "width";
-                    } else if (this.id == "tbl_row_height") {
-                        selParams.tblCellHeight = true;
-                        selParams.attrName = "height";
-                    } else if (this.id == "tbl_cell_padding") {
-                        selParams.tblCellPadding = true;
-                        selParams.attrName = "padding";
-                    } else if (this.id == "tbl_cell_font_size") {
-                        selParams.tblCellFontSize = true;
-                        selParams.attrName = "fontSize";
-                    } //image attrs
-                    else if (this.id == "img_width") {
-                        selParams.imgWidth = true;
-                        selParams.attrName = "width";
-                    } else if (this.id == "img_height") {
-                        selParams.imgHeight = true;
-                        selParams.attrName = "height";
-                    }
-                    selParams.attrValue = this.value;
-                    this.value = '';
-                    $('#text_input_message').text("Ok");
-                    $('#text_input_message').removeAttr('style');
-                    $('#text_input_message').fadeOut("slow");
-                    context.ace.callWithAce(function (ace) {
-                        ace.ace_doDatatableOptions(selParams);
-                    }, 'tblOptions', true);
-                });
-            }
-        }
-        if (!init) {
-            $.alignMenu($.tblContextMenu, 'tbl-menu');
-            $.tblContextMenu.show();
-        }
-    };
-    $('#tbl-menu').click($.createTableMenu);
-    YAHOO.util.Dom.addClass(document.body, 'yui-skin-sam');
-    $("body").append($('<div id="yui-picker-panel" class="yui-picker-panel">' + '<div class="hd">Please choose a color:</div>' + '<div class="bd">' + '	<div class="yui-picker" id="color-picker-menu"></div>' + '</div>' + '<div class="ft"></div>' + '</div>'));
-    $("body").append($('<div id="yui-tbl-prop-panel" class="yui-picker-panel">' + '<div class="hd">Table/Image Properties</div>' + '<div class="bd">' + '	<div class="yui-picker" id="tbl-props"></div>' + '</div>' + '<div class="ft"></div>' + '</div>'));
-    $.createTableMenu(true);
-};
-// Once ace is initialized, we set ace_doDatatableOptions and bind it to the context
-exports.aceInitialized = function (hook, context) {
-    var editorInfo = context.editorInfo;
-    editorInfo.ace_doDatatableOptions = _(Datatables.doDatatableOptions).bind(context);
-};
-exports.acePostWriteDomLineHTML = function (hook_name, args, cb) {
-    // Iterate through the child nodes (spans) and point SyntaxHighlighter at them
-    var children = args.node.children;
-    for (var i = 0; i < children.length; i++) {
-        if (args.node.children[i].className.indexOf("list") != -1 || args.node.children[i].className.indexOf("tag") != -1 || args.node.children[i].className.indexOf("url") != -1) continue;
-        var lineText = "";
-        if (args.node.children[i].innerText) lineText = args.node.children[i].innerText;
-        else lineText = args.node.children[i].textContent;
-        if (lineText && lineText.indexOf("data-tables") != -1) {
-            var dtAttrs = typeof (exports.Datatables) != 'undefined' ? exports.Datatables.attributes : null;
-            dtAttrs = dtAttrs || "";
-            DatatablesRenderer.render({}, args.node.children[i], dtAttrs);
-            exports.Datatables.attributes = null;
-        }
-    }
-}
-exports.eejsBlock_scripts = function (hook_name, args, cb) {
-    args.content = args.content + require('ep_etherpad-lite/node/eejs/').require("ep_tables/templates/datatablesScripts.ejs");
-}
-exports.eejsBlock_editbarMenuLeft = function (hook_name, args, cb) {
-    args.content = args.content + require('ep_etherpad-lite/node/eejs/').require("ep_tables/templates/datatablesEditbarButtons.ejs");
-}
-exports.eejsBlock_styles = function (hook_name, args, cb) {
-    args.content = require('ep_etherpad-lite/node/eejs/').require("ep_tables/templates/styles.ejs") + args.content;
-}
-// Our heading attribute will result in a heaading:h1... :h6 class
-exports.aceAttribsToClasses = function (hook, context) {
-    Datatables.attributes = null;
-    if (context.key == 'tblProp') {
-        Datatables.attributes = context.value;
-        return ['tblProp:' + context.value];
-    }
-}
-exports.aceStartLineAndCharForPoint = function (hook, context) {
-	var selStart = null;
-    try {
-        Datatables.context = context;
-        if (Datatables.isFocused()) {
-			selStart = Datatables.getLineAndCharForPoint();
-        }
-    } catch (error) {
-        top.console.log('error ' + error);
-        top.console.log('context rep' + Datatables.context.rep);
-    }
-    return selStart;
-};
-
-exports.aceEndLineAndCharForPoint = function (hook, context) {
-	var selEndLine = null;
-    try {
-        Datatables.context = context;
-        if (Datatables.isFocused()) {
-          selEndLine =   Datatables.getLineAndCharForPoint();
-        }
-    } catch (error) {
-        top.console.log('error ' + error);
-        top.console.log('context rep' + Datatables.context.rep);
-    }
-    return selEndLine;
-};
-exports.aceKeyEvent = function (hook, context) {
-
-	var specialHandled = false;
-    try {
-        Datatables.context = context;
-        if (Datatables.isFocused()) {
-            var evt = context.evt;
-            var type = evt.type;
-            var keyCode = evt.keyCode;
-            var isTypeForSpecialKey = ((Ace2Common.browser.msie || Ace2Common.browser.safari) ? (type == "keydown") : (type == "keypress"));
-            var isTypeForCmdKey = ((Ace2Common.browser.msie || Ace2Common.browser.safari) ? (type == "keydown") : (type == "keypress"));
-            var which = evt.which;
-            if ((!specialHandled) && isTypeForSpecialKey && keyCode == 9 && !(evt.metaKey || evt.ctrlKey)) {
-                context.editorInfo.ace_fastIncorp(5);
-                evt.preventDefault();
-                Datatables.performDocumentTableTabKey();
-                specialHandled = true;
-            }
-            if ((!specialHandled) && isTypeForSpecialKey && keyCode == 13) {
-                // return key, handle specially;
-                context.editorInfo.ace_fastIncorp(5);
-                evt.preventDefault();
-                Datatables.doReturnKey();
-                specialHandled = true;
-            }
-            if ((!specialHandled) && isTypeForSpecialKey && (keyCode == Datatables.vars.JS_KEY_CODE_DEL || keyCode == Datatables.vars.JS_KEY_CODE_BS || (String.fromCharCode(which).toLowerCase() == "h" && (evt.ctrlKey)))) {
-                context.editorInfo.ace_fastIncorp(20);
-                evt.preventDefault();
-                specialHandled = true;
-                if (Datatables.isCellDeleteOk(keyCode)) {
-                    Datatables.doDeleteKey();
-                }
-            }
-        }
-    } catch (error) {}
-    //console.log(' ace key evt specialHandled ',specialHandled);
-    return specialHandled;
-};
-if (typeof (Datatables) == 'undefined') var Datatables = function () {
-        // Get the text within an element
-        // Doesn't do any normalising, returns a string
-        // of text as found.
-        function nodeText(n) {
-            var text = [];
-            var self = arguments.callee;
-            var el, els = n.childNodes;
-            var excluded = {
-                'noscript': 'noscript',
-                'script': 'script',
-            };
-            for (var i = 0, iLen = els.length; i < iLen; i++) {
-                el = els[i];
-                // May need to add other node types here
-                if (el.nodeType == 1 && !(el.tagName.toLowerCase() in excluded)) {
-                    text.push(self(el));
-                    // If working with XML, add nodeType 4 to get text from CDATA nodes
-                } else if (el.nodeType == 3) {
-                    // Deal with extra whitespace and returns in text here.
-                    text.push(el.data);
-                }
-            }
-            return text.join('');
-        }
-        var dt = {
-            defaults: {
-                tblProps: {
-                    borderWidth: "1",
-                    cellAttrs: [],
-                    width: "6",
-                    rowAttrs: {},
-                    colAttrs: [],
-                    authors: {}
-                }
-            },
-            config: {},
-            /** Internal 'global' variables. */
-            vars: {
-                OVERHEAD_LEN_PRE: '{"payload":[["'.length,
-                OVERHEAD_LEN_MID: '","'.length,
-                OVERHEAD_LEN_ROW_START: '["'.length,
-                OVERHEAD_LEN_ROW_END: '"],'.length,
-                JS_KEY_CODE_BS: 8,
-                JS_KEY_CODE_DEL: 46,
-                TBL_OPTIONS: ['addTbl', 'addTblRowA', 'addTblRowB', 'addTblColL', 'addTblColR', 'delTbl', 'delTblRow', 'delTblCol', 'delImg']
-            },
-            /* passed parameters */
-            context: null
-        }; // end of dt
-        dt.isFocused = function () {
-            if (!this.context.rep.selStart || !this.context.rep.selEnd) return false;
-            var line = this.context.rep.lines.atIndex(this.context.rep.selStart[0]);
-            if (!line) return false;
-            var currLineText = line.text || '';
-            if (currLineText.indexOf("data-tables") == -1) {
-                return false;
-            }
-            return true;
-        };
-        /* Helper function. not meant to be used as a standalone function
-
-			   requires rowStartOffset
-
-			 */
-        dt._getRowEndOffset = function (rowStartOffset, tds) {
-            var rowEndOffset = rowStartOffset + this.vars.OVERHEAD_LEN_ROW_START;
-            for (var i = 0, len = tds.length; i < len; i++) {
-                var overHeadLen = this.vars.OVERHEAD_LEN_MID;
-                if (i == len - 1) {
-                    overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
-                }
-                rowEndOffset += tds[i].length + overHeadLen;
-            }
-            return rowEndOffset;
-        }
-        /**
-
-			current row index, 
-
-			td index ,
-
-			the length of leftover text of the current cell,
-
-			current row start offset,
-
-			current row end offset,
-
-			current td start offset,
-
-			current td end offset,
-
-			and cellCaretPos
-
-		*/
-        dt.getFocusedTdInfo = function (payload, colStart) {
-            var payloadOffset = colStart - this.vars.OVERHEAD_LEN_PRE;
-            var rowStartOffset = 0;
-            var payloadSum = 0;
-            for (var rIndex = 0, rLen = payload.length; rIndex < rLen; rIndex++) {
-                var tds = payload[rIndex];
-                for (var tIndex = 0, tLen = tds.length; tIndex < tLen; tIndex++) {
-                    var overHeadLen = this.vars.OVERHEAD_LEN_MID;
-                    if (tIndex == tLen - 1) {
-                        overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
-                    }
-                    payloadSum += tds[tIndex].length + overHeadLen;
-                    if (payloadSum >= payloadOffset) {
-                        if (payloadSum == payloadOffset) {
-                            tIndex++;
-                        }
-                        var leftOverTdTxtLen = payloadSum - payloadOffset == 0 ? payload[rIndex][tIndex].length + this.vars.OVERHEAD_LEN_MID : payloadSum - payloadOffset;
-                        var cellCaretPos = tds[tIndex].length - (leftOverTdTxtLen - overHeadLen);
-                        var rowEndOffset = this._getRowEndOffset(rowStartOffset, tds);
-                        return {
-                            row: rIndex,
-                            td: tIndex,
-                            leftOverTdTxtLen: leftOverTdTxtLen,
-                            rowStartOffset: rowStartOffset,
-                            rowEndOffset: rowEndOffset,
-                            cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
-                            cellEndOffset: payloadSum,
-                            cellCaretPos: cellCaretPos
-                        };
-                    }
-                }
-                rowStartOffset = payloadSum;
-                payloadSum += this.vars.OVERHEAD_LEN_ROW_START;
-            }
-        };
-        dt.printCaretPos = function (start, end) {
-            top.console.log(JSON.stringify(start));
-            top.console.log(JSON.stringify(end));
-        };
-        dt.doDatatableOptions = function (cmd, xByY) {
-            Datatables.context = this; // the scope is still ep lite and not DataTables because of the binding we have to do in  exports.aceInitialized
-            if ((typeof (cmd) == 'object' && cmd.tblPropertyChange)) {
-                Datatables.updateTableProperties(cmd);
-            } else {
-                switch (cmd) {
-                case Datatables.vars.TBL_OPTIONS[0]:
-                    Datatables.addTable(xByY);
-                    break;
-                case Datatables.vars.TBL_OPTIONS[1]:
-                    Datatables.insertTblRow("addA");
-                    break;
-                case Datatables.vars.TBL_OPTIONS[2]:
-                    Datatables.insertTblRow("addB");
-                    break;
-                case Datatables.vars.TBL_OPTIONS[3]:
-                    Datatables.insertTblColumn("addL");
-                    break;
-                case Datatables.vars.TBL_OPTIONS[4]:
-                    Datatables.insertTblColumn("addR");
-                    break;
-                case Datatables.vars.TBL_OPTIONS[5]:
-                    Datatables.deleteTable();
-                    break;
-                case Datatables.vars.TBL_OPTIONS[6]:
-                    Datatables.deleteTblRow();
-                    break;
-                case Datatables.vars.TBL_OPTIONS[7]:
-                    Datatables.deleteTblColumn();
-                    break;
-                }
-            }
-        };
-        dt.addTable = function (tableObj) {
-            var rep = this.context.rep;
-            var start = rep.selStart;
-            var end = rep.selEnd;
-            var line = rep.lines.atIndex(rep.selStart[0]);
-            var hasMoreRows = null;
-            var isRowAddition = null;
-            if (tableObj) {
-                hasMoreRows = tableObj.hasMoreRows;
-                isRowAddition = tableObj.isRowAddition;
-            }
-            if (isRowAddition) {
-                var table = JSON.parse(tableObj.tblString);
-                insertTblRowBelow(0, table);
-                performDocApplyTblAttrToRow(rep.selStart, JSON.stringify(table.tblProperties));
-                return;
-            }
-            //if the carret is within a table, add the new table at the bottom
-            if (line) {
-                var currLineText = line.text;
-                if (currLineText.indexOf("data-tables") != -1) {
-                    do {
-                        rep.selStart[0] = rep.selStart[0] + 1
-                        currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-                    } while (currLineText.indexOf("data-tables") != -1);
-                    rep.selEnd[1] = rep.selStart[1] = currLineText.length;
-                    this.context.editorInfo.ace_doReturnKey();
-                    this.context.editorInfo.ace_doReturnKey();
-                } else {
-                    rep.selEnd[1] = rep.selStart[1] = currLineText.length;
-                    this.context.editorInfo.ace_doReturnKey();
-                    //				this.context.editorInfo.ace_inCallStackIfNecessary ('newline',this.context.editorInfo.ace_doReturnKey);	
-                }
-            }
-            //if no col/row specified, create a default 3X3  empty table
-            if (tableObj == null) {
-                var authors = {};
-                this.insertTblRowBelow(3);
-                this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
-                this.insertTblRowBelow(3);
-                this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
-                this.insertTblRowBelow(3);
-                this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
-                this.context.editorInfo.ace_doReturnKey();
-                //this.context.editorInfo.ace_inCallStackIfNecessary ('newline',this.context.editorInfo.ace_doReturnKey);	
-                this.updateAuthorAndCaretPos(rep.selStart[0] - 3);
-                return;
-            }
-            //xbyy cols and rows have been specified or an actual payload object is present, for the former, create x rows of magicdom lines that contain a row
-            //per table.
-            xByYSelect = typeof (tableObj) == "object" ? null : tableObj.split("X");
-            if (xByYSelect != null && xByYSelect.length == 3) {
-                var cols = parseInt(xByYSelect[1]);
-                var rows = parseInt(xByYSelect[2]);
-                var jsoStrTblProp = JSON.stringify(this.createDefaultTblProperties());
-                var authors = {};
-                for (var i = 0; i < rows; i++) {
-                    this.insertTblRowBelow(cols);
-                    if (i == 0) {
-                        this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
-                    } else {
-                        this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
-                    }
-                }
-                this.updateAuthorAndCaretPos(rep.selStart[0] - rows + 1);
-                return;
-            }
-            return newText;
-        };
-        //insert a row
-        dt.insertTblRow = function (aboveOrBelow) {
-            var func = 'insertTblRow()';
-            var rep = this.context.rep;
-            try {
-                var newText = "";
-                var currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-                var payload = JSON.parse(currLineText).payload;
-                var currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-                var currRow = currTdInfo.row;
-                var lastRowOffSet = 0;
-                var start = [],
-                    end = [];
-                start[0] = rep.selStart[0], start[1] = rep.selStart[1];
-                end[0] = rep.selStart[0], end[1] = rep.selStart[1];
-                if (aboveOrBelow == 'addA') {
-                    rep.selStart[0] = rep.selEnd[0] = rep.selStart[0] - 1;
-                    this.insertTblRowBelow(payload[0].length);
-                } else { //below curr row ( aboveOrBelow = 'addB')
-                    this.insertTblRowBelow(payload[0].length);
-                }
-                this.context.editorInfo.ace_performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
-                this.updateAuthorAndCaretPos(rep.selStart[0]);
-                var updateEvenOddBgColor = true;
-                this.sanitizeTblProperties(rep.selStart, updateEvenOddBgColor);
-            } catch (error) {
-                //domline.createErrorState(start,end,'insertTblRow',rep.lines.atIndex(rep.selStart[0]).text,rep.selStart,rep.selEnd,newText,error);		
-            }
-        };
-        //delete a table, also removes table overhead
-        dt.deleteTable = function () {
-            var rep = this.context.rep;
-            var func = 'deleteTable()';
-            var start = rep.seStart;
-            var end = rep.seEnd;
-            try {
-                var line = rep.selStart[0] - 1;
-                var numOfLinesAbove = 0;
-                var numOfLinesBelow = 0;
-                while (rep.lines.atIndex(line).text.indexOf('data-tables') != -1) { //count num of rows above current pos
-                    numOfLinesAbove++;
-                    line--;
-                }
-                line = rep.selEnd[0] + 1;
-                while (rep.lines.atIndex(line).text.indexOf('data-tables') != -1) { //count num of rows below current pos		
-                    numOfLinesBelow++;
-                    line++;
-                }
-                rep.selStart[1] = 0;
-                rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
-                rep.selEnd[0] = rep.selEnd[0] + numOfLinesBelow;
-                rep.selEnd[1] = rep.lines.atIndex(rep.selEnd[0]).text.length;
-                this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, "");
-            } catch (error) {
-                //domline.createErrorState(start,end,func,rep.lines.atIndex(rep.selStart[0]).text,rep.selStart,rep.selEnd,"",error);		
-            }
-        };
-        //delete a row
-        dt.deleteTblRow = function () {
-            var func = 'deleteTblRow()';
-            var rep = this.context.rep;
-            try {
-                var currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-                if (currLineText.indexOf('data-tables') == -1) return;
-                rep.selEnd[0] = rep.selStart[0] + 1;
-                rep.selStart[1] = 0;
-                rep.selEnd[1] = 0;
-                this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, "");
-                currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-                if (currLineText.indexOf('data-tables') == -1) return;
-                this.updateAuthorAndCaretPos(rep.selStart[0], 0, 0);
-                updateEvenOddBgColor = true;
-                this.sanitizeTblProperties(rep.selStart, updateEvenOddBgColor);
-            } catch (error) {
-                //domline.createErrorState(start,end,'deleteTblRow',rep.lines.atIndex(rep.selStart[0]).text,rep.selStart,rep.selEnd,"",error);		
-            }
-        };
-        dt.updateTableProperties = function (props) {
-            var rep = this.context.rep;
-            var currTd = null;
-            if (props.tblColWidth || props.tblSingleColBgColor || props.tblColVAlign) {
-                var currLine = rep.lines.atIndex(rep.selStart[0]);
-                var currLineText = currLine.text;
-                var tblJSONObj = JSON.parse(currLineText);
-                var payload = tblJSONObj.payload;
-                var currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-                currTd = currTdInfo.td;
-            }
-            if (props.tblWidth || props.tblHeight || props.tblBorderWidth || props.tblBorderColor || props.tblColWidth || props.tblSingleColBgColor || props.tblEvenRowBgColor || props.tblOddRowBgColor || props.tblColVAlign) {
-                var start = [];
-                start[0] = rep.selStart[0], start[1] = rep.selStart[1];
-                var numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
-                var tempStart = [];
-                tempStart[0] = start[0] - numOfLinesAbove;
-                tempStart[1] = start[1];
-                while (tempStart[0] < rep.lines.length() && rep.lines.atIndex(tempStart[0]).text.indexOf('data-tables') != -1) { //start from top of a table			
-                    if (props.tblEvenRowBgColor && tempStart[0] % 2 != 0) {
-                        tempStart[0] = tempStart[0] + 1;
-                        continue;
-                    } else if (props.tblOddRowBgColor && tempStart[0] % 2 == 0) {
-                        tempStart[0] = tempStart[0] + 1;
-                        continue;
-                    }
-                    this.updateTablePropertiesHelper(props, tempStart, currTd);
-                    tempStart[0] = tempStart[0] + 1;
-                }
-            } else {
-                var start = [];
-                start[0] = rep.selStart[0];
-                start[1] = rep.selStart[1];
-                this.updateTablePropertiesHelper(props, start, currTd);
-            }
-        };
-        dt.addCellAttr = function (start, tblJSONObj, tblProperties, attrName, attrValue) {
-            var rep = this.context.rep;
-            var payload = tblJSONObj.payload;
-            var currTdInfo = this.getFocusedTdInfo(payload, start[1]);
-            var currRow = currTdInfo.row;
-            var currTd = currTdInfo.td;
-            var cellAttrs = tblProperties.cellAttrs;
-            var row = cellAttrs[currRow];
-            if (row == null || typeof (row) == 'undefined') {
-                row = [];
-            }
-            cell = row[currTd];
-            if (cell == null || typeof (cell) == 'undefined') {
-                cell = {};
-            }
-            //toggle these attributes
-            if (attrName == 'fontWeight' || attrName == 'fontStyle' || attrName == 'textDecoration') {
-                if (cell[attrName] == attrValue) {
-                    attrValue = '';
-                }
-            } else if (cell[attrName] == attrValue) return false; //other wise no need to update
-            cell[attrName] = attrValue;
-            row[currTd] = cell;
-            cellAttrs[currRow] = row;
-            tblProperties.cellAttrs = cellAttrs;
-            return tblProperties;
-        };
-        //returns false if no chanage to tblProperties
-        dt.addRowAttr = function (tblJSONObj, tblProperties, attrName, attrValue) {
-            var rep = this.context.rep;
-            var rowAttrs = tblProperties.rowAttrs;
-            if (attrName == 'bgColor') { //specific single row property
-                var payload = tblJSONObj.payload;
-                var currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-                var currRow = currTdInfo.row;
-                var singleRowAttrs = rowAttrs.singleRowAttrs;
-                if (singleRowAttrs == null || typeof (singleRowAttrs) == 'undefined') {
-                    singleRowAttrs = [];
-                }
-                if (singleRowAttrs[currRow] == null || typeof (singleRowAttrs[currRow]) == 'undefined') {
-                    singleRowAttrs[currRow] = {};
-                } else if (singleRowAttrs[currRow][attrName] == attrValue) {
-                    return false;
-                }
-                singleRowAttrs[currRow][attrName] = attrValue;
-                rowAttrs.singleRowAttrs = singleRowAttrs;
-            } else { //even-odd rows properties,rowAlign			
-                if (rowAttrs[attrName] == attrValue) return false;
-                rowAttrs[attrName] = attrValue;
-            }
-            tblProperties.rowAttrs = rowAttrs;
-            return tblProperties;
-        };
-        //returns false if no chanage to tblProperties
-        dt.addColumnAttr = function (start, tblJSONObj, tblProperties, attrName, attrValue, currTd) {
-            var payload = tblJSONObj.payload;
-            var currTdInfo = this.getFocusedTdInfo(payload, start[1]);
-            var colAttrs = tblProperties.colAttrs;
-            if (colAttrs == null || typeof (colAttrs) == 'undefined') {
-                colAttrs = [];
-            }
-            if (colAttrs[currTd] == null || typeof (colAttrs[currTd]) == 'undefined') {
-                colAttrs[currTd] = {};
-            } else if (colAttrs[currTd][attrName] == attrValue) {
-                return false;
-            }
-            colAttrs[currTd][attrName] = attrValue;
-            tblProperties.colAttrs = colAttrs;
-            return tblProperties;
-        };
-        dt.updateTablePropertiesHelper = function (props, start, currTd) {
-            var rep = this.context.rep;
-            lastTblPropertyUsed = 'updateTableProperties';
-            start = start || rep.selStart;
-            if (!(start)) return;
-            var currLine = rep.lines.atIndex(start[0]);
-            var currLineText = currLine.text;
-            if (currLineText.indexOf('data-tables') == -1) return true;
-            try {
-                var tblJSONObj = JSON.parse(currLineText);
-                var tblProperties = this.getLineTableProperty(start[0]);
-                var update = false;
-                //table width , height , border width and tbl  color	
-                if (props.tblWidth || props.tblHeight || props.tblBorderWidth || props.tblBorderColor) {
-                    var currAttrValue = tblProperties[props.attrName];
-                    if (props.attrValue != null && (typeof (currAttrValue) == 'undefined' || currAttrValue != props.attrValue)) {
-                        tblProperties[props.attrName] = props.attrValue;
-                        update = true;
-                    }
-                }
-                /*
-
-			set or unset table cells attrs
-
-			bold , italic , line-through/underline;
-
-			*/
-                if (props.tblCellFontWeight || props.tblCellFontStyle || props.tblCellTextDecoration) {
-                    var tblProps = this.addCellAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue);
-                    if (tblProps) {
-                        tblProperties = tblProps;
-                        update = true;
-                    }
-                }
-                //cell background color, height, and padding, cell font size		
-                if (props.tblCellFontSize || props.tblCellBgColor || props.tblCellHeight || props.tblCellPadding || props.tblcellVAlign) {
-                    var tblProps = this.addCellAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue);
-                    if (tblProps) {
-                        tblProperties = tblProps;
-                        update = true;
-                    }
-                }
-                //even/odd row background color		
-                if (props.tblEvenRowBgColor || props.tblOddRowBgColor) {
-                    var tblProps = this.addRowAttr(tblJSONObj, tblProperties, props.attrName, props.attrValue);
-                    if (tblProps) {
-                        tblProperties = tblProps;
-                        update = true;
-                    }
-                }
-                //single row background color, rowVAlign		
-                if (props.tblSingleRowBgColor || props.tblRowVAlign) {
-                    var tblProps = this.addRowAttr(tblJSONObj, tblProperties, props.attrName, props.attrValue);
-                    if (tblProps) {
-                        tblProperties = tblProps;
-                        update = true;
-                    }
-                }
-                // col width, col bgColor, colVAlign
-                if (props.tblColWidth || props.tblSingleColBgColor || props.tblColVAlign) {
-                    var tblProps = this.addColumnAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue, currTd);
-                    if (tblProps) {
-                        tblProperties = tblProps;
-                        update = true;
-                    }
-                }
-                //only update if there is a change
-                if (update) {
-                    this.updateTblPropInAPool(-1, -1, tblProperties, start);
-                }
-            } catch (error) {
-                // domline.createErrorState(start,end,'updateTableProperties',rep.lines.atIndex(rep.selStart[0]).text,rep.selStart,rep.selEnd,"",error);	
-            }
-        };
-        dt.updateAuthorAndCaretPos = function (magicDomLineNum, tblRowNum, tblColNum) {
-            var rep = this.context.rep;
-            rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
-            rep.selStart[0] = rep.selEnd[0] = magicDomLineNum;
-            var row = typeof (tblRowNum) == 'undefined' || tblRowNum == null ? 0 : tblRowNum;
-            var col = typeof (tblColNum) == 'undefined' || tblRowNum == null ? 0 : tblColNum;
-            this.updateTblPropInAPool(row, col, null, rep.selStart);
-            rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
-            this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
-        }
-        dt.insertTblRowBelow = function (numOfRows, table) {
-            var rep = this.rep;
-            var currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-            var payload = [
-                []
-            ];
-            if (!numOfRows && numOfRows != 0) {
-                var tblPayload = JSON.parse(currLineText).payload;
-                numOfRows = tblPayload[0].length;
-            }
-            var tblRows = new Array(numOfRows);
-            if (numOfRows != 0) {
-                for (var i = 0; i < tblRows.length; i++) {
-                    tblRows[i] = " ";
-                }
-            }
-            payload = [tblRows];
-            if (table) {
-                payload = table.payload;
-            }
-            tableObj = {
-                "payload": payload,
-                "tblId": 1,
-                "tblClass": "data-tables",
-                "trClass": "alst",
-                "tdClass": "hide-el"
-            }
-            rep.selEnd[1] = rep.selStart[1] = currLineText.length;
-            this.context.editorInfo.ace_doReturnKey();
-            this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, JSON.stringify(tableObj));
-        };
-        dt.createDefaultTblProperties = function (authors) {
-            var rep = this.context.rep;
-            var defTblProp = {
-                borderWidth: "1",
-                cellAttrs: [],
-                width: "6",
-                rowAttrs: {},
-                colAttrs: [],
-                authors: {}
-            };
-            if (authors) {
-                defTblProp['authors'] = authors;
-            }
-            //from existing Table tableborder,tbl_border_width,table_width and table_height		
-            var prevLine = rep.lines.atIndex(rep.selEnd[0] - 1);
-            var jsoTblProp = null;
-            if (prevLine) {
-                var prevLineText = prevLine.text;
-                if (prevLineText.indexOf("data-tables") != -1) {
-                    jsoTblProp = this.getLineTableProperty(rep.selStart[0] - 1);
-                }
-            }
-            if (!jsoTblProp) {
-                var nextLine = rep.lines.atIndex(rep.selEnd[0] - 1);
-                if (nextLine) {
-                    var nextLineText = nextLine.text;
-                    if (nextLineText.indexOf("data-tables") != -1) {
-                        jsoTblProp = this.getLineTableProperty(rep.selStart[0] + 1);
-                    }
-                }
-            }
-            if (jsoTblProp) {
-                defTblProp.borderWidth = jsoTblProp.borderWidth;
-                defTblProp.borderColor = jsoTblProp.borderColor;
-                defTblProp.width = jsoTblProp.width;
-                defTblProp.height = jsoTblProp.height;
-                defTblProp.colAttrs = jsoTblProp.colAttrs;
-            }
-            var jsoStrTblProp = JSON.stringify(defTblProp);
-            return jsoStrTblProp;
-        }
-        dt.performDocApplyTblAttrToRow = function (start, jsoStrTblProp) {
-            var tempStart = [],
-                tempEnd = [];
-            tempStart[0] = start[0], tempEnd[0] = start[0];
-            tempStart[1] = 0, tempEnd[1] = this.context.rep.lines.atIndex(start[0]).text.length;
-            this.context.editorInfo.ace_performDocumentApplyAttributesToRange(tempStart, tempEnd, [
-                ["tblProp", jsoStrTblProp]
-            ]);
-        }
-        /* handles tab key within a table */
-        dt.performDocumentTableTabKey = function () {
-            try {
-                var context = this.context;
-                var rep = context.rep;
-                var currLine = rep.lines.atIndex(rep.selStart[0]);
-                var currLineText = currLine.text;
-                var tblJSONObj = JSON.parse(currLineText);
-                var payload = tblJSONObj.payload;
-                var currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-                var leftOverTdTxtLen = currTdInfo.leftOverTdTxtLen;
-                var currRow = currTdInfo.row;
-                var currTd = currTdInfo.td;
-                if (typeof (payload[currRow][currTd + 1]) == "undefined") { //next row
-                    currRow += 1;
-                    var nextLine = rep.lines.atIndex(rep.selStart[0] + 1);
-                    var nextLineText = nextLine.text;
-                    var updateEvenOddBgColor = false;
-                    if (nextLineText == null || nextLineText == '' || nextLineText.indexOf('data-tables') == -1) { //create new row and move caret to this new row			
-                        this.insertTblRowBelow(null, null);
-                        this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
-                        rep.selEnd[1] = rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE;
-                        updateEvenOddBgColor = true;
-                    } else { //just move caret to existing next row
-                        currTd = -1;
-                        rep.selStart[0] = rep.selEnd[0] = rep.selStart[0] + 1;
-                        var tblJSONObj = JSON.parse(nextLineText);
-                        var payload = tblJSONObj.payload;
-                        leftOverTdTxtLen = payload[0][0].length;
-                        rep.selEnd[1] = rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE + leftOverTdTxtLen;
-                    }
-                    context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, "");
-                    var start = [];
-                    start[0] = rep.selStart[0];
-                    start[1] = rep.selStart[1];
-                    dt.updateTblCellAuthor(0, 0, null, start, updateEvenOddBgColor); //this requires removing potential user color in a differnt row(although it should only check the previous row)					   
-                } else { //tab to the next col and update cell user color
-                    var nextTdTxtLen = typeof (payload[currRow]) == 'undefined' ? -leftOverTdTxtLen : payload[currRow][currTd + 1].length;
-                    payload = tblJSONObj.payload;
-                    rep.selStart[1] = rep.selEnd[1] = rep.selEnd[1] + nextTdTxtLen + leftOverTdTxtLen;
-                    context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, "");
-                    // debugger;
-                    dt.updateTblPropInAPool(currRow, currTd + 1, null, rep.selStart); //this need not to update entire table of color setting		
-                }
-            } catch (error) {}
-        };
-        dt.getTdInfo = function (payload, tdIndex) {
-            var rep = this.context.rep;
-            var startOffset = this.vars.OVERHEAD_LEN_PRE;
-            var rowStartOffset = startOffset;
-            var payloadSum = startOffset;
-            var tds = payload[0];
-            for (var tIndex = 0, tLen = tds.length; tIndex < tLen; tIndex++) {
-                var overHeadLen = this.vars.OVERHEAD_LEN_MID;
-                if (tIndex == tLen - 1) {
-                    overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
-                }
-                payloadSum += tds[tIndex].length + overHeadLen;
-                if (tIndex >= tdIndex) {
-                    return {
-                        cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
-                        cellEndOffset: payloadSum
-                    }
-                }
-            }
-        };
-        dt.getNextTdInfo = function (payload, currTdInfo) {
-            var rep = this.context.rep;
-            var startOffset = currTdInfo.rowEndOffset;
-            var rowStartOffset = startOffset;
-            var payloadSum = startOffset;
-            var tds = payload[currTdInfo.row];
-            for (var tIndex = 0, tLen = tds.length; tIndex < tLen; tIndex++) {
-                var overHeadLen = this.vars.OVERHEAD_LEN_MID;
-                if (tIndex == tLen - 1) {
-                    overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
-                }
-                payloadSum += tds[tIndex].length + overHeadLen;
-                if (tIndex >= currTdInfo.td) {
-                    var leftOverTdTxtLen = payloadSum - startOffset == 0 ? payload[currTdInfo.row + 1][tIndex].length + this.vars.OVERHEAD_LEN_MID : payloadSum - startOffset;
-                    var rowEndOffset = this._getRowEndOffset(rowStartOffset, tds);
-                    var tdInfo = {
-                        row: currTdInfo.row + 1,
-                        td: tIndex,
-                        leftOverTdTxtLen: leftOverTdTxtLen,
-                        rowStartOffset: rowStartOffset,
-                        rowEndOffset: rowEndOffset,
-                        cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
-                        cellEndOffset: payloadSum
-                    };
-                    return tdInfo;
-                }
-            }
-        };
-        //insert a column.
-        dt.insertTblColumn = function (leftOrRight, start, end) {
-            var rep = this.context.rep;
-            var func = 'insertTblColumn()';
-            try {
-                var currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-                var tblJSONObj = JSON.parse(currLineText);
-                var payload = tblJSONObj.payload;
-                var currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-                var currTd = currTdInfo.td;
-                start = [], end = [];
-                start[0] = rep.selStart[0];
-                start[1] = rep.selStart[1];
-                end[0] = rep.selEnd[0];
-                end[1] = rep.selEnd[1];
-                if (leftOrRight == "addL") {
-                    currTd -= 1;
-                }
-                var numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
-                rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
-                while (rep.selStart[0] < rep.lines.length() && rep.lines.atIndex(rep.selStart[0]).text.indexOf('data-tables') != -1) { //count num of rows above current pos
-                    var currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-                    var tblJSONObj = JSON.parse(currLineText);
-                    var payload = tblJSONObj.payload;
-                    var cellPos = this.getTdInfo(payload, currTd).cellEndOffset;
-                    var newText = '" ",';
-                    if (currTd == payload[0].length - 1) { //add to the most right
-                        rep.selStart[1] = rep.selEnd[1] = cellPos - this.vars.OVERHEAD_LEN_ROW_END + 1;
-                        newText = '," "';
-                    } else if (currTd == -1) { //add to most left
-                        rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE - 1;
-                    } else {
-                        rep.selStart[1] = rep.selEnd[1] = cellPos - 1;
-                    }
-                    this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, newText);
-                    rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] + 1;
-                }
-                rep.selStart = start;
-                rep.selEnd = end;
-                if (leftOrRight == "addL") {
-                    rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
-                    rep.selStart[0] = rep.selEnd[0] = rep.selStart[0];
-                    this.updateTblPropInAPool(0, 0, null, rep.selStart);
-                    rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
-                }
-                currTd++;
-                var updateEvenOddBgColor = false;
-                var updateColAttrs = true;
-                this.sanitizeTblProperties(start, updateEvenOddBgColor, updateColAttrs, currTd, "add")
-                this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, "");
-            } catch (error) {
-                //domline.createErrorState(start,end,'insertTblColumn',rep.lines.atIndex(rep.selStart[0]).text,rep.selStart,rep.selEnd,"",error);
-            }
-        };
-        dt.deleteTblColumn = function () {
-            var func = 'deleteTblColumn()';
-            var rep = this.context.rep;
-            try {
-                var currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-                var tblJSONObj = JSON.parse(currLineText);
-                var payload = tblJSONObj.payload;
-                if (payload[0].length == 1) {
-                    deleteTable();
-                }
-                var currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-                var currTd = currTdInfo.td;
-                var start = [],
-                    end = [];
-                start[0] = rep.selStart[0];
-                start[1] = rep.selStart[1];
-                end[0] = rep.selEnd[0];
-                end[1] = rep.selEnd[1];
-                var numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
-                rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
-                while (rep.selStart[0] < rep.lines.length() && rep.lines.atIndex(rep.selStart[0]).text.indexOf('data-tables') != -1) { //count num of rows above current pos
-                    var currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-                    var tblJSONObj = JSON.parse(currLineText);
-                    var payload = tblJSONObj.payload;
-                    var cellTdInfo = this.getTdInfo(payload, currTd);
-                    var newText = '" ",';
-                    if (currTd == payload[0].length - 1) { //remove most right col				
-                        rep.selStart[1] = cellTdInfo.cellStartOffset - 2;
-                        rep.selEnd[1] = cellTdInfo.cellEndOffset - 2;
-                    } else if (currTd == 0) { //remove most left col
-                        rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE - 1;
-                        rep.selEnd[1] = cellTdInfo.cellEndOffset - 1;
-                    } else {
-                        rep.selStart[1] = cellTdInfo.cellStartOffset - 1
-                        rep.selEnd[1] = cellTdInfo.cellEndOffset - 1;
-                    }
-                    this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, "");
-                    rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] + 1;
-                }
-                rep.selStart = start;
-                rep.selEnd = end;
-                var updateEvenOddBgColor = false;
-                var updateColAttrs = true;
-                this.sanitizeTblProperties(start, updateEvenOddBgColor, updateColAttrs, currTd, "del")
-                this.updateAuthorAndCaretPos(rep.selStart[0], 0, 0);
-            } catch (error) {
-                //domline.createErrorState(start,end,'deleteTblColumn',rep.lines.atIndex(rep.selStart[0]).text,rep.selStart,rep.selEnd,"",error);
-            }
-        }
-        dt.insertTblRowBelow = function (numOfRows, table) {
-            var context = this.context;
-            var rep = context.rep;
-            var currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-            var payload = [
-                []
-            ];
-            if (!numOfRows && numOfRows != 0) {
-                var tblPayload = JSON.parse(currLineText).payload;
-                numOfRows = tblPayload[0].length;
-            }
-            var tblRows = new Array(numOfRows);
-            if (numOfRows != 0) {
-                for (var i = 0; i < tblRows.length; i++) {
-                    tblRows[i] = " ";
-                }
-            }
-            payload = [tblRows];
-            if (table) {
-                payload = table.payload;
-            }
-            tableObj = {
-                "payload": payload,
-                "tblId": 1,
-                "tblClass": "data-tables",
-                "trClass": "alst",
-                "tdClass": "hide-el"
-            }
-            rep.selEnd[1] = rep.selStart[1] = currLineText.length;
-            this.context.editorInfo.ace_inCallStackIfNecessary('newline', this.context.editorInfo.ace_doReturnKey);
-            context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, JSON.stringify(tableObj));
-        };
-        dt.doReturnKey = function () {
-            var context = this.context;
-            var rep = context.rep;
-            var start = rep.seStart;
-            var end = rep.selEnd;
-            lastTblPropertyUsed = 'doTableReturnKey';
-            var currLine = rep.lines.atIndex(rep.selStart[0]);
-            var currLineText = currLine.text;
-            if (currLineText.indexOf('data-tables') == -1) return false;
-            else {
-                var func = 'doTableReturnKey()';
-                try {
-                    var currCarretPos = rep.selStart[1];
-                    if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) == '","') return true;
-                    else if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) == '","') return true;
-                    else if (currCarretPos < this.vars.OVERHEAD_LEN_PRE) return true;
-                    else if (currCarretPos > currLineText.length) return true;
-                    var start = rep.selStart,
-                        end = rep.selEnd;
-                    newText = " /r/n ";
-                    start[1] = currCarretPos;
-                    end[1] = currCarretPos;
-                    try {
-                        var jsonObj = JSON.parse(currLineText.substring(0, start[1]) + newText + currLineText.substring(start[1]));
-                        payloadStr = JSON.stringify(jsonObj.payload);
-                        if (currCarretPos > payloadStr.length + this.vars.OVERHEAD_LEN_PRE - 2) {
-                            return true;
-                        }
-                    } catch (error) {
-                        return true;
-                    }
-                    context.editorInfo.ace_performDocumentReplaceRange(start, end, newText);
-                } catch (error) {}
-                return true;
-            }
-        };
-        dt.isCellDeleteOk = function (keyCode) {
-            var context = this.context;
-            var rep = context.rep;
-            var start = rep.selStart;
-            var end = rep.selEnd;
-            var currLine = rep.lines.atIndex(rep.selStart[0]);
-            var currLineText = currLine.text;
-            if (currLineText.indexOf('data-tables') == -1) return true;
-            var isDeleteAccepted = false;
-            try {
-                var tblJSONObj = JSON.parse(currLineText);
-                var table = tblJSONObj.payload;
-                var currTdInfo = this.getFocusedTdInfo(table, rep.selStart[1]);
-                cellEntryLen = table[currTdInfo.row][currTdInfo.td].length;
-                var currCarretPos = rep.selStart[1];
-                if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) == '","') return false;
-                else if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) == '","') return false;
-                switch (keyCode) {
-                case this.vars.JS_KEY_CODE_BS:
-                    if (cellEntryLen != 0 && cellEntryLen > (currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID)) {
-                        isDeleteAccepted = true;
-                    }
-                    break;
-                case this.vars.JS_KEY_CODE_DEL:
-                    return false; //disabled for the moment				
-                    if (cellEntryLen != 0 && currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID > 0) {
-                        isDeleteAccepted = true;
-                    }
-                    break;
-                default:
-                    // cntrl H		 
-                    if (cellEntryLen != 0 && cellEntryLen > (currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID)) {
-                        isDeleteAccepted = true;
-                    }
-                    break;
-                }
-            } catch (error) {
-                isDeleteAccepted = false;
-            }
-            return isDeleteAccepted;
-        };
-        dt.nodeTextPlain = function (n) {
-            return n.innerText || n.textContent || n.nodeValue || '';
-        }
-        // Get the text within an element
-        // Doesn't do any normalising, returns a string
-        // of text as found.
-        dt.toString = function () {
-            return "ep_tables";
-        };
-        dt.getLineAndCharForPoint = function () {
-            var context = this.context;
-            var point = context.point;
-            var root = context.root;
-            // Turn DOM node selection into [line,char] selection.
-            // This method has to work when the DOM is not pristine,
-            // assuming the point is not in a dirty node.
-            if (point.node == root) {
-                if (point.index == 0) {
-                    return [0, 0];                    
-                } else {
-                    var N = this.context.rep.lines.length();
-                    var ln = this.context.rep.lines.atIndex(N - 1);                    
-                    return [N - 1, ln.text.length];
-                }
-            } else {
-                var n = point.node;
-                var col = 0;
-                // if this part fails, it probably means the selection node
-                // was dirty, and we didn't see it when collecting dirty nodes.
-                if (nodeText(n) || point.index > 0) {
-                    col = point.index;
-                }
-                var parNode, prevSib;
-                while ((parNode = n.parentNode) != root) {
-                    if ((prevSib = n.previousSibling)) {
-                        n = prevSib;
-                        var textLen = nodeText(n).length == 0 ? this.nodeTextPlain(n).length : nodeText(n).length;
-                        col += textLen;
-                    } else {
-                        n = parNode;
-                    }
-                }
-                if (n.id == "") console.debug("BAD");
-                if (n.firstChild && context.editorInfo.ace_isBlockElement(n.firstChild)) {
-                    col += 1; // lineMarker
-                }
-                var lineEntry = this.context.rep.lines.atKey(n.id);
-                var lineNum = this.context.rep.lines.indexOfEntry(lineEntry);
-                return [lineNum, col];
-            }
-        };
-        dt.doDeleteKey = function () {
-            var context = this.context;
-            var evt = context.evt || {};
-            var handled = false;
-            var rep = this.context.rep;
-            var editorInfo = context.editorInfo;
-            if (rep.selStart) {
-                //end tbl-mod-by-wlos
-                if (editorInfo.ace_isCaret()) {
-                    var lineNum = editorInfo.ace_caretLine();
-                    var col = editorInfo.ace_caretColumn();
-                    var lineEntry = rep.lines.atIndex(lineNum);
-                    var lineText = lineEntry.text;
-                    var lineMarker = lineEntry.lineMarker;
-                    if (/^ +$/.exec(lineText.substring(lineMarker, col))) {
-                        var col2 = col - lineMarker;
-                        var tabSize = ''.length; // zero for now, tabs are not supported within tables
-                        var toDelete = ((col2 - 1) % tabSize) + 1;
-                        editorInfo.ace_performDocumentReplaceRange([lineNum, col - toDelete], [lineNum, col], '');
-                        //scrollSelectionIntoView();
-                        handled = true;
-                    }
-                }
-                if (!handled) {
-                    if (editorInfo.ace_isCaret()) {
-                        var theLine = editorInfo.ace_caretLine();
-                        var lineEntry = rep.lines.atIndex(theLine);
-                        if (editorInfo.ace_caretColumn() <= lineEntry.lineMarker) {
-                            // delete at beginning of line
-                            var action = 'delete_newline';
-                            var prevLineListType = (theLine > 0 ? editorInfo.ace_getLineListType(theLine - 1) : '');
-                            var thisLineListType = editorInfo.ace_getLineListType(theLine);
-                            var prevLineEntry = (theLine > 0 && rep.lines.atIndex(theLine - 1));
-                            var prevLineBlank = (prevLineEntry && prevLineEntry.text.length == prevLineEntry.lineMarker);
-                            if (thisLineListType) {
-                                // this line is a list
-                                if (prevLineBlank && !prevLineListType) {
-                                    // previous line is blank, remove it
-                                    editorInfo.ace_performDocumentReplaceRange([theLine - 1, prevLineEntry.text.length], [theLine, 0], '');
-                                } else {
-                                    // delistify
-                                    editorInfo.ace_performDocumentReplaceRange([theLine, 0], [theLine, lineEntry.lineMarker], '');
-                                }
-                            } else if (theLine > 0) {
-                                // remove newline
-                                editorInfo.ace_performDocumentReplaceRange([theLine - 1, prevLineEntry.text.length], [theLine, 0], '');
-                            }
-                        } else {
-                            var docChar = editorInfo.ace_caretDocChar();
-                            if (docChar > 0) {
-                                if (evt.metaKey || evt.ctrlKey || evt.altKey) {
-                                    // delete as many unicode "letters or digits" in a row as possible;
-                                    // always delete one char, delete further even if that first char
-                                    // isn't actually a word char.
-                                    var deleteBackTo = docChar - 1;
-                                    while (deleteBackTo > lineEntry.lineMarker && editorInfo.ace_isWordChar(rep.alltext.charAt(deleteBackTo - 1))) {
-                                        deleteBackTo--;
-                                    }
-                                    editorInfo.ace_performDocumentReplaceCharRange(deleteBackTo, docChar, '');
-                                } else {
-                                    var returnKeyWitinTblOffset = 0;
-                                    if (lineText.substring(col - 5, col) == '/r/n ') {
-                                        returnKeyWitinTblOffset = 4;
-                                    }
-                                    // normal or table return key delete
-                                    editorInfo.ace_performDocumentReplaceCharRange(docChar - 1 - returnKeyWitinTblOffset, docChar, '');
-                                }
-                            }
-                        }
-                    } else {
-                        editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, "");
-                    }
-                }
-            }
-            //if the list has been removed, it is necessary to renumber
-            //starting from the *next* line because the list may have been
-            //separated. If it returns null, it means that the list was not cut, try
-            //from the current one.
-            var line = editorInfo.ace_caretLine();
-            if (line != -1 && editorInfo.ace_renumberList(line + 1) === null) {
-                editorInfo.ace_renumberList(line);
-            }
-        };
-        dt.getLineTableProperty = function (lineNum) {
-            var rep = this.context.rep;
-            // get "tblProp" attribute of first char of line
-            var aline = rep.alines[lineNum];
-            if (aline) {
-                var opIter = Changeset.opIterator(aline);
-                if (opIter.hasNext()) {
-                    var tblJSString = Changeset.opAttributeValue(opIter.next(), 'tblProp', rep.apool);
-                    try {
-                        return JSON.parse(tblJSString);
-                    } catch (error) {
-                        return this.defaults.tblProps;
-                    }
-                }
-            }
-            return this.defaults.tblProps;
-        };
-        dt.updateTblPropInAPool = function (row, td, jsoTblProp, start) {
-            try {
-                var rep = this.context.rep;
-                var tblProps;
-                var editorInfo = this.context.editorInfo;
-                var thisAuthor = editorInfo.ace_getAuthor();
-                var authorInfos = editorInfo.ace_getAuthorInfos();
-                if (typeof (jsoTblProp) == 'undefined' || jsoTblProp == null) {
-                    jsoTblProp = this.getLineTableProperty(start[0]);
-                }
-                if (row != -1 && td != -1) {
-                    jsoTblProp['authors'][thisAuthor] = {
-                        row: row,
-                        cell: td,
-                        colorId: authorInfos[thisAuthor].bgcolor
-                    };
-                }
-                var jsoStrTblProp = JSON.stringify(jsoTblProp);
-                var attrStart = [],
-                    attrEnd = [];
-                attrStart[0] = start[0], attrStart[1] = 0;
-                attrEnd[0] = start[0], attrEnd[1] = rep.lines.atIndex(start[0]).text.length;
-                editorInfo.ace_performDocumentApplyAttributesToRange(attrStart, attrEnd, [
-                    ["tblProp", jsoStrTblProp]
-                ]);
-            } catch (error) {
-                //createErrorState(start, start, 'updateTblPropInAPool', rep.lines.atIndex(start[0]).text, [row,td], [row,td], "", error);
-            }
-        };
-        dt.getCurrTblOddEvenRowBgColor = function (startRowNum, currRowNum) {
-            var rowBgColors = {
-                oddBgColor: null,
-                evenBgColor: null
-            };
-            if (startRowNum != currRowNum) {
-                var jsoTblProp1 = this.getLineTableProperty(startRowNum);
-                var jsoTblProp2 = this.getLineTableProperty(startRowNum + 1);
-                rowBgColors.evenBgColor = jsoTblProp1['rowAttrs']['evenBgColor'] || jsoTblProp2['rowAttrs']['evenBgColor'];
-                rowBgColors.oddBgColor = jsoTblProp1['rowAttrs']['oddBgColor'] || jsoTblProp2['rowAttrs']['oddBgColor'];
-            }
-            return rowBgColors;
-        };
-        dt.getTblAboveRowsFromCurFocus = function (start) {
-            var rep = this.context.rep;
-            var numOfLinesAbove = 0;
-            var line = start[0] - 1;
-            while (rep.lines.atIndex(line).text.indexOf('data-tables') != -1) { //count num of rows above current pos
-                numOfLinesAbove++;
-                line--;
-            }
-            return numOfLinesAbove;
-        }
-        dt.updateTableIndices = function (tblProperties, currTd, addOrDel) {
-            cellAttrs = tblProperties.cellAttrs;
-            for (var rIndex = 0, rLen = cellAttrs.length; rIndex < rLen; rIndex++) {
-                var cellAttr = cellAttrs[rIndex];
-                if (addOrDel == 'add') { //insert column            
-                    if (cellAttr) {
-                        cellAttr.splice(currTd, 0, null);
-                    }
-                } else { //remove column            
-                    if (cellAttr) {
-                        cellAttr.splice(currTd, 1);
-                    }
-                }
-            }
-            //col attrs 
-            colAttrs = tblProperties.colAttrs;
-            if (addOrDel == 'add') { //insert column
-                if (colAttrs) {
-                    colAttrs.splice(currTd, 0, null);
-                }
-            } else { //remove column
-                if (colAttrs) {
-                    colAttrs.splice(currTd, 1);
-                }
-            }
-            return tblProperties;
-        };
-        dt.sanitizeTblProperties = function (start, updateEvenOddBgColor, updateColAttrs, currTd, addOrDel) {
-            var rep = this.context.rep;
-            var editorInfo = this.context.editorInfo;
-            var thisAuthor = editorInfo.ace_getAuthor();
-            var numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
-            var tempStart = [];
-            tempStart[0] = start[0] - numOfLinesAbove;
-            var evenOddRowBgColors = {};
-            if (updateEvenOddBgColor) {
-                //evenOddRowBgColors=getCurrTblOddEvenRowBgColor(tempStart[0],start[0]);
-            }
-            while (tempStart[0] < rep.lines.length() && rep.lines.atIndex(tempStart[0]).text.indexOf('data-tables') != -1) { //start from top of a table						
-                var jsoTblProp = this.getLineTableProperty(tempStart[0]);
-                var update = false;
-                if (tempStart[0] != start[0] && jsoTblProp['authors'] && jsoTblProp['authors'][thisAuthor]) {
-                    delete jsoTblProp['authors'][thisAuthor];
-                    update = true;
-                }
-                if (updateColAttrs) {
-                    jsoTblProp = this.updateTableIndices(jsoTblProp, currTd, addOrDel);
-                    update = true;
-                }
-                if (tempStart[0] != start[0] && updateEvenOddBgColor) {
-                    delete jsoTblProp['rowAttrs']['oddBgColor'];
-                    delete jsoTblProp['rowAttrs']['evenBgColor'];
-                    update = true;
-                }
-                if (update) {
-                    this.updateTblPropInAPool(-1, -1, jsoTblProp, tempStart);
-                }
-                tempStart[0] = tempStart[0] + 1;
-            }
-        };
-        dt.updateTblPropInAPool = function (row, td, jsoTblProp, start) {
-            try {
-                var rep = this.context.rep;
-                var editorInfo = this.context.editorInfo;
-                var thisAuthor = editorInfo.ace_getAuthor();
-                var authorInfos = editorInfo.ace_getAuthorInfos();
-                var tblProps;
-                if (typeof (jsoTblProp) == 'undefined' || jsoTblProp == null) {
-                    jsoTblProp = this.getLineTableProperty(start[0]);
-                }
-                if (row != -1 && td != -1) {
-                    jsoTblProp['authors'][thisAuthor] = {
-                        row: row,
-                        cell: td,
-                        colorId: authorInfos[thisAuthor].bgcolor
-                    };
-                }
-                var jsoStrTblProp = JSON.stringify(jsoTblProp);
-                var attrStart = [],
-                    attrEnd = [];
-                attrStart[0] = start[0], attrStart[1] = 0;
-                attrEnd[0] = start[0], attrEnd[1] = rep.lines.atIndex(start[0]).text.length;
-                editorInfo.ace_performDocumentApplyAttributesToRange(attrStart, attrEnd, [
-                    ["tblProp", jsoStrTblProp]
-                ]);
-            } catch (error) {
-                //createErrorState(start, start, 'updateTblPropInAPool', rep.lines.atIndex(start[0]).text, [row,td], [row,td], "", error);
-            }
-        };
-        dt.updateTblCellAuthor = function (row, td, tblProperties, start, updateEvenOddBgColor) {
-            try {
-                this.updateTblPropInAPool(row, td, tblProperties, start);
-                var tempStart = [];
-                tempStart[0] = start[0];
-                tempStart[1] = start[1];
-                this.sanitizeTblProperties(tempStart, updateEvenOddBgColor);
-            } catch (error) {
-                //createErrorState(start, end, 'updateTblCellAuthor', rep.lines.atIndex(start).text, rep.selStart, rep.selEnd, "", error);
-            }
-        }
-        return dt;
-    }(); // end of anonymous function
-typeof (exports) != 'undefined' ? exports.Datatables = Datatables : null;

From 169963bf535e454d55363c6a75b91cc35ce8e37b Mon Sep 17 00:00:00 2001
From: Audrey Tang <audreyt@audreyt.org>
Date: Tue, 30 Oct 2012 15:28:47 +0800
Subject: [PATCH 02/36] * package.ls

---
 package.json |  7 +++++--
 package.ls   | 29 +++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+), 2 deletions(-)
 create mode 100644 package.ls

diff --git a/package.json b/package.json
index 1d613d4..375f62b 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,9 @@
 {
   "author": {
-    "name": ["Gedion Woldeselassie","Tenzin Tsetan"],
+    "name": [
+      "Gedion Woldeselassie",
+      "Tenzin Tsetan"
+    ],
     "email": "gwy321@gmail.com"
   },
   "name": "ep_tables",
@@ -11,7 +14,7 @@
     "url": "git://github.com/gedion/ep_tables.git"
   },
   "scripts": {
-      "prepublish": "./node_modules/.bin/livescript -bc -o static/js src/js"
+    "prepublish": "./node_modules/.bin/livescript -j package.ls > package.tmp &&\nmv package.tmp package.json &&\n./node_modules/.bin/livescript -bc -o static/js src/js"
   },
   "engines": {
     "node": "*"
diff --git a/package.ls b/package.ls
new file mode 100644
index 0000000..1500bbb
--- /dev/null
+++ b/package.ls
@@ -0,0 +1,29 @@
+author:
+  name: ['Gedion Woldeselassie', 'Tenzin Tsetan']
+  email: 'gwy321@gmail.com'
+name: 'ep_tables'
+description: 'Adds tables to etherpad-lite'
+version: '0.1.1'
+repository:
+  type: 'git'
+  url: 'git://github.com/gedion/ep_tables.git'
+scripts:
+  prepublish: """
+    ./node_modules/.bin/livescript -j package.ls > package.tmp &&
+    mv package.tmp package.json &&
+    ./node_modules/.bin/livescript -bc -o static/js src/js
+  """
+engines: {node: '*'}
+dependencies: {}
+devDependencies:
+  LiveScript: \1.1.x
+optionalDependencies: {}
+_id: 'ep_tables@0.1.1'
+_engineSupported: true
+_npmVersion: '1.1.24'
+_nodeVersion: 'v0.6.16'
+_defaultsLoaded: true
+_from: 'ep_tables'
+_npmUser:
+  name: \gedion
+  email: \gwy321@gmail.com

From e7d81bfcd93018d688e3ec4d9369ddf575038342 Mon Sep 17 00:00:00 2001
From: Audrey Tang <audreyt@audreyt.org>
Date: Tue, 30 Oct 2012 15:29:52 +0800
Subject: [PATCH 03/36] * Do not emit npm-local package.ls

---
 package.json | 12 +-----------
 package.ls   |  9 ---------
 2 files changed, 1 insertion(+), 20 deletions(-)

diff --git a/package.json b/package.json
index 375f62b..56bbcdf 100644
--- a/package.json
+++ b/package.json
@@ -23,15 +23,5 @@
   "devDependencies": {
     "LiveScript": "1.1.x"
   },
-  "optionalDependencies": {},
-  "_id": "ep_tables@0.1.1",
-  "_engineSupported": true,
-  "_npmVersion": "1.1.24",
-  "_nodeVersion": "v0.6.16",
-  "_defaultsLoaded": true,
-  "_from": "ep_tables",
-  "_npmUser": {
-    "name": "gedion",
-    "email": "gwy321@gmail.com"
-  }
+  "optionalDependencies": {}
 }
diff --git a/package.ls b/package.ls
index 1500bbb..8cee5ba 100644
--- a/package.ls
+++ b/package.ls
@@ -18,12 +18,3 @@ dependencies: {}
 devDependencies:
   LiveScript: \1.1.x
 optionalDependencies: {}
-_id: 'ep_tables@0.1.1'
-_engineSupported: true
-_npmVersion: '1.1.24'
-_nodeVersion: 'v0.6.16'
-_defaultsLoaded: true
-_from: 'ep_tables'
-_npmUser:
-  name: \gedion
-  email: \gwy321@gmail.com

From 8bfa8b53afa8ae944039e653fcc397d60814bbfb Mon Sep 17 00:00:00 2001
From: Audrey Tang <audreyt@audreyt.org>
Date: Tue, 30 Oct 2012 15:34:41 +0800
Subject: [PATCH 04/36] * Convert everything to livescript

---
 src/js/contentcollector.ls       |  31 +++
 src/js/datatables-renderer.ls    | 154 +++++++++++
 src/js/linestylefilter.ls        |   5 +
 static/js/contentcollector.js    |  78 +++---
 static/js/datatables-renderer.js | 437 ++++++++++++++++++-------------
 static/js/linestylefilter.js     |  17 +-
 6 files changed, 492 insertions(+), 230 deletions(-)
 create mode 100644 src/js/contentcollector.ls
 create mode 100644 src/js/datatables-renderer.ls
 create mode 100644 src/js/linestylefilter.ls

diff --git a/src/js/contentcollector.ls b/src/js/contentcollector.ls
new file mode 100644
index 0000000..93db74c
--- /dev/null
+++ b/src/js/contentcollector.ls
@@ -0,0 +1,31 @@
+exports.collectContentLineBreak = (hook, context) ->
+  tvalue = context.tvalue
+  breakLine = true
+  breakLine = false if tvalue and tvalue is 'tblBreak'
+  breakLine
+
+exports.collectContentLineText = (hook, context) ->
+  n = context.node
+  txt = context.text
+  if txt
+    while n
+      if n.tagName is 'TD'
+        elementName = n.getAttribute 'name'
+        if elementName is 'tData'
+          txt = txt.replace //\\//g, '|'
+          txt = txt.replace //"//g, '\''
+          break
+        else
+          if elementName is 'delimCell'
+            txt = '","'
+            break
+          else
+            if elementName is 'payload'
+              txt = '{"payload":[["'
+              break
+            else
+              if elementName is 'bracketAndcomma'
+                txt = '"]],"tblId":"1","tblClass":"data-tables"}'
+                break
+      n = n.parentNode
+  txt
\ No newline at end of file
diff --git a/src/js/datatables-renderer.ls b/src/js/datatables-renderer.ls
new file mode 100644
index 0000000..f0154c8
--- /dev/null
+++ b/src/js/datatables-renderer.ls
@@ -0,0 +1,154 @@
+if typeof DatatablesRenderer is 'undefined'
+  DatatablesRenderer = do ->
+    dRenderer = {render: (params, element, attributes) ->
+      renderer = new DatatablesRenderer.Renderer
+      if element.innerText then code = element.innerText else code = element.textContent
+      element.innerHTML = renderer.getHtml code, attributes}
+    dRenderer.Renderer = ->
+    dRenderer.Renderer.prototype = {
+      createDefaultTblProperties: (authors) ->
+        {
+          borderWidth: '1'
+          cellAttrs: []
+          width: '6'
+          rowAttrs: {}
+          colAttrs: []
+          authors: {}
+        }
+      buildTabularData: (tblJSONObj, tblPropsJSString) ->
+        htmlTbl = ''
+        tblId = tblJSONObj.tblId
+        tblClass = tblJSONObj.tblClass
+        tdClass = tblJSONObj.tdClass
+        trClass = tblJSONObj.trClass
+        payload = tblJSONObj.payload
+        tblProperties = {}
+        try
+          tblProperties = JSON.parse tblPropsJSString
+        catch error
+          tblProperties = @createDefaultTblProperties!
+        rowAttrs = tblProperties.rowAttrs
+        singleRowAttrs = rowAttrs.singleRowAttrs
+        cellAttrs = tblProperties.cellAttrs
+        colAttrs = tblProperties.colAttrs
+        tblWidth = if typeof tblProperties is 'undefined' or not tblProperties? then '1' else tblProperties.width or '1'
+        tblWidth = @getAttrInInch tblWidth
+        tblHeight = if typeof tblProperties is 'undefined' or not tblProperties? then '.1' else tblProperties.height or '.1'
+        tblHeight = @getAttrInInch tblHeight
+        tblBorderWidth = if typeof tblProperties is 'undefined' or not tblProperties? then 0 else tblProperties.borderWidth or 0
+        tblBorderColor = if typeof tblProperties is 'undefined' or not tblProperties? then '#000000' else tblProperties.borderColor or '#000000'
+        currRow = tblProperties.currRowAuthorIdx
+        currCell = tblProperties.currCellAuthorIdx
+        authors = tblProperties.authors
+        printViewTBlStyles = 'table-layout:fixed !important;border-collapse:collapse!important;font-family:Trebuchet MS!important;'
+        printViewTblTDStyles = 'font-size: 1em!important;line-height: 1em!important;padding: 3px 7px 2px!important;word-wrap: break-word!important;'
+        htmlTbl = '<table class=\'' + tblClass + '\' style=\'' + printViewTBlStyles + 'background-color:white;width:' + tblWidth + 'px!important;height:' + tblHeight + 'px!important; border-top: ' + tblBorderWidth + 'px solid ' + tblBorderColor + '!important;' + '\'><tbody>'
+        borders = 'border-bottom:' + tblBorderWidth + 'px solid ' + tblBorderColor
+        rowVAlign = if typeof rowAttrs is 'undefined' or not rowAttrs? then 'left' else rowAttrs.rowVAlign or 'left'
+        rows = tblJSONObj.payload
+        evenRowBgColor = if typeof rowAttrs is 'undefined' or not rowAttrs? then '#FFFFFF' else rowAttrs.evenBgColor or '#FFFFFF'
+        oddRowBgColor = if typeof rowAttrs is 'undefined' or not rowAttrs? then null else rowAttrs.oddBgColor or null
+        j = 0
+        rl = rows.length
+        while j < rl
+          tds = rows[j]
+          rowBgColor = oddRowBgColor
+          rowBgColor = evenRowBgColor if not rowBgColor
+          htmlTbl += '<tr style=\'vertical-align:' + rowVAlign + ';background-color:' + rowBgColor + '; ' + borders + '!important;\' class=\'' + trClass + '\'>'
+          preHeader = ''
+          if j is 0 then preHeader = '{"payload":[["'
+          htmlTbl += '<td  name=\'payload\' class=\'hide-el overhead\'>' + preHeader + '</td>'
+          singleRowAttr = if typeof singleRowAttrs is 'undefined' or not singleRowAttrs? then null else singleRowAttrs[j]
+          i = 0
+          tl = tds.length
+          while i < tl
+            cellAttr = if typeof cellAttrs[j] is 'undefined' or not cellAttrs[j]? then null else cellAttrs[j][i]
+            cellStyles = @getCellAttrs singleRowAttr, cellAttr, colAttrs[i], authors, i, j
+            authorBorderColor = (@getCellAuthorColors authors, i, j, tblBorderWidth) + '!important;'
+            borderTop = ''
+            borderTop = ' border-top: 0px solid white !important;' if tblBorderWidth is 0
+            colVAlign = if typeof colAttrs[i] is 'undefined' or not colAttrs[i]? then '' else 'align=\'' + colAttrs[i].colVAlign + '\'' or ''
+            quoteAndComma = '","'
+            cellDel = ''
+            delimCell = '<td name=\'delimCell\' id=\'' + '\' class=\'hide-el overhead\'>' + quoteAndComma + '</td>'
+            lastCellBorder = ''
+            if i is tl - 1
+              delimCell = ''
+              lastCellBorder = 'border-right:' + tblBorderWidth + 'px solid ' + tblBorderColor + '!important;'
+              quoteAndComma = ''
+            if not ((tds[i].indexOf '/r/n') is -1)
+              cellsWithBr = ''
+              tdText = tds[i].split '/r/n'
+              k = 0
+              while k < tdText.length
+                if k < tdText.length - 1
+                  cellsWithBr += tdText[k] + '<label value=\'tblBreak\' class=\'hide-el\'>/r/n</label><label class=\'tblBreak\'></label>'
+                else
+                  cellsWithBr += tdText[k]
+                k++
+              htmlTbl += '<td  name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + lastCellBorder + '\' >' + cellsWithBr + '<br value=\'tblBreak\'></td>' + delimCell
+            else
+              htmlTbl += '<td name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + lastCellBorder + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + '\' >' + tds[i] + '' + '<br value=\'tblBreak\'></td>' + delimCell
+            i++
+          bracketAndcomma = '"]],"tblId":"1","tblClass":"data-tables"}'
+          htmlTbl += '<td name=\'bracketAndcomma\' class=\'  hide-el overhead\'>' + bracketAndcomma + '</td>'
+          htmlTbl += '</tr>'
+          j++
+        htmlTbl += '</tbody></table>'
+        htmlTbl
+      getCellAuthorColors: (authors, cell, row, tblBorderWidth) ->
+        cellBorderColor = null
+        if typeof authors isnt 'undefined' and authors?
+          for authorId of authors
+            author = authors[authorId]
+            cellBorderColor = author.colorId if typeof author isnt 'undefined' and author? and author.cell is cell and author.row is row
+        borderWidth = if tblBorderWidth isnt 0 then tblBorderWidth else 1
+        cellBorderColor = if not cellBorderColor? then '' else ';border:' + borderWidth + 'px solid ' + cellBorderColor
+        cellBorderColor
+      getCellAttrs: (singleRowAttr, cellAttr, colAttr, authors, cell, row) ->
+        attrsJSO = {}
+        colWidth = if typeof colAttr is 'undefined' or not colAttr? then '1' else colAttr.width or '1'
+        attrsJSO.'width' = (@getAttrInInch colWidth) + 'px'
+        cellBgColor = ''
+        if typeof singleRowAttr isnt 'undefined' and singleRowAttr?
+          bgColor = singleRowAttr.bgColor
+          cellBgColor = bgColor if typeof bgColor isnt 'undefined' and bgColor? and bgColor isnt '#FFFFFF'
+        if typeof colAttr isnt 'undefined' and colAttr?
+          bgColor = colAttr.bgColor
+          cellBgColor = bgColor if typeof bgColor isnt 'undefined' and bgColor? and bgColor isnt '#FFFFFF'
+        cellBgColor = if typeof cellAttr is 'undefined' or not cellAttr? then cellBgColor else cellAttr.bgColor or cellBgColor
+        attrsJSO.'background-color' = cellBgColor
+        cellHeight = if typeof cellAttr is 'undefined' or not cellAttr? then '' else cellAttr.height or ''
+        attrsJSO.'height' = (@getAttrInInch cellHeight) + 'px'
+        cellPadding = if typeof cellAttr is 'undefined' or not cellAttr? then '' else cellAttr.padding or ''
+        attrsJSO.'padding-top' = attrsJSO.'padding-bottom' = attrsJSO.'padding-left' = attrsJSO.'padding-right' = (@getAttrInInch cellPadding) + 'px'
+        cellVAlign = if typeof cellAttr is 'undefined' or not cellAttr? then '' else cellAttr.vAlign or ''
+        attrsJSO.'vertical-align' = cellVAlign
+        cellFontSize = if typeof cellAttr is 'undefined' or not cellAttr? then '' else cellAttr.fontSize or ''
+        attrsJSO.'font-size' = cellFontSize + 'px'
+        cellFontWeight = if typeof cellAttr is 'undefined' or not cellAttr? then '' else cellAttr.fontWeight or ''
+        attrsJSO.'font-weight' = cellFontWeight
+        cellFontStyle = if typeof cellAttr is 'undefined' or not cellAttr? then '' else cellAttr.fontStyle or ''
+        attrsJSO.'font-style' = cellFontStyle
+        cellTextDecoration = if typeof cellAttr is 'undefined' or not cellAttr? then '' else cellAttr.textDecoration or ''
+        attrsJSO.'text-decoration' = cellTextDecoration
+        attrsString = ''
+        [attrsString += attrName + ':' + attrsJSO[attrName] + ' !important;' if attrName and attrsJSO[attrName] isnt '' and attrsJSO[attrName] isnt 'NaNpx' and attrsJSO[attrName] isnt 'px' for attrName of attrsJSO]
+        attrsString
+      getAttrInInch: (attrValue) ->
+        intAttrValue = 0
+        intAttrValue = parseFloat attrValue
+        attrValue = if isNaN intAttrValue then parseFloat attrValue else intAttrValue
+        96 * attrValue - 1
+      getHtml: (code, attributes) ->
+        JSONCode = ''
+        html = ''
+        try
+          JSONCode = JSON.parse code
+          html = @buildTabularData JSONCode, attributes
+        catch
+        html
+    }
+    dRenderer
+
+if typeof exports isnt 'undefined' then exports.DatatablesRenderer = DatatablesRenderer else null
diff --git a/src/js/linestylefilter.ls b/src/js/linestylefilter.ls
new file mode 100644
index 0000000..587bbb3
--- /dev/null
+++ b/src/js/linestylefilter.ls
@@ -0,0 +1,5 @@
+exports.disableAuthorColorsForThisLine = (hook, context) ->
+  lineText = context.text
+  disableLineColors = false
+  disableLineColors = true if lineText and (lineText.indexOf 'data-tables') isnt -1
+  disableLineColors
\ No newline at end of file
diff --git a/static/js/contentcollector.js b/static/js/contentcollector.js
index a3d7b1b..1aa9901 100644
--- a/static/js/contentcollector.js
+++ b/static/js/contentcollector.js
@@ -1,35 +1,43 @@
-exports.collectContentLineBreak = function (hook, context) {
-    var tvalue = context.tvalue;
-    var breakLine = true;
-    if (tvalue && tvalue == 'tblBreak') {
-       breakLine = false;
-    }
-    return breakLine;
-};
-exports.collectContentLineText= function (hook, context) {
-    var n = context.node;
-    var txt = context.text;
-    if (txt) {
-        while (n) {
-            if (n.tagName == 'TD') {
-                var elementName = n.getAttribute("name");
-                if (elementName == 'tData') {
-                    txt = txt.replace(/\\/g, "|");
-                    txt = txt.replace(/"/g, "'");
-                    break;
-                } else if (elementName == 'delimCell') {
-                    txt = '","';
-                    break;
-                } else if (elementName == 'payload') {
-                    txt = "{\"payload\":[[\"";
-                    break;
-                } else if (elementName == 'bracketAndcomma') {
-                    txt = "\"]],\"tblId\":\"1\",\"tblClass\":\"data-tables\"}";
-                    break;
-                }
-            }
-            n = n.parentNode;
-        }
-    }
-    return txt;
-};
+exports.collectContentLineBreak = function(hook, context){
+  var tvalue, breakLine;
+  tvalue = context.tvalue;
+  breakLine = true;
+  if (tvalue && tvalue === 'tblBreak') {
+    breakLine = false;
+  }
+  return breakLine;
+};
+exports.collectContentLineText = function(hook, context){
+  var n, txt, elementName;
+  n = context.node;
+  txt = context.text;
+  if (txt) {
+    while (n) {
+      if (n.tagName === 'TD') {
+        elementName = n.getAttribute('name');
+        if (elementName === 'tData') {
+          txt = txt.replace(/\\/g, '|');
+          txt = txt.replace(/"/g, '\'');
+          break;
+        } else {
+          if (elementName === 'delimCell') {
+            txt = '","';
+            break;
+          } else {
+            if (elementName === 'payload') {
+              txt = '{"payload":[["';
+              break;
+            } else {
+              if (elementName === 'bracketAndcomma') {
+                txt = '"]],"tblId":"1","tblClass":"data-tables"}';
+                break;
+              }
+            }
+          }
+        }
+      }
+      n = n.parentNode;
+    }
+  }
+  return txt;
+};
\ No newline at end of file
diff --git a/static/js/datatables-renderer.js b/static/js/datatables-renderer.js
index fe2add0..1f3efbc 100644
--- a/static/js/datatables-renderer.js
+++ b/static/js/datatables-renderer.js
@@ -1,187 +1,250 @@
-if (typeof (DatatablesRenderer) == 'undefined') var DatatablesRenderer = function () {
-        var dRenderer = {
-            render: function (params, element, attributes) {
-                var renderer = new DatatablesRenderer.Renderer();
-                if (element.innerText) code = element.innerText;
-                else code = element.textContent;
-                element.innerHTML = renderer.getHtml(code, attributes);
-            }
-        }; // end of dRenderer
-        dRenderer.Renderer = function () {
-            //	
-        };
-        dRenderer.Renderer.prototype = {
-            createDefaultTblProperties: function (authors) {
-                return {
-                    borderWidth: "1",
-                    cellAttrs: [],
-                    width: "6",
-                    rowAttrs: {},
-                    colAttrs: [],
-                    authors: {}
-                };
-            },
-            buildTabularData: function (tblJSONObj, tblPropsJSString) {
-                var htmlTbl = "";
-                var tblId = tblJSONObj.tblId;
-                var tblClass = tblJSONObj.tblClass;
-                var tdClass = tblJSONObj.tdClass;
-                var trClass = tblJSONObj.trClass;
-                var payload = tblJSONObj.payload;
-                var tblProperties = {};
-                try {
-                    tblProperties = JSON.parse(tblPropsJSString);
-                } catch (error) {
-                    tblProperties = this.createDefaultTblProperties();
-                }
-                var rowAttrs = tblProperties.rowAttrs;
-                var singleRowAttrs = rowAttrs.singleRowAttrs;
-                var cellAttrs = tblProperties.cellAttrs;
-                var colAttrs = tblProperties.colAttrs;
-                var tblWidth = typeof (tblProperties) == 'undefined' || tblProperties == null ? "1" : tblProperties.width || "1";
-                tblWidth = this.getAttrInInch(tblWidth);
-                var tblHeight = typeof (tblProperties) == 'undefined' || tblProperties == null ? ".1" : tblProperties.height || ".1";
-                tblHeight = this.getAttrInInch(tblHeight);
-                var tblBorderWidth = typeof (tblProperties) == 'undefined' || tblProperties == null ? 0 : tblProperties.borderWidth || 0;
-                var tblBorderColor = typeof (tblProperties) == 'undefined' || tblProperties == null ? "#000000" : tblProperties.borderColor || "#000000";
-                var currRow = tblProperties.currRowAuthorIdx;
-                var currCell = tblProperties.currCellAuthorIdx;
-                var authors = tblProperties.authors;
-                var printViewTBlStyles = "table-layout:fixed !important;border-collapse:collapse!important;font-family:Trebuchet MS!important;";
-                var printViewTblTDStyles = "font-size: 1em!important;line-height: 1em!important;padding: 3px 7px 2px!important;word-wrap: break-word!important;"
-                var htmlTbl = "<table class='" + tblClass + "' style='" + printViewTBlStyles + "background-color:white;width:" + tblWidth + "px!important;height:" + tblHeight + "px!important; border-top: " + tblBorderWidth + "px solid " + tblBorderColor + "!important;" + "'><tbody>";
-                var borders = "border-bottom:" + tblBorderWidth + "px solid " + tblBorderColor;
-                var rowVAlign = typeof (rowAttrs) == 'undefined' || rowAttrs == null ? "left" : rowAttrs.rowVAlign || "left";
-                var rows = tblJSONObj.payload;
-                var evenRowBgColor = typeof (rowAttrs) == 'undefined' || rowAttrs == null ? "#FFFFFF" : rowAttrs.evenBgColor || "#FFFFFF";
-                var oddRowBgColor = typeof (rowAttrs) == 'undefined' || rowAttrs == null ? null : rowAttrs.oddBgColor || null;
-                for (var j = 0, rl = rows.length; j < rl; j++) {
-                    var tds = rows[j];
-                    var rowBgColor = oddRowBgColor;
-                    if (!rowBgColor) {
-                        rowBgColor = evenRowBgColor;
-                    }
-                    htmlTbl += "<tr style='vertical-align:" + rowVAlign + ";background-color:" + rowBgColor + "; " + borders + "!important;' class='" + trClass + "'>";
-                    var preHeader = "";
-                    if (j == 0) {
-                        preHeader = "{\"payload\":[[\"";
-                    }
-                    htmlTbl += "<td  name='payload' class='hide-el overhead'>" + preHeader + "</td>";
-                    var singleRowAttr = typeof (singleRowAttrs) == 'undefined' || singleRowAttrs == null ? null : singleRowAttrs[j];
-                    for (var i = 0, tl = tds.length; i < tl; i++) {
-                        var cellAttr = typeof (cellAttrs[j]) == 'undefined' || cellAttrs[j] == null ? null : cellAttrs[j][i];
-                        var cellStyles = this.getCellAttrs(singleRowAttr, cellAttr, colAttrs[i], authors, i, j);
-                        
-                        var authorBorderColor = this.getCellAuthorColors(authors, i, j, tblBorderWidth) + "!important;";
-                        var borderTop = "";
-                        if (tblBorderWidth == 0) {
-                            borderTop = " border-top: 0px solid white !important;";
-                        }
-                        //col vAlign
-                        var colVAlign = typeof (colAttrs[i]) == 'undefined' || colAttrs[i] == null ? "" : "align='" + colAttrs[i].colVAlign + "'" || "";
-                        var quoteAndComma = "\",\"";
-                        var cellDel = "";
-                        var delimCell = "<td name='delimCell' id='" + "' class='hide-el overhead'>" + quoteAndComma + "</td>";
-                        var lastCellBorder = "";
-                        if (i == tl - 1) {
-                            delimCell = "";
-                            lastCellBorder = "border-right:" + tblBorderWidth + "px solid " + tblBorderColor + "!important;";
-                            quoteAndComma = "";
-                        }
-                        if (tds[i].indexOf('/r/n') != -1) {
-                            cellsWithBr = "";
-                            var tdText = tds[i].split('/r/n');
-                            for (var k = 0; k < tdText.length; k++) {
-                                if (k < tdText.length - 1) {
-                                    cellsWithBr += tdText[k] + "<label value='tblBreak' class='hide-el'>/r/n</label><label class='tblBreak'></label>";
-                                } else cellsWithBr += tdText[k];
-                            }
-                            htmlTbl += "<td  name='tData' " + colVAlign + " style='" + printViewTblTDStyles + cellStyles + " border-left:" + 
-                            tblBorderWidth + "px solid " + tblBorderColor + authorBorderColor + borderTop + lastCellBorder + "' >" + cellsWithBr + 
-                            "<br value='tblBreak'></td>" + delimCell;
-                        } else {
-                            htmlTbl += "<td name='tData' " + colVAlign + " style='" + printViewTblTDStyles + cellStyles + lastCellBorder + " border-left:" + tblBorderWidth + "px solid " + tblBorderColor + authorBorderColor + borderTop + "' >" + tds[i] + "" + "<br value='tblBreak'></td>" + delimCell
-                        }
-                    }
-                    var bracketAndcomma = "\"]],\"tblId\":\"1\",\"tblClass\":\"data-tables\"}";
-                    htmlTbl += "<td name='bracketAndcomma' class='  hide-el overhead'>" + bracketAndcomma + "</td>";
-                    htmlTbl += "</tr>";
-                }
-                htmlTbl += "</tbody></table>";
-                return htmlTbl;
-            },
-            getCellAuthorColors: function (authors, cell, row, tblBorderWidth) {
-                var cellBorderColor = null;
-                if (typeof (authors) != 'undefined' && authors != null) {
-                    for (var authorId in authors) {
-                        author = authors[authorId];
-                        if (typeof (author) != 'undefined' && author != null && author.cell == cell && author.row == row) {
-                            cellBorderColor = author.colorId;
-                        }
-                    }
-                }
-                var borderWidth = tblBorderWidth != 0 ? tblBorderWidth : 1;           
-                cellBorderColor = cellBorderColor == null ? "" : ";border:" + borderWidth + "px solid " + cellBorderColor;
-                return cellBorderColor;
-            },
-            getCellAttrs: function (singleRowAttr, cellAttr, colAttr, authors, cell, row) {
-                var attrsJSO = {};
-                var colWidth = typeof (colAttr) == 'undefined' || colAttr == null ? "1" : colAttr.width || "1";
-                attrsJSO['width'] = this.getAttrInInch(colWidth) + 'px';
-                var cellBgColor = "";
-                //row highlight
-                if (typeof (singleRowAttr) != 'undefined' && singleRowAttr != null) {
-                    var bgColor = singleRowAttr.bgColor;
-                    if (typeof (bgColor) != 'undefined' && bgColor != null && bgColor != '#FFFFFF') {
-                        cellBgColor = bgColor;
-                    }
-                }
-                //col highlight
-                if (typeof (colAttr) != 'undefined' && colAttr != null) {
-                    var bgColor = colAttr.bgColor;
-                    if (typeof (bgColor) != 'undefined' && bgColor != null && bgColor != '#FFFFFF') {
-                        cellBgColor = bgColor;
-                    }
-                }
-                cellBgColor = typeof (cellAttr) == 'undefined' || cellAttr == null ? cellBgColor : cellAttr.bgColor || cellBgColor;
-                attrsJSO['background-color'] = cellBgColor;
-                var cellHeight = typeof (cellAttr) == 'undefined' || cellAttr == null ? "" : cellAttr.height || "";
-                attrsJSO['height'] = this.getAttrInInch(cellHeight) + 'px';
-                var cellPadding = typeof (cellAttr) == 'undefined' || cellAttr == null ? "" : cellAttr.padding || "";
-                attrsJSO['padding-top'] = attrsJSO['padding-bottom'] = attrsJSO['padding-left'] = attrsJSO['padding-right'] = this.getAttrInInch(cellPadding) + 'px';
-                var cellVAlign = typeof (cellAttr) == 'undefined' || cellAttr == null ? "" : cellAttr.vAlign || "";
-                attrsJSO['vertical-align'] = cellVAlign;
-                var cellFontSize = typeof (cellAttr) == 'undefined' || cellAttr == null ? "" : cellAttr.fontSize || "";
-                attrsJSO['font-size'] = cellFontSize + 'px';
-                var cellFontWeight = typeof (cellAttr) == 'undefined' || cellAttr == null ? "" : cellAttr.fontWeight || "";
-                attrsJSO['font-weight'] = cellFontWeight;
-                var cellFontStyle = typeof (cellAttr) == 'undefined' || cellAttr == null ? "" : cellAttr.fontStyle || "";
-                attrsJSO['font-style'] = cellFontStyle;
-                var cellTextDecoration = typeof (cellAttr) == 'undefined' || cellAttr == null ? "" : cellAttr.textDecoration || "";
-                attrsJSO['text-decoration'] = cellTextDecoration;
-                var attrsString = "";
-                for (var attrName in attrsJSO) {
-                    if (attrName && attrsJSO[attrName] != "" && attrsJSO[attrName] != "NaNpx" && attrsJSO[attrName] != "px") attrsString += attrName + ":" + attrsJSO[attrName] + " !important;";
-                }
-                return attrsString;
-            },
-            getAttrInInch: function (attrValue) {
-                var intAttrValue = 0;
-                intAttrValue = parseFloat(attrValue);
-                attrValue = isNaN(intAttrValue) ? parseFloat(attrValue) : intAttrValue;
-                return 96 * attrValue - 1;
-            },
-            getHtml: function (code, attributes) {
-                var JSONCode = "";
-                var html = "";
-                try {
-                    JSONCode = JSON.parse(code);
-                    html = this.buildTabularData(JSONCode, attributes);
-                } catch (error) {}
-                return html;
-            },
-        };
-        return dRenderer;
-    }(); // end of anonymous function
-// CommonJS
-typeof (exports) != 'undefined' ? exports.DatatablesRenderer = DatatablesRenderer : null;
+var DatatablesRenderer;
+if (typeof DatatablesRenderer === 'undefined') {
+  DatatablesRenderer = function(){
+    var dRenderer;
+    dRenderer = {
+      render: function(params, element, attributes){
+        var renderer, code;
+        renderer = new DatatablesRenderer.Renderer;
+        if (element.innerText) {
+          code = element.innerText;
+        } else {
+          code = element.textContent;
+        }
+        return element.innerHTML = renderer.getHtml(code, attributes);
+      }
+    };
+    dRenderer.Renderer = function(){};
+    dRenderer.Renderer.prototype = {
+      createDefaultTblProperties: function(authors){
+        return {
+          borderWidth: '1',
+          cellAttrs: [],
+          width: '6',
+          rowAttrs: {},
+          colAttrs: [],
+          authors: {}
+        };
+      },
+      buildTabularData: function(tblJSONObj, tblPropsJSString){
+        var htmlTbl, tblId, tblClass, tdClass, trClass, payload, tblProperties, error, rowAttrs, singleRowAttrs, cellAttrs, colAttrs, tblWidth, tblHeight, tblBorderWidth, tblBorderColor, currRow, currCell, authors, printViewTBlStyles, printViewTblTDStyles, borders, rowVAlign, rows, evenRowBgColor, oddRowBgColor, j, rl, tds, rowBgColor, preHeader, singleRowAttr, i, tl, cellAttr, cellStyles, authorBorderColor, borderTop, colVAlign, quoteAndComma, cellDel, delimCell, lastCellBorder, cellsWithBr, tdText, k, bracketAndcomma;
+        htmlTbl = '';
+        tblId = tblJSONObj.tblId;
+        tblClass = tblJSONObj.tblClass;
+        tdClass = tblJSONObj.tdClass;
+        trClass = tblJSONObj.trClass;
+        payload = tblJSONObj.payload;
+        tblProperties = {};
+        try {
+          tblProperties = JSON.parse(tblPropsJSString);
+        } catch (e$) {
+          error = e$;
+          tblProperties = this.createDefaultTblProperties();
+        }
+        rowAttrs = tblProperties.rowAttrs;
+        singleRowAttrs = rowAttrs.singleRowAttrs;
+        cellAttrs = tblProperties.cellAttrs;
+        colAttrs = tblProperties.colAttrs;
+        tblWidth = typeof tblProperties === 'undefined' || tblProperties == null
+          ? '1'
+          : tblProperties.width || '1';
+        tblWidth = this.getAttrInInch(tblWidth);
+        tblHeight = typeof tblProperties === 'undefined' || tblProperties == null
+          ? '.1'
+          : tblProperties.height || '.1';
+        tblHeight = this.getAttrInInch(tblHeight);
+        tblBorderWidth = typeof tblProperties === 'undefined' || tblProperties == null
+          ? 0
+          : tblProperties.borderWidth || 0;
+        tblBorderColor = typeof tblProperties === 'undefined' || tblProperties == null
+          ? '#000000'
+          : tblProperties.borderColor || '#000000';
+        currRow = tblProperties.currRowAuthorIdx;
+        currCell = tblProperties.currCellAuthorIdx;
+        authors = tblProperties.authors;
+        printViewTBlStyles = 'table-layout:fixed !important;border-collapse:collapse!important;font-family:Trebuchet MS!important;';
+        printViewTblTDStyles = 'font-size: 1em!important;line-height: 1em!important;padding: 3px 7px 2px!important;word-wrap: break-word!important;';
+        htmlTbl = '<table class=\'' + tblClass + '\' style=\'' + printViewTBlStyles + 'background-color:white;width:' + tblWidth + 'px!important;height:' + tblHeight + 'px!important; border-top: ' + tblBorderWidth + 'px solid ' + tblBorderColor + '!important;' + '\'><tbody>';
+        borders = 'border-bottom:' + tblBorderWidth + 'px solid ' + tblBorderColor;
+        rowVAlign = typeof rowAttrs === 'undefined' || rowAttrs == null
+          ? 'left'
+          : rowAttrs.rowVAlign || 'left';
+        rows = tblJSONObj.payload;
+        evenRowBgColor = typeof rowAttrs === 'undefined' || rowAttrs == null
+          ? '#FFFFFF'
+          : rowAttrs.evenBgColor || '#FFFFFF';
+        oddRowBgColor = typeof rowAttrs === 'undefined' || rowAttrs == null
+          ? null
+          : rowAttrs.oddBgColor || null;
+        j = 0;
+        rl = rows.length;
+        while (j < rl) {
+          tds = rows[j];
+          rowBgColor = oddRowBgColor;
+          if (!rowBgColor) {
+            rowBgColor = evenRowBgColor;
+          }
+          htmlTbl += '<tr style=\'vertical-align:' + rowVAlign + ';background-color:' + rowBgColor + '; ' + borders + '!important;\' class=\'' + trClass + '\'>';
+          preHeader = '';
+          if (j === 0) {
+            preHeader = '{"payload":[["';
+          }
+          htmlTbl += '<td  name=\'payload\' class=\'hide-el overhead\'>' + preHeader + '</td>';
+          singleRowAttr = typeof singleRowAttrs === 'undefined' || singleRowAttrs == null
+            ? null
+            : singleRowAttrs[j];
+          i = 0;
+          tl = tds.length;
+          while (i < tl) {
+            cellAttr = typeof cellAttrs[j] === 'undefined' || cellAttrs[j] == null
+              ? null
+              : cellAttrs[j][i];
+            cellStyles = this.getCellAttrs(singleRowAttr, cellAttr, colAttrs[i], authors, i, j);
+            authorBorderColor = this.getCellAuthorColors(authors, i, j, tblBorderWidth) + '!important;';
+            borderTop = '';
+            if (tblBorderWidth === 0) {
+              borderTop = ' border-top: 0px solid white !important;';
+            }
+            colVAlign = typeof colAttrs[i] === 'undefined' || colAttrs[i] == null
+              ? ''
+              : 'align=\'' + colAttrs[i].colVAlign + '\'' || '';
+            quoteAndComma = '","';
+            cellDel = '';
+            delimCell = '<td name=\'delimCell\' id=\'' + '\' class=\'hide-el overhead\'>' + quoteAndComma + '</td>';
+            lastCellBorder = '';
+            if (i === tl - 1) {
+              delimCell = '';
+              lastCellBorder = 'border-right:' + tblBorderWidth + 'px solid ' + tblBorderColor + '!important;';
+              quoteAndComma = '';
+            }
+            if (!(tds[i].indexOf('/r/n') === -1)) {
+              cellsWithBr = '';
+              tdText = tds[i].split('/r/n');
+              k = 0;
+              while (k < tdText.length) {
+                if (k < tdText.length - 1) {
+                  cellsWithBr += tdText[k] + '<label value=\'tblBreak\' class=\'hide-el\'>/r/n</label><label class=\'tblBreak\'></label>';
+                } else {
+                  cellsWithBr += tdText[k];
+                }
+                k++;
+              }
+              htmlTbl += '<td  name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + lastCellBorder + '\' >' + cellsWithBr + '<br value=\'tblBreak\'></td>' + delimCell;
+            } else {
+              htmlTbl += '<td name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + lastCellBorder + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + '\' >' + tds[i] + '' + '<br value=\'tblBreak\'></td>' + delimCell;
+            }
+            i++;
+          }
+          bracketAndcomma = '"]],"tblId":"1","tblClass":"data-tables"}';
+          htmlTbl += '<td name=\'bracketAndcomma\' class=\'  hide-el overhead\'>' + bracketAndcomma + '</td>';
+          htmlTbl += '</tr>';
+          j++;
+        }
+        htmlTbl += '</tbody></table>';
+        return htmlTbl;
+      },
+      getCellAuthorColors: function(authors, cell, row, tblBorderWidth){
+        var cellBorderColor, authorId, author, borderWidth;
+        cellBorderColor = null;
+        if (typeof authors !== 'undefined' && authors != null) {
+          for (authorId in authors) {
+            author = authors[authorId];
+            if (typeof author !== 'undefined' && author != null && author.cell === cell && author.row === row) {
+              cellBorderColor = author.colorId;
+            }
+          }
+        }
+        borderWidth = tblBorderWidth !== 0 ? tblBorderWidth : 1;
+        cellBorderColor = cellBorderColor == null
+          ? ''
+          : ';border:' + borderWidth + 'px solid ' + cellBorderColor;
+        return cellBorderColor;
+      },
+      getCellAttrs: function(singleRowAttr, cellAttr, colAttr, authors, cell, row){
+        var attrsJSO, colWidth, cellBgColor, bgColor, cellHeight, cellPadding, cellVAlign, cellFontSize, cellFontWeight, cellFontStyle, cellTextDecoration, attrsString, attrName;
+        attrsJSO = {};
+        colWidth = typeof colAttr === 'undefined' || colAttr == null
+          ? '1'
+          : colAttr.width || '1';
+        attrsJSO['width'] = this.getAttrInInch(colWidth) + 'px';
+        cellBgColor = '';
+        if (typeof singleRowAttr !== 'undefined' && singleRowAttr != null) {
+          bgColor = singleRowAttr.bgColor;
+          if (typeof bgColor !== 'undefined' && bgColor != null && bgColor !== '#FFFFFF') {
+            cellBgColor = bgColor;
+          }
+        }
+        if (typeof colAttr !== 'undefined' && colAttr != null) {
+          bgColor = colAttr.bgColor;
+          if (typeof bgColor !== 'undefined' && bgColor != null && bgColor !== '#FFFFFF') {
+            cellBgColor = bgColor;
+          }
+        }
+        cellBgColor = typeof cellAttr === 'undefined' || cellAttr == null
+          ? cellBgColor
+          : cellAttr.bgColor || cellBgColor;
+        attrsJSO['background-color'] = cellBgColor;
+        cellHeight = typeof cellAttr === 'undefined' || cellAttr == null
+          ? ''
+          : cellAttr.height || '';
+        attrsJSO['height'] = this.getAttrInInch(cellHeight) + 'px';
+        cellPadding = typeof cellAttr === 'undefined' || cellAttr == null
+          ? ''
+          : cellAttr.padding || '';
+        attrsJSO['padding-top'] = attrsJSO['padding-bottom'] = attrsJSO['padding-left'] = attrsJSO['padding-right'] = this.getAttrInInch(cellPadding) + 'px';
+        cellVAlign = typeof cellAttr === 'undefined' || cellAttr == null
+          ? ''
+          : cellAttr.vAlign || '';
+        attrsJSO['vertical-align'] = cellVAlign;
+        cellFontSize = typeof cellAttr === 'undefined' || cellAttr == null
+          ? ''
+          : cellAttr.fontSize || '';
+        attrsJSO['font-size'] = cellFontSize + 'px';
+        cellFontWeight = typeof cellAttr === 'undefined' || cellAttr == null
+          ? ''
+          : cellAttr.fontWeight || '';
+        attrsJSO['font-weight'] = cellFontWeight;
+        cellFontStyle = typeof cellAttr === 'undefined' || cellAttr == null
+          ? ''
+          : cellAttr.fontStyle || '';
+        attrsJSO['font-style'] = cellFontStyle;
+        cellTextDecoration = typeof cellAttr === 'undefined' || cellAttr == null
+          ? ''
+          : cellAttr.textDecoration || '';
+        attrsJSO['text-decoration'] = cellTextDecoration;
+        attrsString = '';
+        for (attrName in attrsJSO) {
+          if (attrName && attrsJSO[attrName] !== '' && attrsJSO[attrName] !== 'NaNpx' && attrsJSO[attrName] !== 'px') {
+            attrsString += attrName + ':' + attrsJSO[attrName] + ' !important;';
+          }
+        }
+        return attrsString;
+      },
+      getAttrInInch: function(attrValue){
+        var intAttrValue;
+        intAttrValue = 0;
+        intAttrValue = parseFloat(attrValue);
+        attrValue = isNaN(intAttrValue) ? parseFloat(attrValue) : intAttrValue;
+        return 96 * attrValue - 1;
+      },
+      getHtml: function(code, attributes){
+        var JSONCode, html, e;
+        JSONCode = '';
+        html = '';
+        try {
+          JSONCode = JSON.parse(code);
+          html = this.buildTabularData(JSONCode, attributes);
+        } catch (e$) {
+          e = e$;
+        }
+        return html;
+      }
+    };
+    return dRenderer;
+  }();
+}
+if (typeof exports !== 'undefined') {
+  exports.DatatablesRenderer = DatatablesRenderer;
+} else {
+  null;
+}
\ No newline at end of file
diff --git a/static/js/linestylefilter.js b/static/js/linestylefilter.js
index 381ce18..5b9cecf 100644
--- a/static/js/linestylefilter.js
+++ b/static/js/linestylefilter.js
@@ -1,8 +1,9 @@
-exports.disableAuthorColorsForThisLine = function (hook, context) {
-    var lineText = context.text;
-    var disableLineColors = false;
-    if (lineText && lineText.indexOf('data-tables')!=-1) {
-       disableLineColors = true;
-    }
-    return disableLineColors;
-};
+exports.disableAuthorColorsForThisLine = function(hook, context){
+  var lineText, disableLineColors;
+  lineText = context.text;
+  disableLineColors = false;
+  if (lineText && lineText.indexOf('data-tables') !== -1) {
+    disableLineColors = true;
+  }
+  return disableLineColors;
+};
\ No newline at end of file

From d6b9e2653cba97e2f14305a5b5a8755fd82fe32a Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 30 Oct 2012 15:43:08 +0800
Subject: [PATCH 05/36] avoid arguments.callee

---
 src/js/datatables.ls | 3 +--
 1 file changed, 1 insertion(+), 2 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index b878f56..c2e1c09 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -599,7 +599,6 @@ if typeof Datatables is 'undefined'
   Datatables = do ->
     nodeText = (n) ->
       text = []
-      self = arguments_.callee
       el = void
       els = n.childNodes
       excluded = {
@@ -610,7 +609,7 @@ if typeof Datatables is 'undefined'
       iLen = els.length
       while i < iLen
         el = els[i]
-        if el.nodeType is 1 and el.tagName.toLowerCase! of excluded then text.push self el else if el.nodeType is 3 then text.push el.data
+        if el.nodeType is 1 and el.tagName.toLowerCase! of excluded then text.push nodeText el else if el.nodeType is 3 then text.push el.data
         i++
       text.join ''
     dt = {

From 97c4a477dd4eae1eddf2ce5bd8d39f1a91145144 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 30 Oct 2012 17:17:31 +0800
Subject: [PATCH 06/36] use alternative json encoding that allows verbatim "
 and \\ in content

---
 src/js/contentcollector.ls       | 10 +++---
 src/js/datatables-renderer.ls    |  8 ++---
 src/js/datatables.ls             | 59 ++++++++++++++++++++------------
 static/js/contentcollector.js    |  8 ++---
 static/js/datatables-renderer.js |  8 ++---
 5 files changed, 53 insertions(+), 40 deletions(-)

diff --git a/src/js/contentcollector.ls b/src/js/contentcollector.ls
index 93db74c..921e0fe 100644
--- a/src/js/contentcollector.ls
+++ b/src/js/contentcollector.ls
@@ -12,20 +12,18 @@ exports.collectContentLineText = (hook, context) ->
       if n.tagName is 'TD'
         elementName = n.getAttribute 'name'
         if elementName is 'tData'
-          txt = txt.replace //\\//g, '|'
-          txt = txt.replace //"//g, '\''
           break
         else
           if elementName is 'delimCell'
-            txt = '","'
+            txt = '\uF134,\uF134'
             break
           else
             if elementName is 'payload'
-              txt = '{"payload":[["'
+              txt = '{\uF134payload\uF134:[[\uF134'
               break
             else
               if elementName is 'bracketAndcomma'
-                txt = '"]],"tblId":"1","tblClass":"data-tables"}'
+                txt = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134data-tables\uF134}'
                 break
       n = n.parentNode
-  txt
\ No newline at end of file
+  txt
diff --git a/src/js/datatables-renderer.ls b/src/js/datatables-renderer.ls
index f0154c8..018c7da 100644
--- a/src/js/datatables-renderer.ls
+++ b/src/js/datatables-renderer.ls
@@ -56,7 +56,7 @@ if typeof DatatablesRenderer is 'undefined'
           rowBgColor = evenRowBgColor if not rowBgColor
           htmlTbl += '<tr style=\'vertical-align:' + rowVAlign + ';background-color:' + rowBgColor + '; ' + borders + '!important;\' class=\'' + trClass + '\'>'
           preHeader = ''
-          if j is 0 then preHeader = '{"payload":[["'
+          if j is 0 then preHeader = '{\uF134payload\uF134:[[\uF134'
           htmlTbl += '<td  name=\'payload\' class=\'hide-el overhead\'>' + preHeader + '</td>'
           singleRowAttr = if typeof singleRowAttrs is 'undefined' or not singleRowAttrs? then null else singleRowAttrs[j]
           i = 0
@@ -68,7 +68,7 @@ if typeof DatatablesRenderer is 'undefined'
             borderTop = ''
             borderTop = ' border-top: 0px solid white !important;' if tblBorderWidth is 0
             colVAlign = if typeof colAttrs[i] is 'undefined' or not colAttrs[i]? then '' else 'align=\'' + colAttrs[i].colVAlign + '\'' or ''
-            quoteAndComma = '","'
+            quoteAndComma = '\uF134,\uF134'
             cellDel = ''
             delimCell = '<td name=\'delimCell\' id=\'' + '\' class=\'hide-el overhead\'>' + quoteAndComma + '</td>'
             lastCellBorder = ''
@@ -90,7 +90,7 @@ if typeof DatatablesRenderer is 'undefined'
             else
               htmlTbl += '<td name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + lastCellBorder + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + '\' >' + tds[i] + '' + '<br value=\'tblBreak\'></td>' + delimCell
             i++
-          bracketAndcomma = '"]],"tblId":"1","tblClass":"data-tables"}'
+          bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134data-tables\uF134}'
           htmlTbl += '<td name=\'bracketAndcomma\' class=\'  hide-el overhead\'>' + bracketAndcomma + '</td>'
           htmlTbl += '</tr>'
           j++
@@ -144,7 +144,7 @@ if typeof DatatablesRenderer is 'undefined'
         JSONCode = ''
         html = ''
         try
-          JSONCode = JSON.parse code
+          JSONCode = JSON.parse code.replace(/(\\|")/g, '\\$1').replace(/\uF134/g, '"')
           html = @buildTabularData JSONCode, attributes
         catch
         html
diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index c2e1c09..f563ee9 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -7,6 +7,21 @@ if not (typeof require is 'undefined')
 exports.aceInitInnerdocbodyHead = (hook_name, args, cb) ->
   args.iframeHTML.push '<link rel="stylesheet" type="text/css" href="/static/plugins/ep_tables/static/css/dataTables.css"/>'
 
+escapedJSON = ->
+  ret = JSON.stringify it
+    .replace /\\(.)/g    (_, _1) -> "\\"+_1.charCodeAt(0)+\;
+    .replace /"/g        '\uF134'
+    .replace /\\(\d+);/g (_, _1) -> "\\"+String.fromCharCode(_1)
+  #console.log ret
+  #console.trace ret
+  ret
+
+fromEscapedJSON = ->
+  ret = JSON.parse it.replace(/(\\|")/g, '\\$1').replace(/\uF134/g, '"')
+  #console.log ret
+  #console.trace \fromEscape
+  ret
+
 exports.postAceInit = (hook, context) ->
   $.createTableMenu = (init) ->
     showTblPropPanel = ->
@@ -623,10 +638,10 @@ if typeof Datatables is 'undefined'
       }}
       config: {}
       vars: {
-        OVERHEAD_LEN_PRE: '{"payload":[["'.length
-        OVERHEAD_LEN_MID: '","'.length
-        OVERHEAD_LEN_ROW_START: '["'.length
-        OVERHEAD_LEN_ROW_END: '"],'.length
+        OVERHEAD_LEN_PRE: '{\uF134payload":[[\uF134'.length
+        OVERHEAD_LEN_MID: '\uF134,\uF134'.length
+        OVERHEAD_LEN_ROW_START: '[\uF134'.length
+        OVERHEAD_LEN_ROW_END: '\uF134],'.length
         JS_KEY_CODE_BS: 8
         JS_KEY_CODE_DEL: 46
         TBL_OPTIONS: [
@@ -703,6 +718,7 @@ if typeof Datatables is 'undefined'
       else
         switch cmd
         case Datatables.vars.TBL_OPTIONS.0
+          console.log xByY
           Datatables.addTable xByY
         case Datatables.vars.TBL_OPTIONS.1
           Datatables.insertTblRow 'addA'
@@ -729,7 +745,7 @@ if typeof Datatables is 'undefined'
         hasMoreRows = tableObj.hasMoreRows
         isRowAddition = tableObj.isRowAddition
       if isRowAddition
-        table = JSON.parse tableObj.tblString
+        table = fromEscapedJSON tableObj.tblString
         insertTblRowBelow 0, table
         performDocApplyTblAttrToRow rep.selStart, JSON.stringify table.tblProperties
         return 
@@ -777,7 +793,8 @@ if typeof Datatables is 'undefined'
       try
         newText = ''
         currLineText = (rep.lines.atIndex rep.selStart.0).text
-        payload = (JSON.parse currLineText).payload
+        payload = (fromEscapedJSON currLineText).payload
+        console.log \zzz, payload
         currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
         currRow = currTdInfo.row
         lastRowOffSet = 0
@@ -841,7 +858,7 @@ if typeof Datatables is 'undefined'
       if props.tblColWidth or props.tblSingleColBgColor or props.tblColVAlign
         currLine = rep.lines.atIndex rep.selStart.0
         currLineText = currLine.text
-        tblJSONObj = JSON.parse currLineText
+        tblJSONObj = fromEscapedJSON currLineText
         payload = tblJSONObj.payload
         currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
         currTd = currTdInfo.td
@@ -920,7 +937,7 @@ if typeof Datatables is 'undefined'
       currLineText = currLine.text
       if (currLineText.indexOf 'data-tables') is -1 then return true
       (try
-        tblJSONObj = JSON.parse currLineText
+        tblJSONObj = fromEscapedJSON currLineText
         tblProperties = @getLineTableProperty start.0
         update = false
         if props.tblWidth or props.tblHeight or props.tblBorderWidth or props.tblBorderColor
@@ -969,7 +986,7 @@ if typeof Datatables is 'undefined'
       currLineText = (rep.lines.atIndex rep.selStart.0).text
       payload = [[]]
       if not numOfRows and numOfRows isnt 0
-        tblPayload = (JSON.parse currLineText).payload
+        tblPayload = (fromEscapedJSON currLineText).payload
         numOfRows = tblPayload.0.length
       tblRows = new Array numOfRows
       if not (numOfRows is 0)
@@ -988,7 +1005,7 @@ if typeof Datatables is 'undefined'
       }
       rep.selEnd.1 = rep.selStart.1 = currLineText.length
       @context.editorInfo.ace_doReturnKey!
-      @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, JSON.stringify tableObj
+      @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, escapedJSON tableObj
     dt.createDefaultTblProperties = (authors) ->
       rep = @context.rep
       defTblProp = {
@@ -1032,7 +1049,7 @@ if typeof Datatables is 'undefined'
         rep = context.rep
         currLine = rep.lines.atIndex rep.selStart.0
         currLineText = currLine.text
-        tblJSONObj = JSON.parse currLineText
+        tblJSONObj = fromEscapedJSON currLineText
         payload = tblJSONObj.payload
         currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
         leftOverTdTxtLen = currTdInfo.leftOverTdTxtLen
@@ -1051,7 +1068,7 @@ if typeof Datatables is 'undefined'
           else
             currTd = -1
             rep.selStart.0 = rep.selEnd.0 = rep.selStart.0 + 1
-            tblJSONObj = JSON.parse nextLineText
+            tblJSONObj = fromEscapedJSON nextLineText
             payload = tblJSONObj.payload
             leftOverTdTxtLen = payload.0.0.length
             rep.selEnd.1 = rep.selStart.1 = @vars.OVERHEAD_LEN_PRE + leftOverTdTxtLen
@@ -1116,7 +1133,7 @@ if typeof Datatables is 'undefined'
       func = 'insertTblColumn()'
       try
         currLineText = (rep.lines.atIndex rep.selStart.0).text
-        tblJSONObj = JSON.parse currLineText
+        tblJSONObj = fromEscapedJSON currLineText
         payload = tblJSONObj.payload
         currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
         currTd = currTdInfo.td
@@ -1131,7 +1148,7 @@ if typeof Datatables is 'undefined'
         rep.selEnd.0 = rep.selStart.0 = rep.selStart.0 - numOfLinesAbove
         while rep.selStart.0 < rep.lines.length! and ((rep.lines.atIndex rep.selStart.0).text.indexOf 'data-tables') isnt -1
           currLineText = (rep.lines.atIndex rep.selStart.0).text
-          tblJSONObj = JSON.parse currLineText
+          tblJSONObj = fromEscapedJSON currLineText
           payload = tblJSONObj.payload
           cellPos = (@getTdInfo payload, currTd).cellEndOffset
           newText = '" ",'
@@ -1160,7 +1177,7 @@ if typeof Datatables is 'undefined'
       rep = @context.rep
       try
         currLineText = (rep.lines.atIndex rep.selStart.0).text
-        tblJSONObj = JSON.parse currLineText
+        tblJSONObj = fromEscapedJSON currLineText
         payload = tblJSONObj.payload
         deleteTable! if payload.0.length is 1
         currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
@@ -1175,7 +1192,7 @@ if typeof Datatables is 'undefined'
         rep.selEnd.0 = rep.selStart.0 = rep.selStart.0 - numOfLinesAbove
         while rep.selStart.0 < rep.lines.length! and ((rep.lines.atIndex rep.selStart.0).text.indexOf 'data-tables') isnt -1
           currLineText = (rep.lines.atIndex rep.selStart.0).text
-          tblJSONObj = JSON.parse currLineText
+          tblJSONObj = fromEscapedJSON currLineText
           payload = tblJSONObj.payload
           cellTdInfo = @getTdInfo payload, currTd
           newText = '" ",'
@@ -1204,7 +1221,7 @@ if typeof Datatables is 'undefined'
       currLineText = (rep.lines.atIndex rep.selStart.0).text
       payload = [[]]
       if not numOfRows and numOfRows isnt 0
-        tblPayload = (JSON.parse currLineText).payload
+        tblPayload = (fromEscapedJSON currLineText).payload
         numOfRows = tblPayload.0.length
       tblRows = new Array numOfRows
       if not (numOfRows is 0)
@@ -1223,7 +1240,7 @@ if typeof Datatables is 'undefined'
       }
       rep.selEnd.1 = rep.selStart.1 = currLineText.length
       @context.editorInfo.ace_inCallStackIfNecessary 'newline', @context.editorInfo.ace_doReturnKey
-      context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, JSON.stringify tableObj
+      context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, escapedJSON tableObj
     dt.doReturnKey = ->
       context = @context
       rep = context.rep
@@ -1249,8 +1266,8 @@ if typeof Datatables is 'undefined'
           start.1 = currCarretPos
           end.1 = currCarretPos
           (try
-            jsonObj = JSON.parse (currLineText.substring 0, start.1) + newText + currLineText.substring start.1
-            payloadStr = JSON.stringify jsonObj.payload
+            jsonObj = fromEscapedJSON (currLineText.substring 0, start.1) + newText + currLineText.substring start.1
+            payloadStr = escapedJSON jsonObj.payload
             return true if currCarretPos > payloadStr.length + @vars.OVERHEAD_LEN_PRE - 2
           catch error
             return true)
@@ -1267,7 +1284,7 @@ if typeof Datatables is 'undefined'
       return true if (currLineText.indexOf 'data-tables') is -1
       isDeleteAccepted = false
       (try
-        tblJSONObj = JSON.parse currLineText
+        tblJSONObj = fromEscapedJSON currLineText
         table = tblJSONObj.payload
         currTdInfo = @getFocusedTdInfo table, rep.selStart.1
         cellEntryLen = table[currTdInfo.row][currTdInfo.td].length
diff --git a/static/js/contentcollector.js b/static/js/contentcollector.js
index 1aa9901..152fcbe 100644
--- a/static/js/contentcollector.js
+++ b/static/js/contentcollector.js
@@ -16,20 +16,18 @@ exports.collectContentLineText = function(hook, context){
       if (n.tagName === 'TD') {
         elementName = n.getAttribute('name');
         if (elementName === 'tData') {
-          txt = txt.replace(/\\/g, '|');
-          txt = txt.replace(/"/g, '\'');
           break;
         } else {
           if (elementName === 'delimCell') {
-            txt = '","';
+            txt = '\uF134,\uF134';
             break;
           } else {
             if (elementName === 'payload') {
-              txt = '{"payload":[["';
+              txt = '{\uF134payload\uF134:[[\uF134';
               break;
             } else {
               if (elementName === 'bracketAndcomma') {
-                txt = '"]],"tblId":"1","tblClass":"data-tables"}';
+                txt = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134data-tables\uF134}';
                 break;
               }
             }
diff --git a/static/js/datatables-renderer.js b/static/js/datatables-renderer.js
index 1f3efbc..03aee5d 100644
--- a/static/js/datatables-renderer.js
+++ b/static/js/datatables-renderer.js
@@ -87,7 +87,7 @@ if (typeof DatatablesRenderer === 'undefined') {
           htmlTbl += '<tr style=\'vertical-align:' + rowVAlign + ';background-color:' + rowBgColor + '; ' + borders + '!important;\' class=\'' + trClass + '\'>';
           preHeader = '';
           if (j === 0) {
-            preHeader = '{"payload":[["';
+            preHeader = '{\uF134payload\uF134:[[\uF134';
           }
           htmlTbl += '<td  name=\'payload\' class=\'hide-el overhead\'>' + preHeader + '</td>';
           singleRowAttr = typeof singleRowAttrs === 'undefined' || singleRowAttrs == null
@@ -108,7 +108,7 @@ if (typeof DatatablesRenderer === 'undefined') {
             colVAlign = typeof colAttrs[i] === 'undefined' || colAttrs[i] == null
               ? ''
               : 'align=\'' + colAttrs[i].colVAlign + '\'' || '';
-            quoteAndComma = '","';
+            quoteAndComma = '\uF134,\uF134';
             cellDel = '';
             delimCell = '<td name=\'delimCell\' id=\'' + '\' class=\'hide-el overhead\'>' + quoteAndComma + '</td>';
             lastCellBorder = '';
@@ -135,7 +135,7 @@ if (typeof DatatablesRenderer === 'undefined') {
             }
             i++;
           }
-          bracketAndcomma = '"]],"tblId":"1","tblClass":"data-tables"}';
+          bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134data-tables\uF134}';
           htmlTbl += '<td name=\'bracketAndcomma\' class=\'  hide-el overhead\'>' + bracketAndcomma + '</td>';
           htmlTbl += '</tr>';
           j++;
@@ -232,7 +232,7 @@ if (typeof DatatablesRenderer === 'undefined') {
         JSONCode = '';
         html = '';
         try {
-          JSONCode = JSON.parse(code);
+          JSONCode = JSON.parse(code.replace(/(\\|")/g, '\\$1').replace(/\uF134/g, '"'));
           html = this.buildTabularData(JSONCode, attributes);
         } catch (e$) {
           e = e$;

From fff02013f52ac0b33fc9e5d43b1bafdffddcc5d7 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 30 Oct 2012 18:00:15 +0800
Subject: [PATCH 07/36] use \uFFF9 as tblclass rather than "data-tables"

---
 src/js/contentcollector.ls       |  2 +-
 src/js/datatables-renderer.ls    |  2 +-
 src/js/datatables.ls             | 50 +++++++++++++++++---------------
 src/js/linestylefilter.ls        |  4 +--
 static/js/contentcollector.js    |  2 +-
 static/js/datatables-renderer.js |  2 +-
 static/js/linestylefilter.js     |  2 +-
 7 files changed, 33 insertions(+), 31 deletions(-)

diff --git a/src/js/contentcollector.ls b/src/js/contentcollector.ls
index 921e0fe..e298171 100644
--- a/src/js/contentcollector.ls
+++ b/src/js/contentcollector.ls
@@ -23,7 +23,7 @@ exports.collectContentLineText = (hook, context) ->
               break
             else
               if elementName is 'bracketAndcomma'
-                txt = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134data-tables\uF134}'
+                txt = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}'
                 break
       n = n.parentNode
   txt
diff --git a/src/js/datatables-renderer.ls b/src/js/datatables-renderer.ls
index 018c7da..e9fb602 100644
--- a/src/js/datatables-renderer.ls
+++ b/src/js/datatables-renderer.ls
@@ -90,7 +90,7 @@ if typeof DatatablesRenderer is 'undefined'
             else
               htmlTbl += '<td name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + lastCellBorder + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + '\' >' + tds[i] + '' + '<br value=\'tblBreak\'></td>' + delimCell
             i++
-          bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134data-tables\uF134}'
+          bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}'
           htmlTbl += '<td name=\'bracketAndcomma\' class=\'  hide-el overhead\'>' + bracketAndcomma + '</td>'
           htmlTbl += '</tr>'
           j++
diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index f563ee9..833f7dd 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -9,7 +9,11 @@ exports.aceInitInnerdocbodyHead = (hook_name, args, cb) ->
 
 escapedJSON = ->
   ret = JSON.stringify it
-    .replace /\\(.)/g    (_, _1) -> "\\"+_1.charCodeAt(0)+\;
+    .replace /\\u(....)|\\(.)/g    (_, _1, _2) ->
+        if _1
+          String.fromCharCode parseInt _1, 16
+        else
+          "\\"+_1.charCodeAt(0)+\;
     .replace /"/g        '\uF134'
     .replace /\\(\d+);/g (_, _1) -> "\\"+String.fromCharCode(_1)
   #console.log ret
@@ -539,7 +543,7 @@ exports.acePostWriteDomLineHTML = (hook_name, args, cb) ->
     continue if (args.node.children[i].className.indexOf 'list') isnt -1 or (args.node.children[i].className.indexOf 'tag') isnt -1 or (args.node.children[i].className.indexOf 'url') isnt -1
     lineText = ''
     if args.node.children[i].innerText then lineText = args.node.children[i].innerText else lineText = args.node.children[i].textContent
-    if lineText and (lineText.indexOf 'data-tables') isnt -1
+    if lineText and (lineText.indexOf '\uFFF9') isnt -1
       dtAttrs = if typeof exports.Datatables isnt 'undefined' then exports.Datatables.attributes else null
       dtAttrs = dtAttrs or ''
       DatatablesRenderer.render {}, args.node.children[i], dtAttrs
@@ -663,7 +667,7 @@ if typeof Datatables is 'undefined'
       line = @context.rep.lines.atIndex @context.rep.selStart.0
       if not line then return false
       currLineText = line.text or ''
-      if (currLineText.indexOf 'data-tables') is -1 then return false
+      if (currLineText.indexOf '\uFFF9') is -1 then return false
       true
     dt._getRowEndOffset = (rowStartOffset, tds) ->
       rowEndOffset = rowStartOffset + @vars.OVERHEAD_LEN_ROW_START
@@ -718,7 +722,6 @@ if typeof Datatables is 'undefined'
       else
         switch cmd
         case Datatables.vars.TBL_OPTIONS.0
-          console.log xByY
           Datatables.addTable xByY
         case Datatables.vars.TBL_OPTIONS.1
           Datatables.insertTblRow 'addA'
@@ -751,11 +754,11 @@ if typeof Datatables is 'undefined'
         return 
       if line
         currLineText = line.text
-        if not ((currLineText.indexOf 'data-tables') is -1)
+        if not ((currLineText.indexOf '\uFFF9') is -1)
           while true
             rep.selStart.0 = rep.selStart.0 + 1
             currLineText = (rep.lines.atIndex rep.selStart.0).text
-            break if not ((currLineText.indexOf 'data-tables') isnt -1)
+            break if not ((currLineText.indexOf '\uFFF9') isnt -1)
           rep.selEnd.1 = rep.selStart.1 = currLineText.length
           @context.editorInfo.ace_doReturnKey!
           @context.editorInfo.ace_doReturnKey!
@@ -794,7 +797,6 @@ if typeof Datatables is 'undefined'
         newText = ''
         currLineText = (rep.lines.atIndex rep.selStart.0).text
         payload = (fromEscapedJSON currLineText).payload
-        console.log \zzz, payload
         currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
         currRow = currTdInfo.row
         lastRowOffSet = 0
@@ -823,11 +825,11 @@ if typeof Datatables is 'undefined'
         line = rep.selStart.0 - 1
         numOfLinesAbove = 0
         numOfLinesBelow = 0
-        while not (((rep.lines.atIndex line).text.indexOf 'data-tables') is -1)
+        while not (((rep.lines.atIndex line).text.indexOf '\uFFF9') is -1)
           numOfLinesAbove++
           line--
         line = rep.selEnd.0 + 1
-        while not (((rep.lines.atIndex line).text.indexOf 'data-tables') is -1)
+        while not (((rep.lines.atIndex line).text.indexOf '\uFFF9') is -1)
           numOfLinesBelow++
           line++
         rep.selStart.1 = 0
@@ -841,13 +843,13 @@ if typeof Datatables is 'undefined'
       rep = @context.rep
       try
         currLineText = (rep.lines.atIndex rep.selStart.0).text
-        return  if (currLineText.indexOf 'data-tables') is -1
+        return  if (currLineText.indexOf '\uFFF9') is -1
         rep.selEnd.0 = rep.selStart.0 + 1
         rep.selStart.1 = 0
         rep.selEnd.1 = 0
         @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
         currLineText = (rep.lines.atIndex rep.selStart.0).text
-        if (currLineText.indexOf 'data-tables') is -1 then return 
+        if (currLineText.indexOf '\uFFF9') is -1 then return 
         @updateAuthorAndCaretPos rep.selStart.0, 0, 0
         updateEvenOddBgColor = true
         @sanitizeTblProperties rep.selStart, updateEvenOddBgColor
@@ -870,7 +872,7 @@ if typeof Datatables is 'undefined'
         tempStart = []
         tempStart.0 = start.0 - numOfLinesAbove
         tempStart.1 = start.1
-        while tempStart.0 < rep.lines.length! and ((rep.lines.atIndex tempStart.0).text.indexOf 'data-tables') isnt -1
+        while tempStart.0 < rep.lines.length! and ((rep.lines.atIndex tempStart.0).text.indexOf '\uFFF9') isnt -1
           if props.tblEvenRowBgColor and tempStart.0 % 2 isnt 0
             tempStart.0 = tempStart.0 + 1
             continue
@@ -935,7 +937,7 @@ if typeof Datatables is 'undefined'
       return  if not start
       currLine = rep.lines.atIndex start.0
       currLineText = currLine.text
-      if (currLineText.indexOf 'data-tables') is -1 then return true
+      if (currLineText.indexOf '\uFFF9') is -1 then return true
       (try
         tblJSONObj = fromEscapedJSON currLineText
         tblProperties = @getLineTableProperty start.0
@@ -999,7 +1001,7 @@ if typeof Datatables is 'undefined'
       tableObj = {
         payload: payload
         tblId: 1
-        tblClass: 'data-tables'
+        tblClass: '\uFFF9'
         trClass: 'alst'
         tdClass: 'hide-el'
       }
@@ -1021,12 +1023,12 @@ if typeof Datatables is 'undefined'
       jsoTblProp = null
       if prevLine
         prevLineText = prevLine.text
-        jsoTblProp = @getLineTableProperty rep.selStart.0 - 1 if not ((prevLineText.indexOf 'data-tables') is -1)
+        jsoTblProp = @getLineTableProperty rep.selStart.0 - 1 if not ((prevLineText.indexOf '\uFFF9') is -1)
       if not jsoTblProp
         nextLine = rep.lines.atIndex rep.selEnd.0 - 1
         if nextLine
           nextLineText = nextLine.text
-          jsoTblProp = @getLineTableProperty rep.selStart.0 + 1 if not ((nextLineText.indexOf 'data-tables') is -1)
+          jsoTblProp = @getLineTableProperty rep.selStart.0 + 1 if not ((nextLineText.indexOf '\uFFF9') is -1)
       if jsoTblProp
         defTblProp.borderWidth = jsoTblProp.borderWidth
         defTblProp.borderColor = jsoTblProp.borderColor
@@ -1060,7 +1062,7 @@ if typeof Datatables is 'undefined'
           nextLine = rep.lines.atIndex rep.selStart.0 + 1
           nextLineText = nextLine.text
           updateEvenOddBgColor = false
-          if not nextLineText? or nextLineText is '' or (nextLineText.indexOf 'data-tables') is -1
+          if not nextLineText? or nextLineText is '' or (nextLineText.indexOf '\uFFF9') is -1
             @insertTblRowBelow null, null
             @performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties!
             rep.selEnd.1 = rep.selStart.1 = @vars.OVERHEAD_LEN_PRE
@@ -1146,7 +1148,7 @@ if typeof Datatables is 'undefined'
         currTd -= 1 if leftOrRight is 'addL'
         numOfLinesAbove = @getTblAboveRowsFromCurFocus start
         rep.selEnd.0 = rep.selStart.0 = rep.selStart.0 - numOfLinesAbove
-        while rep.selStart.0 < rep.lines.length! and ((rep.lines.atIndex rep.selStart.0).text.indexOf 'data-tables') isnt -1
+        while rep.selStart.0 < rep.lines.length! and ((rep.lines.atIndex rep.selStart.0).text.indexOf '\uFFF9') isnt -1
           currLineText = (rep.lines.atIndex rep.selStart.0).text
           tblJSONObj = fromEscapedJSON currLineText
           payload = tblJSONObj.payload
@@ -1190,7 +1192,7 @@ if typeof Datatables is 'undefined'
         end.1 = rep.selEnd.1
         numOfLinesAbove = @getTblAboveRowsFromCurFocus start
         rep.selEnd.0 = rep.selStart.0 = rep.selStart.0 - numOfLinesAbove
-        while rep.selStart.0 < rep.lines.length! and ((rep.lines.atIndex rep.selStart.0).text.indexOf 'data-tables') isnt -1
+        while rep.selStart.0 < rep.lines.length! and ((rep.lines.atIndex rep.selStart.0).text.indexOf '\uFFF9') isnt -1
           currLineText = (rep.lines.atIndex rep.selStart.0).text
           tblJSONObj = fromEscapedJSON currLineText
           payload = tblJSONObj.payload
@@ -1234,7 +1236,7 @@ if typeof Datatables is 'undefined'
       tableObj = {
         payload: payload
         tblId: 1
-        tblClass: 'data-tables'
+        tblClass: '\uFFF9'
         trClass: 'alst'
         tdClass: 'hide-el'
       }
@@ -1249,7 +1251,7 @@ if typeof Datatables is 'undefined'
       lastTblPropertyUsed = 'doTableReturnKey'
       currLine = rep.lines.atIndex rep.selStart.0
       currLineText = currLine.text
-      if not ((currLineText.indexOf 'data-tables') is -1)
+      if not ((currLineText.indexOf '\uFFF9') is -1)
         func = 'doTableReturnKey()'
         try
           currCarretPos = rep.selStart.1
@@ -1281,7 +1283,7 @@ if typeof Datatables is 'undefined'
       end = rep.selEnd
       currLine = rep.lines.atIndex rep.selStart.0
       currLineText = currLine.text
-      return true if (currLineText.indexOf 'data-tables') is -1
+      return true if (currLineText.indexOf '\uFFF9') is -1
       isDeleteAccepted = false
       (try
         tblJSONObj = fromEscapedJSON currLineText
@@ -1438,7 +1440,7 @@ if typeof Datatables is 'undefined'
       rep = @context.rep
       numOfLinesAbove = 0
       line = start.0 - 1
-      while not (((rep.lines.atIndex line).text.indexOf 'data-tables') is -1)
+      while not (((rep.lines.atIndex line).text.indexOf '\uFFF9') is -1)
         numOfLinesAbove++
         line--
       numOfLinesAbove
@@ -1462,7 +1464,7 @@ if typeof Datatables is 'undefined'
       tempStart.0 = start.0 - numOfLinesAbove
       evenOddRowBgColors = {}
       updateEvenOddBgColor
-      while tempStart.0 < rep.lines.length! and ((rep.lines.atIndex tempStart.0).text.indexOf 'data-tables') isnt -1
+      while tempStart.0 < rep.lines.length! and ((rep.lines.atIndex tempStart.0).text.indexOf '\uFFF9') isnt -1
         jsoTblProp = @getLineTableProperty tempStart.0
         update = false
         if tempStart.0 isnt start.0 and jsoTblProp.'authors' and jsoTblProp.'authors'[thisAuthor]
diff --git a/src/js/linestylefilter.ls b/src/js/linestylefilter.ls
index 587bbb3..f9d229f 100644
--- a/src/js/linestylefilter.ls
+++ b/src/js/linestylefilter.ls
@@ -1,5 +1,5 @@
 exports.disableAuthorColorsForThisLine = (hook, context) ->
   lineText = context.text
   disableLineColors = false
-  disableLineColors = true if lineText and (lineText.indexOf 'data-tables') isnt -1
-  disableLineColors
\ No newline at end of file
+  disableLineColors = true if lineText and (lineText.indexOf '\uFFF9') isnt -1
+  disableLineColors
diff --git a/static/js/contentcollector.js b/static/js/contentcollector.js
index 152fcbe..044216c 100644
--- a/static/js/contentcollector.js
+++ b/static/js/contentcollector.js
@@ -27,7 +27,7 @@ exports.collectContentLineText = function(hook, context){
               break;
             } else {
               if (elementName === 'bracketAndcomma') {
-                txt = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134data-tables\uF134}';
+                txt = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}';
                 break;
               }
             }
diff --git a/static/js/datatables-renderer.js b/static/js/datatables-renderer.js
index 03aee5d..23cf3b3 100644
--- a/static/js/datatables-renderer.js
+++ b/static/js/datatables-renderer.js
@@ -135,7 +135,7 @@ if (typeof DatatablesRenderer === 'undefined') {
             }
             i++;
           }
-          bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134data-tables\uF134}';
+          bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}';
           htmlTbl += '<td name=\'bracketAndcomma\' class=\'  hide-el overhead\'>' + bracketAndcomma + '</td>';
           htmlTbl += '</tr>';
           j++;
diff --git a/static/js/linestylefilter.js b/static/js/linestylefilter.js
index 5b9cecf..f688f29 100644
--- a/static/js/linestylefilter.js
+++ b/static/js/linestylefilter.js
@@ -2,7 +2,7 @@ exports.disableAuthorColorsForThisLine = function(hook, context){
   var lineText, disableLineColors;
   lineText = context.text;
   disableLineColors = false;
-  if (lineText && lineText.indexOf('data-tables') !== -1) {
+  if (lineText && lineText.indexOf('\uFFF9') !== -1) {
     disableLineColors = true;
   }
   return disableLineColors;

From 7a48223e1dd42fd310306ca7d3bc41e7fcd43f48 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 30 Oct 2012 18:17:52 +0800
Subject: [PATCH 08/36] modern class for DatatableRenderer

---
 src/js/datatables-renderer.ls    |  21 +-
 static/js/datatables-renderer.js | 462 +++++++++++++++----------------
 2 files changed, 241 insertions(+), 242 deletions(-)

diff --git a/src/js/datatables-renderer.ls b/src/js/datatables-renderer.ls
index e9fb602..3379b8c 100644
--- a/src/js/datatables-renderer.ls
+++ b/src/js/datatables-renderer.ls
@@ -1,11 +1,12 @@
-if typeof DatatablesRenderer is 'undefined'
-  DatatablesRenderer = do ->
-    dRenderer = {render: (params, element, attributes) ->
-      renderer = new DatatablesRenderer.Renderer
-      if element.innerText then code = element.innerText else code = element.textContent
-      element.innerHTML = renderer.getHtml code, attributes}
-    dRenderer.Renderer = ->
-    dRenderer.Renderer.prototype = {
+DatatablesRenderer = {}
+class DatatablesRenderer
+  @render = (params, element, attributes) ->
+    renderer = new DatatablesRenderer.Renderer
+    if element.innerText then code = element.innerText else code = element.textContent
+    element.innerHTML = renderer.getHtml code, attributes
+
+  class @Renderer
+      ->
       createDefaultTblProperties: (authors) ->
         {
           borderWidth: '1'
@@ -148,7 +149,5 @@ if typeof DatatablesRenderer is 'undefined'
           html = @buildTabularData JSONCode, attributes
         catch
         html
-    }
-    dRenderer
 
-if typeof exports isnt 'undefined' then exports.DatatablesRenderer = DatatablesRenderer else null
+exports?DatatablesRenderer = DatatablesRenderer
diff --git a/static/js/datatables-renderer.js b/static/js/datatables-renderer.js
index 23cf3b3..4bd2ad4 100644
--- a/static/js/datatables-renderer.js
+++ b/static/js/datatables-renderer.js
@@ -1,250 +1,250 @@
 var DatatablesRenderer;
-if (typeof DatatablesRenderer === 'undefined') {
-  DatatablesRenderer = function(){
-    var dRenderer;
-    dRenderer = {
-      render: function(params, element, attributes){
-        var renderer, code;
-        renderer = new DatatablesRenderer.Renderer;
-        if (element.innerText) {
-          code = element.innerText;
-        } else {
-          code = element.textContent;
-        }
-        return element.innerHTML = renderer.getHtml(code, attributes);
-      }
+DatatablesRenderer = {};
+DatatablesRenderer = (function(){
+  DatatablesRenderer.displayName = 'DatatablesRenderer';
+  var Renderer, prototype = DatatablesRenderer.prototype, constructor = DatatablesRenderer;
+  DatatablesRenderer.render = function(params, element, attributes){
+    var renderer, code;
+    renderer = new DatatablesRenderer.Renderer;
+    if (element.innerText) {
+      code = element.innerText;
+    } else {
+      code = element.textContent;
+    }
+    return element.innerHTML = renderer.getHtml(code, attributes);
+  };
+  DatatablesRenderer.Renderer = Renderer = (function(){
+    Renderer.displayName = 'Renderer';
+    var prototype = Renderer.prototype, constructor = Renderer;
+    function Renderer(){}
+    prototype.createDefaultTblProperties = function(authors){
+      return {
+        borderWidth: '1',
+        cellAttrs: [],
+        width: '6',
+        rowAttrs: {},
+        colAttrs: [],
+        authors: {}
+      };
     };
-    dRenderer.Renderer = function(){};
-    dRenderer.Renderer.prototype = {
-      createDefaultTblProperties: function(authors){
-        return {
-          borderWidth: '1',
-          cellAttrs: [],
-          width: '6',
-          rowAttrs: {},
-          colAttrs: [],
-          authors: {}
-        };
-      },
-      buildTabularData: function(tblJSONObj, tblPropsJSString){
-        var htmlTbl, tblId, tblClass, tdClass, trClass, payload, tblProperties, error, rowAttrs, singleRowAttrs, cellAttrs, colAttrs, tblWidth, tblHeight, tblBorderWidth, tblBorderColor, currRow, currCell, authors, printViewTBlStyles, printViewTblTDStyles, borders, rowVAlign, rows, evenRowBgColor, oddRowBgColor, j, rl, tds, rowBgColor, preHeader, singleRowAttr, i, tl, cellAttr, cellStyles, authorBorderColor, borderTop, colVAlign, quoteAndComma, cellDel, delimCell, lastCellBorder, cellsWithBr, tdText, k, bracketAndcomma;
-        htmlTbl = '';
-        tblId = tblJSONObj.tblId;
-        tblClass = tblJSONObj.tblClass;
-        tdClass = tblJSONObj.tdClass;
-        trClass = tblJSONObj.trClass;
-        payload = tblJSONObj.payload;
-        tblProperties = {};
-        try {
-          tblProperties = JSON.parse(tblPropsJSString);
-        } catch (e$) {
-          error = e$;
-          tblProperties = this.createDefaultTblProperties();
+    prototype.buildTabularData = function(tblJSONObj, tblPropsJSString){
+      var htmlTbl, tblId, tblClass, tdClass, trClass, payload, tblProperties, error, rowAttrs, singleRowAttrs, cellAttrs, colAttrs, tblWidth, tblHeight, tblBorderWidth, tblBorderColor, currRow, currCell, authors, printViewTBlStyles, printViewTblTDStyles, borders, rowVAlign, rows, evenRowBgColor, oddRowBgColor, j, rl, tds, rowBgColor, preHeader, singleRowAttr, i, tl, cellAttr, cellStyles, authorBorderColor, borderTop, colVAlign, quoteAndComma, cellDel, delimCell, lastCellBorder, cellsWithBr, tdText, k, bracketAndcomma;
+      htmlTbl = '';
+      tblId = tblJSONObj.tblId;
+      tblClass = tblJSONObj.tblClass;
+      tdClass = tblJSONObj.tdClass;
+      trClass = tblJSONObj.trClass;
+      payload = tblJSONObj.payload;
+      tblProperties = {};
+      try {
+        tblProperties = JSON.parse(tblPropsJSString);
+      } catch (e$) {
+        error = e$;
+        tblProperties = this.createDefaultTblProperties();
+      }
+      rowAttrs = tblProperties.rowAttrs;
+      singleRowAttrs = rowAttrs.singleRowAttrs;
+      cellAttrs = tblProperties.cellAttrs;
+      colAttrs = tblProperties.colAttrs;
+      tblWidth = typeof tblProperties === 'undefined' || tblProperties == null
+        ? '1'
+        : tblProperties.width || '1';
+      tblWidth = this.getAttrInInch(tblWidth);
+      tblHeight = typeof tblProperties === 'undefined' || tblProperties == null
+        ? '.1'
+        : tblProperties.height || '.1';
+      tblHeight = this.getAttrInInch(tblHeight);
+      tblBorderWidth = typeof tblProperties === 'undefined' || tblProperties == null
+        ? 0
+        : tblProperties.borderWidth || 0;
+      tblBorderColor = typeof tblProperties === 'undefined' || tblProperties == null
+        ? '#000000'
+        : tblProperties.borderColor || '#000000';
+      currRow = tblProperties.currRowAuthorIdx;
+      currCell = tblProperties.currCellAuthorIdx;
+      authors = tblProperties.authors;
+      printViewTBlStyles = 'table-layout:fixed !important;border-collapse:collapse!important;font-family:Trebuchet MS!important;';
+      printViewTblTDStyles = 'font-size: 1em!important;line-height: 1em!important;padding: 3px 7px 2px!important;word-wrap: break-word!important;';
+      htmlTbl = '<table class=\'' + tblClass + '\' style=\'' + printViewTBlStyles + 'background-color:white;width:' + tblWidth + 'px!important;height:' + tblHeight + 'px!important; border-top: ' + tblBorderWidth + 'px solid ' + tblBorderColor + '!important;' + '\'><tbody>';
+      borders = 'border-bottom:' + tblBorderWidth + 'px solid ' + tblBorderColor;
+      rowVAlign = typeof rowAttrs === 'undefined' || rowAttrs == null
+        ? 'left'
+        : rowAttrs.rowVAlign || 'left';
+      rows = tblJSONObj.payload;
+      evenRowBgColor = typeof rowAttrs === 'undefined' || rowAttrs == null
+        ? '#FFFFFF'
+        : rowAttrs.evenBgColor || '#FFFFFF';
+      oddRowBgColor = typeof rowAttrs === 'undefined' || rowAttrs == null
+        ? null
+        : rowAttrs.oddBgColor || null;
+      j = 0;
+      rl = rows.length;
+      while (j < rl) {
+        tds = rows[j];
+        rowBgColor = oddRowBgColor;
+        if (!rowBgColor) {
+          rowBgColor = evenRowBgColor;
         }
-        rowAttrs = tblProperties.rowAttrs;
-        singleRowAttrs = rowAttrs.singleRowAttrs;
-        cellAttrs = tblProperties.cellAttrs;
-        colAttrs = tblProperties.colAttrs;
-        tblWidth = typeof tblProperties === 'undefined' || tblProperties == null
-          ? '1'
-          : tblProperties.width || '1';
-        tblWidth = this.getAttrInInch(tblWidth);
-        tblHeight = typeof tblProperties === 'undefined' || tblProperties == null
-          ? '.1'
-          : tblProperties.height || '.1';
-        tblHeight = this.getAttrInInch(tblHeight);
-        tblBorderWidth = typeof tblProperties === 'undefined' || tblProperties == null
-          ? 0
-          : tblProperties.borderWidth || 0;
-        tblBorderColor = typeof tblProperties === 'undefined' || tblProperties == null
-          ? '#000000'
-          : tblProperties.borderColor || '#000000';
-        currRow = tblProperties.currRowAuthorIdx;
-        currCell = tblProperties.currCellAuthorIdx;
-        authors = tblProperties.authors;
-        printViewTBlStyles = 'table-layout:fixed !important;border-collapse:collapse!important;font-family:Trebuchet MS!important;';
-        printViewTblTDStyles = 'font-size: 1em!important;line-height: 1em!important;padding: 3px 7px 2px!important;word-wrap: break-word!important;';
-        htmlTbl = '<table class=\'' + tblClass + '\' style=\'' + printViewTBlStyles + 'background-color:white;width:' + tblWidth + 'px!important;height:' + tblHeight + 'px!important; border-top: ' + tblBorderWidth + 'px solid ' + tblBorderColor + '!important;' + '\'><tbody>';
-        borders = 'border-bottom:' + tblBorderWidth + 'px solid ' + tblBorderColor;
-        rowVAlign = typeof rowAttrs === 'undefined' || rowAttrs == null
-          ? 'left'
-          : rowAttrs.rowVAlign || 'left';
-        rows = tblJSONObj.payload;
-        evenRowBgColor = typeof rowAttrs === 'undefined' || rowAttrs == null
-          ? '#FFFFFF'
-          : rowAttrs.evenBgColor || '#FFFFFF';
-        oddRowBgColor = typeof rowAttrs === 'undefined' || rowAttrs == null
+        htmlTbl += '<tr style=\'vertical-align:' + rowVAlign + ';background-color:' + rowBgColor + '; ' + borders + '!important;\' class=\'' + trClass + '\'>';
+        preHeader = '';
+        if (j === 0) {
+          preHeader = '{\uF134payload\uF134:[[\uF134';
+        }
+        htmlTbl += '<td  name=\'payload\' class=\'hide-el overhead\'>' + preHeader + '</td>';
+        singleRowAttr = typeof singleRowAttrs === 'undefined' || singleRowAttrs == null
           ? null
-          : rowAttrs.oddBgColor || null;
-        j = 0;
-        rl = rows.length;
-        while (j < rl) {
-          tds = rows[j];
-          rowBgColor = oddRowBgColor;
-          if (!rowBgColor) {
-            rowBgColor = evenRowBgColor;
+          : singleRowAttrs[j];
+        i = 0;
+        tl = tds.length;
+        while (i < tl) {
+          cellAttr = typeof cellAttrs[j] === 'undefined' || cellAttrs[j] == null
+            ? null
+            : cellAttrs[j][i];
+          cellStyles = this.getCellAttrs(singleRowAttr, cellAttr, colAttrs[i], authors, i, j);
+          authorBorderColor = this.getCellAuthorColors(authors, i, j, tblBorderWidth) + '!important;';
+          borderTop = '';
+          if (tblBorderWidth === 0) {
+            borderTop = ' border-top: 0px solid white !important;';
           }
-          htmlTbl += '<tr style=\'vertical-align:' + rowVAlign + ';background-color:' + rowBgColor + '; ' + borders + '!important;\' class=\'' + trClass + '\'>';
-          preHeader = '';
-          if (j === 0) {
-            preHeader = '{\uF134payload\uF134:[[\uF134';
+          colVAlign = typeof colAttrs[i] === 'undefined' || colAttrs[i] == null
+            ? ''
+            : 'align=\'' + colAttrs[i].colVAlign + '\'' || '';
+          quoteAndComma = '\uF134,\uF134';
+          cellDel = '';
+          delimCell = '<td name=\'delimCell\' id=\'' + '\' class=\'hide-el overhead\'>' + quoteAndComma + '</td>';
+          lastCellBorder = '';
+          if (i === tl - 1) {
+            delimCell = '';
+            lastCellBorder = 'border-right:' + tblBorderWidth + 'px solid ' + tblBorderColor + '!important;';
+            quoteAndComma = '';
           }
-          htmlTbl += '<td  name=\'payload\' class=\'hide-el overhead\'>' + preHeader + '</td>';
-          singleRowAttr = typeof singleRowAttrs === 'undefined' || singleRowAttrs == null
-            ? null
-            : singleRowAttrs[j];
-          i = 0;
-          tl = tds.length;
-          while (i < tl) {
-            cellAttr = typeof cellAttrs[j] === 'undefined' || cellAttrs[j] == null
-              ? null
-              : cellAttrs[j][i];
-            cellStyles = this.getCellAttrs(singleRowAttr, cellAttr, colAttrs[i], authors, i, j);
-            authorBorderColor = this.getCellAuthorColors(authors, i, j, tblBorderWidth) + '!important;';
-            borderTop = '';
-            if (tblBorderWidth === 0) {
-              borderTop = ' border-top: 0px solid white !important;';
-            }
-            colVAlign = typeof colAttrs[i] === 'undefined' || colAttrs[i] == null
-              ? ''
-              : 'align=\'' + colAttrs[i].colVAlign + '\'' || '';
-            quoteAndComma = '\uF134,\uF134';
-            cellDel = '';
-            delimCell = '<td name=\'delimCell\' id=\'' + '\' class=\'hide-el overhead\'>' + quoteAndComma + '</td>';
-            lastCellBorder = '';
-            if (i === tl - 1) {
-              delimCell = '';
-              lastCellBorder = 'border-right:' + tblBorderWidth + 'px solid ' + tblBorderColor + '!important;';
-              quoteAndComma = '';
-            }
-            if (!(tds[i].indexOf('/r/n') === -1)) {
-              cellsWithBr = '';
-              tdText = tds[i].split('/r/n');
-              k = 0;
-              while (k < tdText.length) {
-                if (k < tdText.length - 1) {
-                  cellsWithBr += tdText[k] + '<label value=\'tblBreak\' class=\'hide-el\'>/r/n</label><label class=\'tblBreak\'></label>';
-                } else {
-                  cellsWithBr += tdText[k];
-                }
-                k++;
+          if (!(tds[i].indexOf('/r/n') === -1)) {
+            cellsWithBr = '';
+            tdText = tds[i].split('/r/n');
+            k = 0;
+            while (k < tdText.length) {
+              if (k < tdText.length - 1) {
+                cellsWithBr += tdText[k] + '<label value=\'tblBreak\' class=\'hide-el\'>/r/n</label><label class=\'tblBreak\'></label>';
+              } else {
+                cellsWithBr += tdText[k];
               }
-              htmlTbl += '<td  name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + lastCellBorder + '\' >' + cellsWithBr + '<br value=\'tblBreak\'></td>' + delimCell;
-            } else {
-              htmlTbl += '<td name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + lastCellBorder + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + '\' >' + tds[i] + '' + '<br value=\'tblBreak\'></td>' + delimCell;
-            }
-            i++;
-          }
-          bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}';
-          htmlTbl += '<td name=\'bracketAndcomma\' class=\'  hide-el overhead\'>' + bracketAndcomma + '</td>';
-          htmlTbl += '</tr>';
-          j++;
-        }
-        htmlTbl += '</tbody></table>';
-        return htmlTbl;
-      },
-      getCellAuthorColors: function(authors, cell, row, tblBorderWidth){
-        var cellBorderColor, authorId, author, borderWidth;
-        cellBorderColor = null;
-        if (typeof authors !== 'undefined' && authors != null) {
-          for (authorId in authors) {
-            author = authors[authorId];
-            if (typeof author !== 'undefined' && author != null && author.cell === cell && author.row === row) {
-              cellBorderColor = author.colorId;
+              k++;
             }
+            htmlTbl += '<td  name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + lastCellBorder + '\' >' + cellsWithBr + '<br value=\'tblBreak\'></td>' + delimCell;
+          } else {
+            htmlTbl += '<td name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + lastCellBorder + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + '\' >' + tds[i] + '' + '<br value=\'tblBreak\'></td>' + delimCell;
           }
+          i++;
         }
-        borderWidth = tblBorderWidth !== 0 ? tblBorderWidth : 1;
-        cellBorderColor = cellBorderColor == null
-          ? ''
-          : ';border:' + borderWidth + 'px solid ' + cellBorderColor;
-        return cellBorderColor;
-      },
-      getCellAttrs: function(singleRowAttr, cellAttr, colAttr, authors, cell, row){
-        var attrsJSO, colWidth, cellBgColor, bgColor, cellHeight, cellPadding, cellVAlign, cellFontSize, cellFontWeight, cellFontStyle, cellTextDecoration, attrsString, attrName;
-        attrsJSO = {};
-        colWidth = typeof colAttr === 'undefined' || colAttr == null
-          ? '1'
-          : colAttr.width || '1';
-        attrsJSO['width'] = this.getAttrInInch(colWidth) + 'px';
-        cellBgColor = '';
-        if (typeof singleRowAttr !== 'undefined' && singleRowAttr != null) {
-          bgColor = singleRowAttr.bgColor;
-          if (typeof bgColor !== 'undefined' && bgColor != null && bgColor !== '#FFFFFF') {
-            cellBgColor = bgColor;
+        bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}';
+        htmlTbl += '<td name=\'bracketAndcomma\' class=\'  hide-el overhead\'>' + bracketAndcomma + '</td>';
+        htmlTbl += '</tr>';
+        j++;
+      }
+      htmlTbl += '</tbody></table>';
+      return htmlTbl;
+    };
+    prototype.getCellAuthorColors = function(authors, cell, row, tblBorderWidth){
+      var cellBorderColor, authorId, author, borderWidth;
+      cellBorderColor = null;
+      if (typeof authors !== 'undefined' && authors != null) {
+        for (authorId in authors) {
+          author = authors[authorId];
+          if (typeof author !== 'undefined' && author != null && author.cell === cell && author.row === row) {
+            cellBorderColor = author.colorId;
           }
         }
-        if (typeof colAttr !== 'undefined' && colAttr != null) {
-          bgColor = colAttr.bgColor;
-          if (typeof bgColor !== 'undefined' && bgColor != null && bgColor !== '#FFFFFF') {
-            cellBgColor = bgColor;
-          }
+      }
+      borderWidth = tblBorderWidth !== 0 ? tblBorderWidth : 1;
+      cellBorderColor = cellBorderColor == null
+        ? ''
+        : ';border:' + borderWidth + 'px solid ' + cellBorderColor;
+      return cellBorderColor;
+    };
+    prototype.getCellAttrs = function(singleRowAttr, cellAttr, colAttr, authors, cell, row){
+      var attrsJSO, colWidth, cellBgColor, bgColor, cellHeight, cellPadding, cellVAlign, cellFontSize, cellFontWeight, cellFontStyle, cellTextDecoration, attrsString, attrName;
+      attrsJSO = {};
+      colWidth = typeof colAttr === 'undefined' || colAttr == null
+        ? '1'
+        : colAttr.width || '1';
+      attrsJSO['width'] = this.getAttrInInch(colWidth) + 'px';
+      cellBgColor = '';
+      if (typeof singleRowAttr !== 'undefined' && singleRowAttr != null) {
+        bgColor = singleRowAttr.bgColor;
+        if (typeof bgColor !== 'undefined' && bgColor != null && bgColor !== '#FFFFFF') {
+          cellBgColor = bgColor;
         }
-        cellBgColor = typeof cellAttr === 'undefined' || cellAttr == null
-          ? cellBgColor
-          : cellAttr.bgColor || cellBgColor;
-        attrsJSO['background-color'] = cellBgColor;
-        cellHeight = typeof cellAttr === 'undefined' || cellAttr == null
-          ? ''
-          : cellAttr.height || '';
-        attrsJSO['height'] = this.getAttrInInch(cellHeight) + 'px';
-        cellPadding = typeof cellAttr === 'undefined' || cellAttr == null
-          ? ''
-          : cellAttr.padding || '';
-        attrsJSO['padding-top'] = attrsJSO['padding-bottom'] = attrsJSO['padding-left'] = attrsJSO['padding-right'] = this.getAttrInInch(cellPadding) + 'px';
-        cellVAlign = typeof cellAttr === 'undefined' || cellAttr == null
-          ? ''
-          : cellAttr.vAlign || '';
-        attrsJSO['vertical-align'] = cellVAlign;
-        cellFontSize = typeof cellAttr === 'undefined' || cellAttr == null
-          ? ''
-          : cellAttr.fontSize || '';
-        attrsJSO['font-size'] = cellFontSize + 'px';
-        cellFontWeight = typeof cellAttr === 'undefined' || cellAttr == null
-          ? ''
-          : cellAttr.fontWeight || '';
-        attrsJSO['font-weight'] = cellFontWeight;
-        cellFontStyle = typeof cellAttr === 'undefined' || cellAttr == null
-          ? ''
-          : cellAttr.fontStyle || '';
-        attrsJSO['font-style'] = cellFontStyle;
-        cellTextDecoration = typeof cellAttr === 'undefined' || cellAttr == null
-          ? ''
-          : cellAttr.textDecoration || '';
-        attrsJSO['text-decoration'] = cellTextDecoration;
-        attrsString = '';
-        for (attrName in attrsJSO) {
-          if (attrName && attrsJSO[attrName] !== '' && attrsJSO[attrName] !== 'NaNpx' && attrsJSO[attrName] !== 'px') {
-            attrsString += attrName + ':' + attrsJSO[attrName] + ' !important;';
-          }
+      }
+      if (typeof colAttr !== 'undefined' && colAttr != null) {
+        bgColor = colAttr.bgColor;
+        if (typeof bgColor !== 'undefined' && bgColor != null && bgColor !== '#FFFFFF') {
+          cellBgColor = bgColor;
         }
-        return attrsString;
-      },
-      getAttrInInch: function(attrValue){
-        var intAttrValue;
-        intAttrValue = 0;
-        intAttrValue = parseFloat(attrValue);
-        attrValue = isNaN(intAttrValue) ? parseFloat(attrValue) : intAttrValue;
-        return 96 * attrValue - 1;
-      },
-      getHtml: function(code, attributes){
-        var JSONCode, html, e;
-        JSONCode = '';
-        html = '';
-        try {
-          JSONCode = JSON.parse(code.replace(/(\\|")/g, '\\$1').replace(/\uF134/g, '"'));
-          html = this.buildTabularData(JSONCode, attributes);
-        } catch (e$) {
-          e = e$;
+      }
+      cellBgColor = typeof cellAttr === 'undefined' || cellAttr == null
+        ? cellBgColor
+        : cellAttr.bgColor || cellBgColor;
+      attrsJSO['background-color'] = cellBgColor;
+      cellHeight = typeof cellAttr === 'undefined' || cellAttr == null
+        ? ''
+        : cellAttr.height || '';
+      attrsJSO['height'] = this.getAttrInInch(cellHeight) + 'px';
+      cellPadding = typeof cellAttr === 'undefined' || cellAttr == null
+        ? ''
+        : cellAttr.padding || '';
+      attrsJSO['padding-top'] = attrsJSO['padding-bottom'] = attrsJSO['padding-left'] = attrsJSO['padding-right'] = this.getAttrInInch(cellPadding) + 'px';
+      cellVAlign = typeof cellAttr === 'undefined' || cellAttr == null
+        ? ''
+        : cellAttr.vAlign || '';
+      attrsJSO['vertical-align'] = cellVAlign;
+      cellFontSize = typeof cellAttr === 'undefined' || cellAttr == null
+        ? ''
+        : cellAttr.fontSize || '';
+      attrsJSO['font-size'] = cellFontSize + 'px';
+      cellFontWeight = typeof cellAttr === 'undefined' || cellAttr == null
+        ? ''
+        : cellAttr.fontWeight || '';
+      attrsJSO['font-weight'] = cellFontWeight;
+      cellFontStyle = typeof cellAttr === 'undefined' || cellAttr == null
+        ? ''
+        : cellAttr.fontStyle || '';
+      attrsJSO['font-style'] = cellFontStyle;
+      cellTextDecoration = typeof cellAttr === 'undefined' || cellAttr == null
+        ? ''
+        : cellAttr.textDecoration || '';
+      attrsJSO['text-decoration'] = cellTextDecoration;
+      attrsString = '';
+      for (attrName in attrsJSO) {
+        if (attrName && attrsJSO[attrName] !== '' && attrsJSO[attrName] !== 'NaNpx' && attrsJSO[attrName] !== 'px') {
+          attrsString += attrName + ':' + attrsJSO[attrName] + ' !important;';
         }
-        return html;
       }
+      return attrsString;
+    };
+    prototype.getAttrInInch = function(attrValue){
+      var intAttrValue;
+      intAttrValue = 0;
+      intAttrValue = parseFloat(attrValue);
+      attrValue = isNaN(intAttrValue) ? parseFloat(attrValue) : intAttrValue;
+      return 96 * attrValue - 1;
+    };
+    prototype.getHtml = function(code, attributes){
+      var JSONCode, html, e;
+      JSONCode = '';
+      html = '';
+      try {
+        JSONCode = JSON.parse(code.replace(/(\\|")/g, '\\$1').replace(/\uF134/g, '"'));
+        html = this.buildTabularData(JSONCode, attributes);
+      } catch (e$) {
+        e = e$;
+      }
+      return html;
     };
-    return dRenderer;
-  }();
-}
-if (typeof exports !== 'undefined') {
+    return Renderer;
+  }());
+  function DatatablesRenderer(){}
+  return DatatablesRenderer;
+}());
+if (typeof exports != 'undefined' && exports !== null) {
   exports.DatatablesRenderer = DatatablesRenderer;
-} else {
-  null;
 }
\ No newline at end of file

From 934b8db147e7164115b78376dacf8d4605804dde Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Wed, 31 Oct 2012 14:11:33 +0800
Subject: [PATCH 09/36] split menu hook into datatables-ui

---
 ep.json                    |    4 +-
 src/js/datatables-ui.ls    |  508 +++++++++++++
 src/js/datatables.ls       |  509 -------------
 static/js/datatables-ui.js |  689 ++++++++++++++++++
 static/js/datatables.js    | 1376 ++++++++++++++++++++++++++++++++++++
 5 files changed, 2575 insertions(+), 511 deletions(-)
 create mode 100644 src/js/datatables-ui.ls
 create mode 100644 static/js/datatables-ui.js
 create mode 100644 static/js/datatables.js

diff --git a/ep.json b/ep.json
index c4185e2..1f2a130 100644
--- a/ep.json
+++ b/ep.json
@@ -9,7 +9,7 @@
 
 		},
 		"client_hooks" : {			
-			"aceInitInnerdocbodyHead": "ep_tables/static/js/datatables:aceInitInnerdocbodyHead",
+			"aceInitInnerdocbodyHead": "ep_tables/static/js/datatables-ui.js:aceInitInnerdocbodyHead",
 		 	"collectContentLineBreak": "ep_tables/static/js/contentcollector:collectContentLineBreak",
 		 	"collectContentLineText": "ep_tables/static/js/contentcollector:collectContentLineText",
 			"aceKeyEvent": "ep_tables/static/js/datatables.js:aceKeyEvent",
@@ -18,7 +18,7 @@
 			"aceAttribsToClasses": "ep_tables/static/js/datatables.js:aceAttribsToClasses",
 			"acePostWriteDomLineHTML": "ep_tables/static/js/datatables:acePostWriteDomLineHTML",
 			"aceInitialized": "ep_tables/static/js/datatables:aceInitialized",
-			"postAceInit": "ep_tables/static/js/datatables:postAceInit",
+			"postAceInit": "ep_tables/static/js/datatables-ui.js:postAceInit",
 			"disableAuthorColorsForThisLine": "ep_tables/static/js/linestylefilter:disableAuthorColorsForThisLine"
 				
 		}
diff --git a/src/js/datatables-ui.ls b/src/js/datatables-ui.ls
new file mode 100644
index 0000000..8c2fd4d
--- /dev/null
+++ b/src/js/datatables-ui.ls
@@ -0,0 +1,508 @@
+exports.aceInitInnerdocbodyHead = (hook_name, args, cb) ->
+  args.iframeHTML.push '<link rel="stylesheet" type="text/css" href="/static/plugins/ep_tables/static/css/dataTables.css"/>'
+
+exports.postAceInit = (hook, context) ->
+  $.createTableMenu = (init) ->
+    showTblPropPanel = ->
+      if not $.tblPropDialog
+        $.tblPropDialog = new YAHOO.widget.Dialog 'yui-tbl-prop-panel', {
+          width: '600px'
+          height: '450px'
+          close: true
+          visible: false
+          zindex: 1001
+          constraintoviewport: true
+        }
+        $.tblPropDialog.setBody $.getTblPropertiesHTML!
+        $.tblPropDialog.render!
+        $.alignMenu $.tblPropDialog, @id
+        initTableProperties!
+      $.tblPropDialog.show!
+    createColorPicker = ->
+      createOColorPicker = ->
+        $.oColorPicker = new YAHOO.widget.ColorPicker 'color-picker-menu', {
+          showhsvcontrols: false
+          showrgbcontrols: false
+          showwebsafe: false
+          showhexsummary: false
+          showhexcontrols: true
+          images: {
+            PICKER_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/picker_thumb.png'
+            HUE_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/hue_thumb.png'
+          }
+        }
+        $.oColorPicker.on 'rgbChange', colorPickerButtonClick
+        $.colorPickerAligned = true
+      handleColorPickerSubmit = -> colorPickerButtonClick $.oColorPicker.get 'hex'
+      handleDialogCancel = -> @cancel!
+      $.oColorPickerDialog = new YAHOO.widget.Dialog 'yui-picker-panel', {
+        width: '500px'
+        close: true
+        visible: false
+        zindex: 1002
+        constraintoviewport: true
+        buttons: [{
+          text: 'Exit'
+          handler: @handleDialogCancel
+        }]
+      }
+      $.oColorPickerDialog.renderEvent.subscribe (-> createOColorPicker! if not $.oColorPicker)
+      $.oColorPickerDialog.render!
+      $.oColorPickerDialog.show!
+    colorPickerButtonClick = (sColor) ->
+      if typeof sColor is 'string' and sColor? and (sColor.indexOf '#') is -1
+        sColor = '#' + sColor
+      else
+        if typeof sColor is 'object' then sColor = if not (@get 'hex')? then @get 'value' else '#' + @get 'hex'
+      selParams = {
+        borderWidth: null
+        tblPropertyChange: true
+      }
+      switch $.tblfocusedProperty
+      case 'tbl_border_color'
+        selParams.tblBorderColor = true
+        selParams.attrName = 'borderColor'
+        $.borderColorPickerButton.set 'value', sColor
+        ($ '#current-color').css 'backgroundColor', sColor
+        ($ '#current-color').innerHTML = 'Current color is ' + sColor
+      case 'tbl_cell_bg_color'
+        selParams.tblCellBgColor = true
+        selParams.attrName = 'bgColor'
+        $.cellBgColorPickerButton.set 'value', sColor
+        ($ '#current-cell-bg-color').css 'backgroundColor', sColor
+        ($ '#current-cell-bg-color').innerHTML = 'Current color is ' + sColor
+      case 'tbl_even_row_bg_color'
+        selParams.tblEvenRowBgColor = true
+        selParams.attrName = 'evenBgColor'
+        $.evenRowBgColorPickerButton.set 'value', sColor
+        ($ '#even-row-bg-color').css 'backgroundColor', sColor
+        ($ '#even-row-bg-color').innerHTML = 'Current color is ' + sColor
+      case 'tbl_odd_row_bg_color'
+        selParams.tblOddRowBgColor = true
+        selParams.attrName = 'oddBgColor'
+        $.oddRowBgColorPickerButton.set 'value', sColor
+        ($ '#odd-row-bg-color').css 'backgroundColor', sColor
+        ($ '#odd-row-bg-color').innerHTML = 'Current color is ' + sColor
+      case 'tbl_single_row_bg_color'
+        selParams.tblSingleRowBgColor = true
+        selParams.attrName = 'bgColor'
+        $.singleRowBgColorPickerButton.set 'value', sColor
+        ($ '#single-row-bg-color').css 'backgroundColor', sColor
+        ($ '#single-row-bg-color').innerHTML = 'Current color is ' + sColor
+      case 'tbl_single_col_bg_color'
+        selParams.tblSingleColBgColor = true
+        selParams.attrName = 'bgColor'
+        $.singleColBgColorPickerButton.set 'value', sColor
+        ($ '#single-col-bg-color').css 'backgroundColor', sColor
+        ($ '#single-col-bg-color').innerHTML = 'Current color is ' + sColor
+      selParams.attrValue = sColor
+      context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
+    top.templatesMenu.hide! if not (typeof top.templatesMenu is 'undefined')
+    if $.tblContextMenu
+      $.alignMenu $.tblContextMenu, 'tbl-menu'
+      $.tblContextMenu.show!
+      return 
+    $.handleTableBorder = (selectValue) ->
+      selParams = {
+        tblBorderWidth: true
+        attrName: 'borderWidth'
+        attrValue: selectValue
+        tblPropertyChange: true
+      }
+      context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
+    $.getTblPropertiesHTML = ->
+      '<span id=\'table_properties\'><span class=\'tbl-prop-menu-header\'></span><br><span id=\'tbl-prop-menu\'class=\'tbl-prop-menu\'>' + '<table class=\'left-tbl-props tbl-inline-block\'>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>Table border</span></td></tr>' + '<tr><td><span class=\'tbl-inline-block\' id=\'tbl_border_color\'> </span><span id=\'tbl_border_width\'class=\'tbl-inline-block tbl_border_width\'></span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Cell background color</span></td></tr><tr><td><span id=\'tbl_cell_bg_color\'></td></tr><tr><td></span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Even/Odd Row background color</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_even_row_bg_color\'>Even   </span><span id=\'tbl_odd_row_bg_color\' class=\'tbl-inline-block\'>Odd</span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Single Row/Col background color</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_single_row_bg_color\'>Single Row   </span><span id=\'tbl_single_col_bg_color\' class=\'tbl-inline-block\'>Single Col</span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Row/Col alignment</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_row_v_align\'>Row align </span><span id=\'tbl_col_v_align\' class=\'tbl-inline-block\'>Col align</span></td></tr>' + '</table>' + '\t<span class=\' tbl-inline-block\'>' + '\t\t<span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + 'Dimensions(Inches) ' + '\t\t</span>  <span id=\'text_input_message\'></span>' + '\t\t<table class=\'tbl-prop-dim\'>' + '\t\t\t<tbody>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Table width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Table height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Column width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_col_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Minimum row height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_row_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label >Cell padding</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_cell_padding\' type=\'text\' size=\'4\' class=\'text-input\'>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t</tbody>' + '\t\t</table>' + '\t\t<br> ' + '\t\t<span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + '\t\t\tFonts ' + '\t\t</span>' + '\t\t<table class=\'tbl-prop-dim\'>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label >Cell font size</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'select-font-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_cell_font_size\' type=\'text\' size=\'4\' class=\'text-input\'>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t</tbody>' + '\t\t</table>' + '\t</span>' + '</span>' + '</span>' + '<span id=\'img_properties\'>' + '<span class=\'tbl-prop-menu-header\'></span><span id=\'img-prop-menu\'class=\'tbl-prop-menu\'>' + '<table class=\'left-tbl-props tbl-inline-block\'>' + '\t\t<caption><span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + '\t\t\tDimensions(Intches) ' + '\t\t</span></caption>' + '\t\t\t<tbody>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Image width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'img_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Image height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'img_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '</table>' + '</span>' + '</span>'
+    if typeof $.tblContextMenu is 'undefined'
+      initTableProperties = ->
+        colVAligns = [
+          'Left'
+          'Center'
+          'Right'
+        ]
+        $.colVAlignsMenu = new YAHOO.widget.ContextMenu 'tbl_col_v_align_menu', {
+          iframe: true
+          zindex: 1003
+          shadow: false
+          position: 'dynamic'
+          keepopen: true
+          clicktohide: true
+        }
+        $.colVAlignsMenu.addItems colVAligns
+        $.colVAlignsMenu.render document.body
+        $.colVAlignsMenu.subscribe 'click', (p_sType, p_aArgs) ->
+          oEvent = p_aArgs.0
+          oMenuItem = p_aArgs.1
+          if oMenuItem
+            align = oMenuItem.cfg.getProperty 'text'
+            selParams = {
+              tblColVAlign: true
+              attrName: 'colVAlign'
+              attrValue: align
+              tblPropertyChange: true
+            }
+            $.colVAlignsMenuButton.set 'value', selParams.attrValue
+            ($ '#current-col-v-alignment').html align
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
+        $.colVAlignsMenuButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em id="current-col-v-alignment">Left</em>'
+          container: 'tbl_col_v_align'
+        }
+        ($ '#tbl_col_v_align').click (->
+          aligned = false
+          $.alignMenu $.colVAlignsMenu, 'tbl_col_v_align' if not aligned
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          if $.oColorPickerDialog then $.oColorPickerDialog.hide!
+          $.colVAlignsMenu.show!
+          vAlignValue = $.colVAlignsMenuButton.get 'value'
+          if vAlignValue
+            selParams = {
+              tblColVAlign: true
+              attrName: 'colVAlign'
+              attrValue: vAlignValue
+              tblPropertyChange: true
+            }
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
+        rowVAligns = [
+          'Top'
+          'Center'
+          'Bottom'
+        ]
+        $.rowVAlignsMenu = new YAHOO.widget.ContextMenu 'tbl_row_v_align_menu', {
+          iframe: true
+          zindex: 1003
+          shadow: false
+          position: 'dynamic'
+          keepopen: true
+          clicktohide: true
+        }
+        $.rowVAlignsMenu.addItems rowVAligns
+        $.rowVAlignsMenu.render document.body
+        $.rowVAlignsMenu.subscribe 'click', (p_sType, p_aArgs) ->
+          oEvent = p_aArgs.0
+          oMenuItem = p_aArgs.1
+          if oMenuItem
+            align = oMenuItem.cfg.getProperty 'text'
+            selParams = {
+              tblRowVAlign: true
+              attrName: 'rowVAlign'
+              attrValue: align
+              tblPropertyChange: true
+            }
+            $.rowVAlignsMenuButton.set 'value', selParams.attrValue
+            ($ '#current-v-alignment').html align
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
+        $.rowVAlignsMenuButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em id="current-v-alignment">Top</em>'
+          container: 'tbl_row_v_align'
+        }
+        ($ '#tbl_row_v_align').click (->
+          aligned = false
+          $.alignMenu $.rowVAlignsMenu, 'tbl_row_v_align' if not aligned
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          if $.oColorPickerDialog then $.oColorPickerDialog.hide!
+          $.rowVAlignsMenu.show!
+          vAlignValue = $.rowVAlignsMenuButton.get 'value'
+          if vAlignValue
+            selParams = {
+              tblRowVAlign: true
+              attrName: 'rowVAlign'
+              attrValue: vAlignValue
+              tblPropertyChange: true
+            }
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
+        borderWidths = [
+          '0px'
+          '1px'
+          '2px'
+          '3px'
+          '4px'
+          '5px'
+          '6px'
+          '7px'
+          '8px'
+        ]
+        $.borderWidthsMenu = new YAHOO.widget.ContextMenu 'tbl_border_width_menu', {
+          iframe: true
+          zindex: 1003
+          shadow: false
+          position: 'dynamic'
+          keepopen: true
+          clicktohide: true
+        }
+        $.borderWidthsMenu.addItems borderWidths
+        $.borderWidthsMenu.render document.body
+        $.borderWidthsMenu.subscribe 'click', (p_sType, p_aArgs) ->
+          oEvent = p_aArgs.0
+          oMenuItem = p_aArgs.1
+          if oMenuItem
+            borderReq = oMenuItem.cfg.getProperty 'text'
+            selParams = {
+              tblBorderWidth: true
+              attrName: 'borderWidth'
+              attrValue: borderReq.substring 0, borderReq.indexOf 'px'
+              tblPropertyChange: true
+            }
+            $.borderWidthPickerButton.set 'value', selParams.attrValue
+            ($ '#current-width').html borderReq
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
+        $.borderWidthPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em id="current-width">1px</em>'
+          container: 'tbl_border_width'
+        }
+        ($ '#tbl_border_width').click (->
+          aligned = false
+          $.alignMenu $.borderWidthsMenu, 'tbl_border_width' if not aligned
+          if $.oColorPickerDialog then $.oColorPickerDialog.hide!
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          $.borderWidthsMenu.show!
+          widthValue = $.borderWidthPickerButton.get 'value'
+          if widthValue
+            selParams = {
+              tblBorderWidth: true
+              attrName: 'borderWidth'
+              attrValue: widthValue
+              tblPropertyChange: true
+            }
+            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
+        $.tblfocusedProperty = ''
+        ($ '#tbl_properties').click (->
+          $.borderWidthsMenu.hide! if not (typeof $.borderWidthsMenu is 'undefined')
+          if not (typeof $.oColorPickerDialog is 'undefined') then $.oColorPickerDialog.hide!
+          if not (typeof $.rowVAlignsMenu is 'undefined') then $.rowVAlignsMenu.hide!)
+        $.colorPickerAligned = false
+        ($ '#tbl_border_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_border_color'
+          $.tblfocusedProperty = 'tbl_border_color'
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Table Border color'
+          $.oColorPickerDialog.show!
+          hexValue = $.borderColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        $.borderColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em  class=\'color-picker-button\' id="current-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_border_color'
+        }
+        $.cellBgColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em class=\'color-picker-button\' id="current-cell-bg-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_cell_bg_color'
+        }
+        ($ '#tbl_cell_bg_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_cell_bg_color'
+          $.tblfocusedProperty = 'tbl_cell_bg_color'
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Cell Background color'
+          $.oColorPickerDialog.show!
+          hexValue = $.cellBgColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        $.evenRowBgColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em class=\'color-picker-button\' id="even-row-bg-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_even_row_bg_color'
+        }
+        ($ '#tbl_even_row_bg_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_even_row_bg_color'
+          $.tblfocusedProperty = 'tbl_even_row_bg_color'
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Even Row Background color'
+          $.oColorPickerDialog.show!
+          hexValue = $.evenRowBgColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        $.oddRowBgColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em class=\'color-picker-button\' id="odd-row-bg-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_odd_row_bg_color'
+        }
+        ($ '#tbl_odd_row_bg_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_odd_row_bg_color'
+          $.tblfocusedProperty = 'tbl_odd_row_bg_color'
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Odd Row Background color'
+          $.oColorPickerDialog.show!
+          hexValue = $.oddRowBgColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        $.singleRowBgColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em class=\'color-picker-button\' id="single-row-bg-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_single_row_bg_color'
+        }
+        ($ '#tbl_single_row_bg_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_single_row_bg_color'
+          $.tblfocusedProperty = 'tbl_single_row_bg_color'
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Single Row Background color'
+          $.oColorPickerDialog.show!
+          hexValue = $.singleRowBgColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        $.singleColBgColorPickerButton = new YAHOO.widget.Button {
+          disabled: false
+          type: 'split'
+          label: '<em class=\'color-picker-button\' id="single-col-bg-color">Current color is #FFFFFF.</em>'
+          container: 'tbl_single_col_bg_color'
+        }
+        ($ '#tbl_single_col_bg_color').click (->
+          createColorPicker! if not $.colorPickerAligned
+          $.alignMenu $.oColorPickerDialog, 'tbl_single_col_bg_color'
+          $.tblfocusedProperty = 'tbl_single_col_bg_color'
+          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
+          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
+          $.oColorPickerDialog.setHeader 'Please choose a color for: Single Column Background color'
+          $.oColorPickerDialog.show!
+          hexValue = $.singleColBgColorPickerButton.get 'value'
+          if hexValue then colorPickerButtonClick hexValue)
+        ($ '.text-input').change (->
+          selParams = {tblPropertyChange: true}
+          if @id is 'tbl_width'
+            selParams.tblWidth = true
+            selParams.attrName = 'width'
+          else
+            if @id is 'tbl_height'
+              selParams.tblHeight = true
+              selParams.attrName = 'height'
+            else
+              if @id is 'tbl_col_width'
+                selParams.tblColWidth = true
+                selParams.attrName = 'width'
+              else
+                if @id is 'tbl_row_height'
+                  selParams.tblCellHeight = true
+                  selParams.attrName = 'height'
+                else
+                  if @id is 'tbl_cell_padding'
+                    selParams.tblCellPadding = true
+                    selParams.attrName = 'padding'
+                  else
+                    if @id is 'tbl_cell_font_size'
+                      selParams.tblCellFontSize = true
+                      selParams.attrName = 'fontSize'
+                    else
+                      if @id is 'img_width'
+                        selParams.imgWidth = true
+                        selParams.attrName = 'width'
+                      else
+                        if @id is 'img_height'
+                          selParams.imgHeight = true
+                          selParams.attrName = 'height'
+          selParams.attrValue = @value
+          @value = ''
+          ($ '#text_input_message').text 'Ok'
+          ($ '#text_input_message').removeAttr 'style'
+          ($ '#text_input_message').fadeOut 'slow'
+          context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
+      matrixTable = '<table id=\'matrix_table\'class=\'matrix-table\'><caption></caption>    <tr value=1><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=2 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=3 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=4><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=5 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=6><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=7><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=8><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=9><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=10><td height=10 value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr></table>'
+      $.tblContextMenu = new YAHOO.widget.ContextMenu 'tbl_context_menu', {
+        iframe: true
+        zindex: 500
+        shadow: false
+        position: 'dynamic'
+        keepopen: true
+        clicktohide: true
+      }
+      $.tblContextMenu.addItems [
+        [{
+          text: 'Insert Table'
+          submenu: {
+            id: 'tbl_insert'
+            itemData: ['<div id=\'select_matrix\'>0 X 0</div>']
+          }
+        }]
+        [
+          'Insert Row Above'
+          'Insert Row Below'
+          'Insert Column Right'
+          'Insert Column Left'
+        ]
+        [
+          'Delete Row'
+          'Delete Column'
+          'Delete Table'
+        ]
+        [{
+          id: 'tbl_prop_menu_item'
+          text: 'Table Properties'
+          onclick: {fn: showTblPropPanel}
+        }]
+      ]
+      subMenus = $.tblContextMenu.getSubmenus!
+      subMenus.0.setFooter matrixTable
+      $.tblContextMenu.render document.body
+      $.alignMenu = (menu, id, addX, addY, scrollY) ->
+        region = YAHOO.util.Dom.getRegion id
+        if typeof id is 'string' and (id is 'tbl-menu' or id is 'upload_image_cont')
+          menu.cfg.setProperty 'xy', [region.left, region.bottom]
+        else
+          if typeof id is 'string' then menu.cfg.setProperty 'xy', [region.right, region.top] else menu.cfg.setProperty 'xy', [30 + addX, 36 + addY - scrollY]
+      ($ 'table td').hover (->
+        x = 0
+        while x <= ($ this).index!
+          y = 0
+          while y <= ($ this).parent!.index!
+            ((($ this).parent!.parent!.children!.eq y).children!.eq x).addClass 'selected'
+            y++
+          x++), -> ($ 'table td').removeClass 'selected'
+      ($ 'table td').hover (->
+        xVal = @getAttribute 'value'
+        yVal = (($ this).closest 'tr').0.getAttribute 'value'
+        ($ '#select_matrix').html xVal + ' X ' + yVal)
+      ($ 'td', '#matrix_table').click ((e) ->
+        context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions 'addTbl', 'addTblX' + ($ '#select_matrix').text!), 'tblOptions', true
+        false)
+      $.tblContextMenu.subscribe 'click', (p_sType, p_aArgs) ->
+        oEvent = p_aArgs.0
+        oMenuItem = p_aArgs.1
+        if oMenuItem
+          tblReq = oMenuItem.cfg.getProperty 'text'
+          disabled = oMenuItem.cfg.getProperty 'disabled'
+          return  if disabled
+          id = ''
+          switch tblReq
+          case 'Insert Table'
+            id = 'addTbl'
+          case 'Insert Row Above'
+            id = 'addTblRowA'
+          case 'Insert Row Below'
+            id = 'addTblRowB'
+          case 'Insert Column Left'
+            id = 'addTblColL'
+          case 'Insert Column Right'
+            id = 'addTblColR'
+          case 'Delete Table'
+            id = 'delTbl'
+          case 'Delete Image'
+            id = 'delImg'
+          case 'Delete Row'
+            id = 'delTblRow'
+          case 'Delete Column'
+            id = 'delTblCol'
+          context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions id), 'tblOptions', true
+          false
+    if not init
+      $.alignMenu $.tblContextMenu, 'tbl-menu'
+      $.tblContextMenu.show!
+  ($ '#tbl-menu').click $.createTableMenu
+  YAHOO.util.Dom.addClass document.body, 'yui-skin-sam'
+  ($ 'body').append $ '<div id="yui-picker-panel" class="yui-picker-panel">' + '<div class="hd">Please choose a color:</div>' + '<div class="bd">' + '\t<div class="yui-picker" id="color-picker-menu"></div>' + '</div>' + '<div class="ft"></div>' + '</div>'
+  ($ 'body').append $ '<div id="yui-tbl-prop-panel" class="yui-picker-panel">' + '<div class="hd">Table/Image Properties</div>' + '<div class="bd">' + '\t<div class="yui-picker" id="tbl-props"></div>' + '</div>' + '<div class="ft"></div>' + '</div>'
+  $.createTableMenu true
diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index 833f7dd..c4f3de3 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -4,9 +4,6 @@ if not (typeof require is 'undefined')
   Ace2Common = require 'ep_etherpad-lite/static/js/ace2_common' if typeof Ace2Common is 'undefined'
   if typeof Changeset is 'undefined' then Changeset = require 'ep_etherpad-lite/static/js/Changeset'
 
-exports.aceInitInnerdocbodyHead = (hook_name, args, cb) ->
-  args.iframeHTML.push '<link rel="stylesheet" type="text/css" href="/static/plugins/ep_tables/static/css/dataTables.css"/>'
-
 escapedJSON = ->
   ret = JSON.stringify it
     .replace /\\u(....)|\\(.)/g    (_, _1, _2) ->
@@ -26,512 +23,6 @@ fromEscapedJSON = ->
   #console.trace \fromEscape
   ret
 
-exports.postAceInit = (hook, context) ->
-  $.createTableMenu = (init) ->
-    showTblPropPanel = ->
-      if not $.tblPropDialog
-        $.tblPropDialog = new YAHOO.widget.Dialog 'yui-tbl-prop-panel', {
-          width: '600px'
-          height: '450px'
-          close: true
-          visible: false
-          zindex: 1001
-          constraintoviewport: true
-        }
-        $.tblPropDialog.setBody $.getTblPropertiesHTML!
-        $.tblPropDialog.render!
-        $.alignMenu $.tblPropDialog, @id
-        initTableProperties!
-      $.tblPropDialog.show!
-    createColorPicker = ->
-      createOColorPicker = ->
-        $.oColorPicker = new YAHOO.widget.ColorPicker 'color-picker-menu', {
-          showhsvcontrols: false
-          showrgbcontrols: false
-          showwebsafe: false
-          showhexsummary: false
-          showhexcontrols: true
-          images: {
-            PICKER_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/picker_thumb.png'
-            HUE_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/hue_thumb.png'
-          }
-        }
-        $.oColorPicker.on 'rgbChange', colorPickerButtonClick
-        $.colorPickerAligned = true
-      handleColorPickerSubmit = -> colorPickerButtonClick $.oColorPicker.get 'hex'
-      handleDialogCancel = -> @cancel!
-      $.oColorPickerDialog = new YAHOO.widget.Dialog 'yui-picker-panel', {
-        width: '500px'
-        close: true
-        visible: false
-        zindex: 1002
-        constraintoviewport: true
-        buttons: [{
-          text: 'Exit'
-          handler: @handleDialogCancel
-        }]
-      }
-      $.oColorPickerDialog.renderEvent.subscribe (-> createOColorPicker! if not $.oColorPicker)
-      $.oColorPickerDialog.render!
-      $.oColorPickerDialog.show!
-    colorPickerButtonClick = (sColor) ->
-      if typeof sColor is 'string' and sColor? and (sColor.indexOf '#') is -1
-        sColor = '#' + sColor
-      else
-        if typeof sColor is 'object' then sColor = if not (@get 'hex')? then @get 'value' else '#' + @get 'hex'
-      selParams = {
-        borderWidth: null
-        tblPropertyChange: true
-      }
-      switch $.tblfocusedProperty
-      case 'tbl_border_color'
-        selParams.tblBorderColor = true
-        selParams.attrName = 'borderColor'
-        $.borderColorPickerButton.set 'value', sColor
-        ($ '#current-color').css 'backgroundColor', sColor
-        ($ '#current-color').innerHTML = 'Current color is ' + sColor
-      case 'tbl_cell_bg_color'
-        selParams.tblCellBgColor = true
-        selParams.attrName = 'bgColor'
-        $.cellBgColorPickerButton.set 'value', sColor
-        ($ '#current-cell-bg-color').css 'backgroundColor', sColor
-        ($ '#current-cell-bg-color').innerHTML = 'Current color is ' + sColor
-      case 'tbl_even_row_bg_color'
-        selParams.tblEvenRowBgColor = true
-        selParams.attrName = 'evenBgColor'
-        $.evenRowBgColorPickerButton.set 'value', sColor
-        ($ '#even-row-bg-color').css 'backgroundColor', sColor
-        ($ '#even-row-bg-color').innerHTML = 'Current color is ' + sColor
-      case 'tbl_odd_row_bg_color'
-        selParams.tblOddRowBgColor = true
-        selParams.attrName = 'oddBgColor'
-        $.oddRowBgColorPickerButton.set 'value', sColor
-        ($ '#odd-row-bg-color').css 'backgroundColor', sColor
-        ($ '#odd-row-bg-color').innerHTML = 'Current color is ' + sColor
-      case 'tbl_single_row_bg_color'
-        selParams.tblSingleRowBgColor = true
-        selParams.attrName = 'bgColor'
-        $.singleRowBgColorPickerButton.set 'value', sColor
-        ($ '#single-row-bg-color').css 'backgroundColor', sColor
-        ($ '#single-row-bg-color').innerHTML = 'Current color is ' + sColor
-      case 'tbl_single_col_bg_color'
-        selParams.tblSingleColBgColor = true
-        selParams.attrName = 'bgColor'
-        $.singleColBgColorPickerButton.set 'value', sColor
-        ($ '#single-col-bg-color').css 'backgroundColor', sColor
-        ($ '#single-col-bg-color').innerHTML = 'Current color is ' + sColor
-      selParams.attrValue = sColor
-      context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
-    top.templatesMenu.hide! if not (typeof top.templatesMenu is 'undefined')
-    if $.tblContextMenu
-      $.alignMenu $.tblContextMenu, 'tbl-menu'
-      $.tblContextMenu.show!
-      return 
-    $.handleTableBorder = (selectValue) ->
-      selParams = {
-        tblBorderWidth: true
-        attrName: 'borderWidth'
-        attrValue: selectValue
-        tblPropertyChange: true
-      }
-      context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
-    $.getTblPropertiesHTML = ->
-      '<span id=\'table_properties\'><span class=\'tbl-prop-menu-header\'></span><br><span id=\'tbl-prop-menu\'class=\'tbl-prop-menu\'>' + '<table class=\'left-tbl-props tbl-inline-block\'>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>Table border</span></td></tr>' + '<tr><td><span class=\'tbl-inline-block\' id=\'tbl_border_color\'> </span><span id=\'tbl_border_width\'class=\'tbl-inline-block tbl_border_width\'></span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Cell background color</span></td></tr><tr><td><span id=\'tbl_cell_bg_color\'></td></tr><tr><td></span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Even/Odd Row background color</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_even_row_bg_color\'>Even   </span><span id=\'tbl_odd_row_bg_color\' class=\'tbl-inline-block\'>Odd</span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Single Row/Col background color</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_single_row_bg_color\'>Single Row   </span><span id=\'tbl_single_col_bg_color\' class=\'tbl-inline-block\'>Single Col</span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Row/Col alignment</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_row_v_align\'>Row align </span><span id=\'tbl_col_v_align\' class=\'tbl-inline-block\'>Col align</span></td></tr>' + '</table>' + '\t<span class=\' tbl-inline-block\'>' + '\t\t<span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + 'Dimensions(Inches) ' + '\t\t</span>  <span id=\'text_input_message\'></span>' + '\t\t<table class=\'tbl-prop-dim\'>' + '\t\t\t<tbody>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Table width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Table height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Column width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_col_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Minimum row height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_row_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label >Cell padding</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_cell_padding\' type=\'text\' size=\'4\' class=\'text-input\'>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t</tbody>' + '\t\t</table>' + '\t\t<br> ' + '\t\t<span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + '\t\t\tFonts ' + '\t\t</span>' + '\t\t<table class=\'tbl-prop-dim\'>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label >Cell font size</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'select-font-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_cell_font_size\' type=\'text\' size=\'4\' class=\'text-input\'>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t</tbody>' + '\t\t</table>' + '\t</span>' + '</span>' + '</span>' + '<span id=\'img_properties\'>' + '<span class=\'tbl-prop-menu-header\'></span><span id=\'img-prop-menu\'class=\'tbl-prop-menu\'>' + '<table class=\'left-tbl-props tbl-inline-block\'>' + '\t\t<caption><span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + '\t\t\tDimensions(Intches) ' + '\t\t</span></caption>' + '\t\t\t<tbody>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Image width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'img_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Image height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'img_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '</table>' + '</span>' + '</span>'
-    if typeof $.tblContextMenu is 'undefined'
-      initTableProperties = ->
-        colVAligns = [
-          'Left'
-          'Center'
-          'Right'
-        ]
-        $.colVAlignsMenu = new YAHOO.widget.ContextMenu 'tbl_col_v_align_menu', {
-          iframe: true
-          zindex: 1003
-          shadow: false
-          position: 'dynamic'
-          keepopen: true
-          clicktohide: true
-        }
-        $.colVAlignsMenu.addItems colVAligns
-        $.colVAlignsMenu.render document.body
-        $.colVAlignsMenu.subscribe 'click', (p_sType, p_aArgs) ->
-          oEvent = p_aArgs.0
-          oMenuItem = p_aArgs.1
-          if oMenuItem
-            align = oMenuItem.cfg.getProperty 'text'
-            selParams = {
-              tblColVAlign: true
-              attrName: 'colVAlign'
-              attrValue: align
-              tblPropertyChange: true
-            }
-            $.colVAlignsMenuButton.set 'value', selParams.attrValue
-            ($ '#current-col-v-alignment').html align
-            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
-        $.colVAlignsMenuButton = new YAHOO.widget.Button {
-          disabled: false
-          type: 'split'
-          label: '<em id="current-col-v-alignment">Left</em>'
-          container: 'tbl_col_v_align'
-        }
-        ($ '#tbl_col_v_align').click (->
-          aligned = false
-          $.alignMenu $.colVAlignsMenu, 'tbl_col_v_align' if not aligned
-          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
-          if $.oColorPickerDialog then $.oColorPickerDialog.hide!
-          $.colVAlignsMenu.show!
-          vAlignValue = $.colVAlignsMenuButton.get 'value'
-          if vAlignValue
-            selParams = {
-              tblColVAlign: true
-              attrName: 'colVAlign'
-              attrValue: vAlignValue
-              tblPropertyChange: true
-            }
-            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
-        rowVAligns = [
-          'Top'
-          'Center'
-          'Bottom'
-        ]
-        $.rowVAlignsMenu = new YAHOO.widget.ContextMenu 'tbl_row_v_align_menu', {
-          iframe: true
-          zindex: 1003
-          shadow: false
-          position: 'dynamic'
-          keepopen: true
-          clicktohide: true
-        }
-        $.rowVAlignsMenu.addItems rowVAligns
-        $.rowVAlignsMenu.render document.body
-        $.rowVAlignsMenu.subscribe 'click', (p_sType, p_aArgs) ->
-          oEvent = p_aArgs.0
-          oMenuItem = p_aArgs.1
-          if oMenuItem
-            align = oMenuItem.cfg.getProperty 'text'
-            selParams = {
-              tblRowVAlign: true
-              attrName: 'rowVAlign'
-              attrValue: align
-              tblPropertyChange: true
-            }
-            $.rowVAlignsMenuButton.set 'value', selParams.attrValue
-            ($ '#current-v-alignment').html align
-            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
-        $.rowVAlignsMenuButton = new YAHOO.widget.Button {
-          disabled: false
-          type: 'split'
-          label: '<em id="current-v-alignment">Top</em>'
-          container: 'tbl_row_v_align'
-        }
-        ($ '#tbl_row_v_align').click (->
-          aligned = false
-          $.alignMenu $.rowVAlignsMenu, 'tbl_row_v_align' if not aligned
-          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
-          if $.oColorPickerDialog then $.oColorPickerDialog.hide!
-          $.rowVAlignsMenu.show!
-          vAlignValue = $.rowVAlignsMenuButton.get 'value'
-          if vAlignValue
-            selParams = {
-              tblRowVAlign: true
-              attrName: 'rowVAlign'
-              attrValue: vAlignValue
-              tblPropertyChange: true
-            }
-            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
-        borderWidths = [
-          '0px'
-          '1px'
-          '2px'
-          '3px'
-          '4px'
-          '5px'
-          '6px'
-          '7px'
-          '8px'
-        ]
-        $.borderWidthsMenu = new YAHOO.widget.ContextMenu 'tbl_border_width_menu', {
-          iframe: true
-          zindex: 1003
-          shadow: false
-          position: 'dynamic'
-          keepopen: true
-          clicktohide: true
-        }
-        $.borderWidthsMenu.addItems borderWidths
-        $.borderWidthsMenu.render document.body
-        $.borderWidthsMenu.subscribe 'click', (p_sType, p_aArgs) ->
-          oEvent = p_aArgs.0
-          oMenuItem = p_aArgs.1
-          if oMenuItem
-            borderReq = oMenuItem.cfg.getProperty 'text'
-            selParams = {
-              tblBorderWidth: true
-              attrName: 'borderWidth'
-              attrValue: borderReq.substring 0, borderReq.indexOf 'px'
-              tblPropertyChange: true
-            }
-            $.borderWidthPickerButton.set 'value', selParams.attrValue
-            ($ '#current-width').html borderReq
-            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true
-        $.borderWidthPickerButton = new YAHOO.widget.Button {
-          disabled: false
-          type: 'split'
-          label: '<em id="current-width">1px</em>'
-          container: 'tbl_border_width'
-        }
-        ($ '#tbl_border_width').click (->
-          aligned = false
-          $.alignMenu $.borderWidthsMenu, 'tbl_border_width' if not aligned
-          if $.oColorPickerDialog then $.oColorPickerDialog.hide!
-          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
-          $.borderWidthsMenu.show!
-          widthValue = $.borderWidthPickerButton.get 'value'
-          if widthValue
-            selParams = {
-              tblBorderWidth: true
-              attrName: 'borderWidth'
-              attrValue: widthValue
-              tblPropertyChange: true
-            }
-            context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
-        $.tblfocusedProperty = ''
-        ($ '#tbl_properties').click (->
-          $.borderWidthsMenu.hide! if not (typeof $.borderWidthsMenu is 'undefined')
-          if not (typeof $.oColorPickerDialog is 'undefined') then $.oColorPickerDialog.hide!
-          if not (typeof $.rowVAlignsMenu is 'undefined') then $.rowVAlignsMenu.hide!)
-        $.colorPickerAligned = false
-        ($ '#tbl_border_color').click (->
-          createColorPicker! if not $.colorPickerAligned
-          $.alignMenu $.oColorPickerDialog, 'tbl_border_color'
-          $.tblfocusedProperty = 'tbl_border_color'
-          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
-          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
-          $.oColorPickerDialog.setHeader 'Please choose a color for: Table Border color'
-          $.oColorPickerDialog.show!
-          hexValue = $.borderColorPickerButton.get 'value'
-          if hexValue then colorPickerButtonClick hexValue)
-        $.borderColorPickerButton = new YAHOO.widget.Button {
-          disabled: false
-          type: 'split'
-          label: '<em  class=\'color-picker-button\' id="current-color">Current color is #FFFFFF.</em>'
-          container: 'tbl_border_color'
-        }
-        $.cellBgColorPickerButton = new YAHOO.widget.Button {
-          disabled: false
-          type: 'split'
-          label: '<em class=\'color-picker-button\' id="current-cell-bg-color">Current color is #FFFFFF.</em>'
-          container: 'tbl_cell_bg_color'
-        }
-        ($ '#tbl_cell_bg_color').click (->
-          createColorPicker! if not $.colorPickerAligned
-          $.alignMenu $.oColorPickerDialog, 'tbl_cell_bg_color'
-          $.tblfocusedProperty = 'tbl_cell_bg_color'
-          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
-          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
-          $.oColorPickerDialog.setHeader 'Please choose a color for: Cell Background color'
-          $.oColorPickerDialog.show!
-          hexValue = $.cellBgColorPickerButton.get 'value'
-          if hexValue then colorPickerButtonClick hexValue)
-        $.evenRowBgColorPickerButton = new YAHOO.widget.Button {
-          disabled: false
-          type: 'split'
-          label: '<em class=\'color-picker-button\' id="even-row-bg-color">Current color is #FFFFFF.</em>'
-          container: 'tbl_even_row_bg_color'
-        }
-        ($ '#tbl_even_row_bg_color').click (->
-          createColorPicker! if not $.colorPickerAligned
-          $.alignMenu $.oColorPickerDialog, 'tbl_even_row_bg_color'
-          $.tblfocusedProperty = 'tbl_even_row_bg_color'
-          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
-          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
-          $.oColorPickerDialog.setHeader 'Please choose a color for: Even Row Background color'
-          $.oColorPickerDialog.show!
-          hexValue = $.evenRowBgColorPickerButton.get 'value'
-          if hexValue then colorPickerButtonClick hexValue)
-        $.oddRowBgColorPickerButton = new YAHOO.widget.Button {
-          disabled: false
-          type: 'split'
-          label: '<em class=\'color-picker-button\' id="odd-row-bg-color">Current color is #FFFFFF.</em>'
-          container: 'tbl_odd_row_bg_color'
-        }
-        ($ '#tbl_odd_row_bg_color').click (->
-          createColorPicker! if not $.colorPickerAligned
-          $.alignMenu $.oColorPickerDialog, 'tbl_odd_row_bg_color'
-          $.tblfocusedProperty = 'tbl_odd_row_bg_color'
-          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
-          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
-          $.oColorPickerDialog.setHeader 'Please choose a color for: Odd Row Background color'
-          $.oColorPickerDialog.show!
-          hexValue = $.oddRowBgColorPickerButton.get 'value'
-          if hexValue then colorPickerButtonClick hexValue)
-        $.singleRowBgColorPickerButton = new YAHOO.widget.Button {
-          disabled: false
-          type: 'split'
-          label: '<em class=\'color-picker-button\' id="single-row-bg-color">Current color is #FFFFFF.</em>'
-          container: 'tbl_single_row_bg_color'
-        }
-        ($ '#tbl_single_row_bg_color').click (->
-          createColorPicker! if not $.colorPickerAligned
-          $.alignMenu $.oColorPickerDialog, 'tbl_single_row_bg_color'
-          $.tblfocusedProperty = 'tbl_single_row_bg_color'
-          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
-          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
-          $.oColorPickerDialog.setHeader 'Please choose a color for: Single Row Background color'
-          $.oColorPickerDialog.show!
-          hexValue = $.singleRowBgColorPickerButton.get 'value'
-          if hexValue then colorPickerButtonClick hexValue)
-        $.singleColBgColorPickerButton = new YAHOO.widget.Button {
-          disabled: false
-          type: 'split'
-          label: '<em class=\'color-picker-button\' id="single-col-bg-color">Current color is #FFFFFF.</em>'
-          container: 'tbl_single_col_bg_color'
-        }
-        ($ '#tbl_single_col_bg_color').click (->
-          createColorPicker! if not $.colorPickerAligned
-          $.alignMenu $.oColorPickerDialog, 'tbl_single_col_bg_color'
-          $.tblfocusedProperty = 'tbl_single_col_bg_color'
-          if $.rowVAlignsMenu then $.rowVAlignsMenu.hide!
-          if $.borderWidthsMenu then $.borderWidthsMenu.hide!
-          $.oColorPickerDialog.setHeader 'Please choose a color for: Single Column Background color'
-          $.oColorPickerDialog.show!
-          hexValue = $.singleColBgColorPickerButton.get 'value'
-          if hexValue then colorPickerButtonClick hexValue)
-        ($ '.text-input').change (->
-          selParams = {tblPropertyChange: true}
-          if @id is 'tbl_width'
-            selParams.tblWidth = true
-            selParams.attrName = 'width'
-          else
-            if @id is 'tbl_height'
-              selParams.tblHeight = true
-              selParams.attrName = 'height'
-            else
-              if @id is 'tbl_col_width'
-                selParams.tblColWidth = true
-                selParams.attrName = 'width'
-              else
-                if @id is 'tbl_row_height'
-                  selParams.tblCellHeight = true
-                  selParams.attrName = 'height'
-                else
-                  if @id is 'tbl_cell_padding'
-                    selParams.tblCellPadding = true
-                    selParams.attrName = 'padding'
-                  else
-                    if @id is 'tbl_cell_font_size'
-                      selParams.tblCellFontSize = true
-                      selParams.attrName = 'fontSize'
-                    else
-                      if @id is 'img_width'
-                        selParams.imgWidth = true
-                        selParams.attrName = 'width'
-                      else
-                        if @id is 'img_height'
-                          selParams.imgHeight = true
-                          selParams.attrName = 'height'
-          selParams.attrValue = @value
-          @value = ''
-          ($ '#text_input_message').text 'Ok'
-          ($ '#text_input_message').removeAttr 'style'
-          ($ '#text_input_message').fadeOut 'slow'
-          context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions selParams), 'tblOptions', true)
-      matrixTable = '<table id=\'matrix_table\'class=\'matrix-table\'><caption></caption>    <tr value=1><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=2 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=3 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=4><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=5 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=6><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=7><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=8><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=9><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=10><td height=10 value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr></table>'
-      $.tblContextMenu = new YAHOO.widget.ContextMenu 'tbl_context_menu', {
-        iframe: true
-        zindex: 500
-        shadow: false
-        position: 'dynamic'
-        keepopen: true
-        clicktohide: true
-      }
-      $.tblContextMenu.addItems [
-        [{
-          text: 'Insert Table'
-          submenu: {
-            id: 'tbl_insert'
-            itemData: ['<div id=\'select_matrix\'>0 X 0</div>']
-          }
-        }]
-        [
-          'Insert Row Above'
-          'Insert Row Below'
-          'Insert Column Right'
-          'Insert Column Left'
-        ]
-        [
-          'Delete Row'
-          'Delete Column'
-          'Delete Table'
-        ]
-        [{
-          id: 'tbl_prop_menu_item'
-          text: 'Table Properties'
-          onclick: {fn: showTblPropPanel}
-        }]
-      ]
-      subMenus = $.tblContextMenu.getSubmenus!
-      subMenus.0.setFooter matrixTable
-      $.tblContextMenu.render document.body
-      $.alignMenu = (menu, id, addX, addY, scrollY) ->
-        region = YAHOO.util.Dom.getRegion id
-        if typeof id is 'string' and (id is 'tbl-menu' or id is 'upload_image_cont')
-          menu.cfg.setProperty 'xy', [region.left, region.bottom]
-        else
-          if typeof id is 'string' then menu.cfg.setProperty 'xy', [region.right, region.top] else menu.cfg.setProperty 'xy', [30 + addX, 36 + addY - scrollY]
-      ($ 'table td').hover (->
-        x = 0
-        while x <= ($ this).index!
-          y = 0
-          while y <= ($ this).parent!.index!
-            ((($ this).parent!.parent!.children!.eq y).children!.eq x).addClass 'selected'
-            y++
-          x++), -> ($ 'table td').removeClass 'selected'
-      ($ 'table td').hover (->
-        xVal = @getAttribute 'value'
-        yVal = (($ this).closest 'tr').0.getAttribute 'value'
-        ($ '#select_matrix').html xVal + ' X ' + yVal)
-      ($ 'td', '#matrix_table').click ((e) ->
-        context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions 'addTbl', 'addTblX' + ($ '#select_matrix').text!), 'tblOptions', true
-        false)
-      $.tblContextMenu.subscribe 'click', (p_sType, p_aArgs) ->
-        oEvent = p_aArgs.0
-        oMenuItem = p_aArgs.1
-        if oMenuItem
-          tblReq = oMenuItem.cfg.getProperty 'text'
-          disabled = oMenuItem.cfg.getProperty 'disabled'
-          return  if disabled
-          id = ''
-          switch tblReq
-          case 'Insert Table'
-            id = 'addTbl'
-          case 'Insert Row Above'
-            id = 'addTblRowA'
-          case 'Insert Row Below'
-            id = 'addTblRowB'
-          case 'Insert Column Left'
-            id = 'addTblColL'
-          case 'Insert Column Right'
-            id = 'addTblColR'
-          case 'Delete Table'
-            id = 'delTbl'
-          case 'Delete Image'
-            id = 'delImg'
-          case 'Delete Row'
-            id = 'delTblRow'
-          case 'Delete Column'
-            id = 'delTblCol'
-          context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions id), 'tblOptions', true
-          false
-    if not init
-      $.alignMenu $.tblContextMenu, 'tbl-menu'
-      $.tblContextMenu.show!
-  ($ '#tbl-menu').click $.createTableMenu
-  YAHOO.util.Dom.addClass document.body, 'yui-skin-sam'
-  ($ 'body').append $ '<div id="yui-picker-panel" class="yui-picker-panel">' + '<div class="hd">Please choose a color:</div>' + '<div class="bd">' + '\t<div class="yui-picker" id="color-picker-menu"></div>' + '</div>' + '<div class="ft"></div>' + '</div>'
-  ($ 'body').append $ '<div id="yui-tbl-prop-panel" class="yui-picker-panel">' + '<div class="hd">Table/Image Properties</div>' + '<div class="bd">' + '\t<div class="yui-picker" id="tbl-props"></div>' + '</div>' + '<div class="ft"></div>' + '</div>'
-  $.createTableMenu true
-
 exports.aceInitialized = (hook, context) ->
   editorInfo = context.editorInfo
   editorInfo.ace_doDatatableOptions = (_ Datatables.doDatatableOptions).bind context
diff --git a/static/js/datatables-ui.js b/static/js/datatables-ui.js
new file mode 100644
index 0000000..acaa899
--- /dev/null
+++ b/static/js/datatables-ui.js
@@ -0,0 +1,689 @@
+exports.aceInitInnerdocbodyHead = function(hook_name, args, cb){
+  return args.iframeHTML.push('<link rel="stylesheet" type="text/css" href="/static/plugins/ep_tables/static/css/dataTables.css"/>');
+};
+exports.postAceInit = function(hook, context){
+  $.createTableMenu = function(init){
+    var showTblPropPanel, createColorPicker, colorPickerButtonClick, initTableProperties, matrixTable, subMenus;
+    showTblPropPanel = function(){
+      if (!$.tblPropDialog) {
+        $.tblPropDialog = new YAHOO.widget.Dialog('yui-tbl-prop-panel', {
+          width: '600px',
+          height: '450px',
+          close: true,
+          visible: false,
+          zindex: 1001,
+          constraintoviewport: true
+        });
+        $.tblPropDialog.setBody($.getTblPropertiesHTML());
+        $.tblPropDialog.render();
+        $.alignMenu($.tblPropDialog, this.id);
+        initTableProperties();
+      }
+      return $.tblPropDialog.show();
+    };
+    createColorPicker = function(){
+      var createOColorPicker, handleColorPickerSubmit, handleDialogCancel;
+      createOColorPicker = function(){
+        $.oColorPicker = new YAHOO.widget.ColorPicker('color-picker-menu', {
+          showhsvcontrols: false,
+          showrgbcontrols: false,
+          showwebsafe: false,
+          showhexsummary: false,
+          showhexcontrols: true,
+          images: {
+            PICKER_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/picker_thumb.png',
+            HUE_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/hue_thumb.png'
+          }
+        });
+        $.oColorPicker.on('rgbChange', colorPickerButtonClick);
+        return $.colorPickerAligned = true;
+      };
+      handleColorPickerSubmit = function(){
+        return colorPickerButtonClick($.oColorPicker.get('hex'));
+      };
+      handleDialogCancel = function(){
+        return this.cancel();
+      };
+      $.oColorPickerDialog = new YAHOO.widget.Dialog('yui-picker-panel', {
+        width: '500px',
+        close: true,
+        visible: false,
+        zindex: 1002,
+        constraintoviewport: true,
+        buttons: [{
+          text: 'Exit',
+          handler: this.handleDialogCancel
+        }]
+      });
+      $.oColorPickerDialog.renderEvent.subscribe(function(){
+        if (!$.oColorPicker) {
+          return createOColorPicker();
+        }
+      });
+      $.oColorPickerDialog.render();
+      return $.oColorPickerDialog.show();
+    };
+    colorPickerButtonClick = function(sColor){
+      var selParams;
+      if (typeof sColor === 'string' && sColor != null && sColor.indexOf('#') === -1) {
+        sColor = '#' + sColor;
+      } else {
+        if (typeof sColor === 'object') {
+          sColor = this.get('hex') == null
+            ? this.get('value')
+            : '#' + this.get('hex');
+        }
+      }
+      selParams = {
+        borderWidth: null,
+        tblPropertyChange: true
+      };
+      switch ($.tblfocusedProperty) {
+      case 'tbl_border_color':
+        selParams.tblBorderColor = true;
+        selParams.attrName = 'borderColor';
+        $.borderColorPickerButton.set('value', sColor);
+        $('#current-color').css('backgroundColor', sColor);
+        $('#current-color').innerHTML = 'Current color is ' + sColor;
+        break;
+      case 'tbl_cell_bg_color':
+        selParams.tblCellBgColor = true;
+        selParams.attrName = 'bgColor';
+        $.cellBgColorPickerButton.set('value', sColor);
+        $('#current-cell-bg-color').css('backgroundColor', sColor);
+        $('#current-cell-bg-color').innerHTML = 'Current color is ' + sColor;
+        break;
+      case 'tbl_even_row_bg_color':
+        selParams.tblEvenRowBgColor = true;
+        selParams.attrName = 'evenBgColor';
+        $.evenRowBgColorPickerButton.set('value', sColor);
+        $('#even-row-bg-color').css('backgroundColor', sColor);
+        $('#even-row-bg-color').innerHTML = 'Current color is ' + sColor;
+        break;
+      case 'tbl_odd_row_bg_color':
+        selParams.tblOddRowBgColor = true;
+        selParams.attrName = 'oddBgColor';
+        $.oddRowBgColorPickerButton.set('value', sColor);
+        $('#odd-row-bg-color').css('backgroundColor', sColor);
+        $('#odd-row-bg-color').innerHTML = 'Current color is ' + sColor;
+        break;
+      case 'tbl_single_row_bg_color':
+        selParams.tblSingleRowBgColor = true;
+        selParams.attrName = 'bgColor';
+        $.singleRowBgColorPickerButton.set('value', sColor);
+        $('#single-row-bg-color').css('backgroundColor', sColor);
+        $('#single-row-bg-color').innerHTML = 'Current color is ' + sColor;
+        break;
+      case 'tbl_single_col_bg_color':
+        selParams.tblSingleColBgColor = true;
+        selParams.attrName = 'bgColor';
+        $.singleColBgColorPickerButton.set('value', sColor);
+        $('#single-col-bg-color').css('backgroundColor', sColor);
+        $('#single-col-bg-color').innerHTML = 'Current color is ' + sColor;
+      }
+      selParams.attrValue = sColor;
+      return context.ace.callWithAce(function(ace){
+        return ace.ace_doDatatableOptions(selParams);
+      }, 'tblOptions', true);
+    };
+    if (!(typeof top.templatesMenu === 'undefined')) {
+      top.templatesMenu.hide();
+    }
+    if ($.tblContextMenu) {
+      $.alignMenu($.tblContextMenu, 'tbl-menu');
+      $.tblContextMenu.show();
+      return;
+    }
+    $.handleTableBorder = function(selectValue){
+      var selParams;
+      selParams = {
+        tblBorderWidth: true,
+        attrName: 'borderWidth',
+        attrValue: selectValue,
+        tblPropertyChange: true
+      };
+      return context.ace.callWithAce(function(ace){
+        return ace.ace_doDatatableOptions(selParams);
+      }, 'tblOptions', true);
+    };
+    $.getTblPropertiesHTML = function(){
+      return '<span id=\'table_properties\'><span class=\'tbl-prop-menu-header\'></span><br><span id=\'tbl-prop-menu\'class=\'tbl-prop-menu\'>' + '<table class=\'left-tbl-props tbl-inline-block\'>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>Table border</span></td></tr>' + '<tr><td><span class=\'tbl-inline-block\' id=\'tbl_border_color\'> </span><span id=\'tbl_border_width\'class=\'tbl-inline-block tbl_border_width\'></span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Cell background color</span></td></tr><tr><td><span id=\'tbl_cell_bg_color\'></td></tr><tr><td></span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Even/Odd Row background color</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_even_row_bg_color\'>Even   </span><span id=\'tbl_odd_row_bg_color\' class=\'tbl-inline-block\'>Odd</span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Single Row/Col background color</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_single_row_bg_color\'>Single Row   </span><span id=\'tbl_single_col_bg_color\' class=\'tbl-inline-block\'>Single Col</span></td></tr>' + '<tr><td class=\'tbl-prop-label-td\'><span class=\'tbl-prop-label\'>Row/Col alignment</span></td></tr>' + '\t<tr><td><span class=\'tbl-inline-block\' id=\'tbl_row_v_align\'>Row align </span><span id=\'tbl_col_v_align\' class=\'tbl-inline-block\'>Col align</span></td></tr>' + '</table>' + '\t<span class=\' tbl-inline-block\'>' + '\t\t<span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + 'Dimensions(Inches) ' + '\t\t</span>  <span id=\'text_input_message\'></span>' + '\t\t<table class=\'tbl-prop-dim\'>' + '\t\t\t<tbody>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Table width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Table height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Column width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_col_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Minimum row height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_row_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label >Cell padding</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_cell_padding\' type=\'text\' size=\'4\' class=\'text-input\'>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t</tbody>' + '\t\t</table>' + '\t\t<br> ' + '\t\t<span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + '\t\t\tFonts ' + '\t\t</span>' + '\t\t<table class=\'tbl-prop-dim\'>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label >Cell font size</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'select-font-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'tbl_cell_font_size\' type=\'text\' size=\'4\' class=\'text-input\'>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t</tbody>' + '\t\t</table>' + '\t</span>' + '</span>' + '</span>' + '<span id=\'img_properties\'>' + '<span class=\'tbl-prop-menu-header\'></span><span id=\'img-prop-menu\'class=\'tbl-prop-menu\'>' + '<table class=\'left-tbl-props tbl-inline-block\'>' + '\t\t<caption><span class=\'tbl-prop-label\' style=\'padding-top: 8px;\'>' + '\t\t\tDimensions(Intches) ' + '\t\t</span></caption>' + '\t\t\t<tbody>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Image width</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'img_width\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '\t\t\t\t<tr>' + '\t\t\t\t\t<td>\t\t\t\t\t\t\t' + '\t\t\t\t\t\t<span class=\'tbl-prop-dim-label tbl-inline-block\'>' + '\t\t\t\t\t\t\t<label  >Image height</label>' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t\t<td class=\'td-spacer\'></td>' + '\t\t\t\t\t<td>' + '\t\t\t\t\t\t<span class=\' tbl-inline-block\'>' + '\t\t\t\t\t\t\t<input id=\'img_height\' type=\'text\' size=\'4\' class=\'text-input\' >' + '\t\t\t\t\t\t</span>' + '\t\t\t\t\t</td>' + '\t\t\t\t</tr>' + '</table>' + '</span>' + '</span>';
+    };
+    if (typeof $.tblContextMenu === 'undefined') {
+      initTableProperties = function(){
+        var colVAligns, rowVAligns, borderWidths;
+        colVAligns = ['Left', 'Center', 'Right'];
+        $.colVAlignsMenu = new YAHOO.widget.ContextMenu('tbl_col_v_align_menu', {
+          iframe: true,
+          zindex: 1003,
+          shadow: false,
+          position: 'dynamic',
+          keepopen: true,
+          clicktohide: true
+        });
+        $.colVAlignsMenu.addItems(colVAligns);
+        $.colVAlignsMenu.render(document.body);
+        $.colVAlignsMenu.subscribe('click', function(p_sType, p_aArgs){
+          var oEvent, oMenuItem, align, selParams;
+          oEvent = p_aArgs[0];
+          oMenuItem = p_aArgs[1];
+          if (oMenuItem) {
+            align = oMenuItem.cfg.getProperty('text');
+            selParams = {
+              tblColVAlign: true,
+              attrName: 'colVAlign',
+              attrValue: align,
+              tblPropertyChange: true
+            };
+            $.colVAlignsMenuButton.set('value', selParams.attrValue);
+            $('#current-col-v-alignment').html(align);
+            return context.ace.callWithAce(function(ace){
+              return ace.ace_doDatatableOptions(selParams);
+            }, 'tblOptions', true);
+          }
+        });
+        $.colVAlignsMenuButton = new YAHOO.widget.Button({
+          disabled: false,
+          type: 'split',
+          label: '<em id="current-col-v-alignment">Left</em>',
+          container: 'tbl_col_v_align'
+        });
+        $('#tbl_col_v_align').click(function(){
+          var aligned, vAlignValue, selParams;
+          aligned = false;
+          if (!aligned) {
+            $.alignMenu($.colVAlignsMenu, 'tbl_col_v_align');
+          }
+          if ($.borderWidthsMenu) {
+            $.borderWidthsMenu.hide();
+          }
+          if ($.oColorPickerDialog) {
+            $.oColorPickerDialog.hide();
+          }
+          $.colVAlignsMenu.show();
+          vAlignValue = $.colVAlignsMenuButton.get('value');
+          if (vAlignValue) {
+            selParams = {
+              tblColVAlign: true,
+              attrName: 'colVAlign',
+              attrValue: vAlignValue,
+              tblPropertyChange: true
+            };
+            return context.ace.callWithAce(function(ace){
+              return ace.ace_doDatatableOptions(selParams);
+            }, 'tblOptions', true);
+          }
+        });
+        rowVAligns = ['Top', 'Center', 'Bottom'];
+        $.rowVAlignsMenu = new YAHOO.widget.ContextMenu('tbl_row_v_align_menu', {
+          iframe: true,
+          zindex: 1003,
+          shadow: false,
+          position: 'dynamic',
+          keepopen: true,
+          clicktohide: true
+        });
+        $.rowVAlignsMenu.addItems(rowVAligns);
+        $.rowVAlignsMenu.render(document.body);
+        $.rowVAlignsMenu.subscribe('click', function(p_sType, p_aArgs){
+          var oEvent, oMenuItem, align, selParams;
+          oEvent = p_aArgs[0];
+          oMenuItem = p_aArgs[1];
+          if (oMenuItem) {
+            align = oMenuItem.cfg.getProperty('text');
+            selParams = {
+              tblRowVAlign: true,
+              attrName: 'rowVAlign',
+              attrValue: align,
+              tblPropertyChange: true
+            };
+            $.rowVAlignsMenuButton.set('value', selParams.attrValue);
+            $('#current-v-alignment').html(align);
+            return context.ace.callWithAce(function(ace){
+              return ace.ace_doDatatableOptions(selParams);
+            }, 'tblOptions', true);
+          }
+        });
+        $.rowVAlignsMenuButton = new YAHOO.widget.Button({
+          disabled: false,
+          type: 'split',
+          label: '<em id="current-v-alignment">Top</em>',
+          container: 'tbl_row_v_align'
+        });
+        $('#tbl_row_v_align').click(function(){
+          var aligned, vAlignValue, selParams;
+          aligned = false;
+          if (!aligned) {
+            $.alignMenu($.rowVAlignsMenu, 'tbl_row_v_align');
+          }
+          if ($.borderWidthsMenu) {
+            $.borderWidthsMenu.hide();
+          }
+          if ($.oColorPickerDialog) {
+            $.oColorPickerDialog.hide();
+          }
+          $.rowVAlignsMenu.show();
+          vAlignValue = $.rowVAlignsMenuButton.get('value');
+          if (vAlignValue) {
+            selParams = {
+              tblRowVAlign: true,
+              attrName: 'rowVAlign',
+              attrValue: vAlignValue,
+              tblPropertyChange: true
+            };
+            return context.ace.callWithAce(function(ace){
+              return ace.ace_doDatatableOptions(selParams);
+            }, 'tblOptions', true);
+          }
+        });
+        borderWidths = ['0px', '1px', '2px', '3px', '4px', '5px', '6px', '7px', '8px'];
+        $.borderWidthsMenu = new YAHOO.widget.ContextMenu('tbl_border_width_menu', {
+          iframe: true,
+          zindex: 1003,
+          shadow: false,
+          position: 'dynamic',
+          keepopen: true,
+          clicktohide: true
+        });
+        $.borderWidthsMenu.addItems(borderWidths);
+        $.borderWidthsMenu.render(document.body);
+        $.borderWidthsMenu.subscribe('click', function(p_sType, p_aArgs){
+          var oEvent, oMenuItem, borderReq, selParams;
+          oEvent = p_aArgs[0];
+          oMenuItem = p_aArgs[1];
+          if (oMenuItem) {
+            borderReq = oMenuItem.cfg.getProperty('text');
+            selParams = {
+              tblBorderWidth: true,
+              attrName: 'borderWidth',
+              attrValue: borderReq.substring(0, borderReq.indexOf('px')),
+              tblPropertyChange: true
+            };
+            $.borderWidthPickerButton.set('value', selParams.attrValue);
+            $('#current-width').html(borderReq);
+            return context.ace.callWithAce(function(ace){
+              return ace.ace_doDatatableOptions(selParams);
+            }, 'tblOptions', true);
+          }
+        });
+        $.borderWidthPickerButton = new YAHOO.widget.Button({
+          disabled: false,
+          type: 'split',
+          label: '<em id="current-width">1px</em>',
+          container: 'tbl_border_width'
+        });
+        $('#tbl_border_width').click(function(){
+          var aligned, widthValue, selParams;
+          aligned = false;
+          if (!aligned) {
+            $.alignMenu($.borderWidthsMenu, 'tbl_border_width');
+          }
+          if ($.oColorPickerDialog) {
+            $.oColorPickerDialog.hide();
+          }
+          if ($.rowVAlignsMenu) {
+            $.rowVAlignsMenu.hide();
+          }
+          $.borderWidthsMenu.show();
+          widthValue = $.borderWidthPickerButton.get('value');
+          if (widthValue) {
+            selParams = {
+              tblBorderWidth: true,
+              attrName: 'borderWidth',
+              attrValue: widthValue,
+              tblPropertyChange: true
+            };
+            return context.ace.callWithAce(function(ace){
+              return ace.ace_doDatatableOptions(selParams);
+            }, 'tblOptions', true);
+          }
+        });
+        $.tblfocusedProperty = '';
+        $('#tbl_properties').click(function(){
+          if (!(typeof $.borderWidthsMenu === 'undefined')) {
+            $.borderWidthsMenu.hide();
+          }
+          if (!(typeof $.oColorPickerDialog === 'undefined')) {
+            $.oColorPickerDialog.hide();
+          }
+          if (!(typeof $.rowVAlignsMenu === 'undefined')) {
+            return $.rowVAlignsMenu.hide();
+          }
+        });
+        $.colorPickerAligned = false;
+        $('#tbl_border_color').click(function(){
+          var hexValue;
+          if (!$.colorPickerAligned) {
+            createColorPicker();
+          }
+          $.alignMenu($.oColorPickerDialog, 'tbl_border_color');
+          $.tblfocusedProperty = 'tbl_border_color';
+          if ($.rowVAlignsMenu) {
+            $.rowVAlignsMenu.hide();
+          }
+          if ($.borderWidthsMenu) {
+            $.borderWidthsMenu.hide();
+          }
+          $.oColorPickerDialog.setHeader('Please choose a color for: Table Border color');
+          $.oColorPickerDialog.show();
+          hexValue = $.borderColorPickerButton.get('value');
+          if (hexValue) {
+            return colorPickerButtonClick(hexValue);
+          }
+        });
+        $.borderColorPickerButton = new YAHOO.widget.Button({
+          disabled: false,
+          type: 'split',
+          label: '<em  class=\'color-picker-button\' id="current-color">Current color is #FFFFFF.</em>',
+          container: 'tbl_border_color'
+        });
+        $.cellBgColorPickerButton = new YAHOO.widget.Button({
+          disabled: false,
+          type: 'split',
+          label: '<em class=\'color-picker-button\' id="current-cell-bg-color">Current color is #FFFFFF.</em>',
+          container: 'tbl_cell_bg_color'
+        });
+        $('#tbl_cell_bg_color').click(function(){
+          var hexValue;
+          if (!$.colorPickerAligned) {
+            createColorPicker();
+          }
+          $.alignMenu($.oColorPickerDialog, 'tbl_cell_bg_color');
+          $.tblfocusedProperty = 'tbl_cell_bg_color';
+          if ($.rowVAlignsMenu) {
+            $.rowVAlignsMenu.hide();
+          }
+          if ($.borderWidthsMenu) {
+            $.borderWidthsMenu.hide();
+          }
+          $.oColorPickerDialog.setHeader('Please choose a color for: Cell Background color');
+          $.oColorPickerDialog.show();
+          hexValue = $.cellBgColorPickerButton.get('value');
+          if (hexValue) {
+            return colorPickerButtonClick(hexValue);
+          }
+        });
+        $.evenRowBgColorPickerButton = new YAHOO.widget.Button({
+          disabled: false,
+          type: 'split',
+          label: '<em class=\'color-picker-button\' id="even-row-bg-color">Current color is #FFFFFF.</em>',
+          container: 'tbl_even_row_bg_color'
+        });
+        $('#tbl_even_row_bg_color').click(function(){
+          var hexValue;
+          if (!$.colorPickerAligned) {
+            createColorPicker();
+          }
+          $.alignMenu($.oColorPickerDialog, 'tbl_even_row_bg_color');
+          $.tblfocusedProperty = 'tbl_even_row_bg_color';
+          if ($.borderWidthsMenu) {
+            $.borderWidthsMenu.hide();
+          }
+          if ($.rowVAlignsMenu) {
+            $.rowVAlignsMenu.hide();
+          }
+          $.oColorPickerDialog.setHeader('Please choose a color for: Even Row Background color');
+          $.oColorPickerDialog.show();
+          hexValue = $.evenRowBgColorPickerButton.get('value');
+          if (hexValue) {
+            return colorPickerButtonClick(hexValue);
+          }
+        });
+        $.oddRowBgColorPickerButton = new YAHOO.widget.Button({
+          disabled: false,
+          type: 'split',
+          label: '<em class=\'color-picker-button\' id="odd-row-bg-color">Current color is #FFFFFF.</em>',
+          container: 'tbl_odd_row_bg_color'
+        });
+        $('#tbl_odd_row_bg_color').click(function(){
+          var hexValue;
+          if (!$.colorPickerAligned) {
+            createColorPicker();
+          }
+          $.alignMenu($.oColorPickerDialog, 'tbl_odd_row_bg_color');
+          $.tblfocusedProperty = 'tbl_odd_row_bg_color';
+          if ($.rowVAlignsMenu) {
+            $.rowVAlignsMenu.hide();
+          }
+          if ($.borderWidthsMenu) {
+            $.borderWidthsMenu.hide();
+          }
+          $.oColorPickerDialog.setHeader('Please choose a color for: Odd Row Background color');
+          $.oColorPickerDialog.show();
+          hexValue = $.oddRowBgColorPickerButton.get('value');
+          if (hexValue) {
+            return colorPickerButtonClick(hexValue);
+          }
+        });
+        $.singleRowBgColorPickerButton = new YAHOO.widget.Button({
+          disabled: false,
+          type: 'split',
+          label: '<em class=\'color-picker-button\' id="single-row-bg-color">Current color is #FFFFFF.</em>',
+          container: 'tbl_single_row_bg_color'
+        });
+        $('#tbl_single_row_bg_color').click(function(){
+          var hexValue;
+          if (!$.colorPickerAligned) {
+            createColorPicker();
+          }
+          $.alignMenu($.oColorPickerDialog, 'tbl_single_row_bg_color');
+          $.tblfocusedProperty = 'tbl_single_row_bg_color';
+          if ($.borderWidthsMenu) {
+            $.borderWidthsMenu.hide();
+          }
+          if ($.rowVAlignsMenu) {
+            $.rowVAlignsMenu.hide();
+          }
+          $.oColorPickerDialog.setHeader('Please choose a color for: Single Row Background color');
+          $.oColorPickerDialog.show();
+          hexValue = $.singleRowBgColorPickerButton.get('value');
+          if (hexValue) {
+            return colorPickerButtonClick(hexValue);
+          }
+        });
+        $.singleColBgColorPickerButton = new YAHOO.widget.Button({
+          disabled: false,
+          type: 'split',
+          label: '<em class=\'color-picker-button\' id="single-col-bg-color">Current color is #FFFFFF.</em>',
+          container: 'tbl_single_col_bg_color'
+        });
+        $('#tbl_single_col_bg_color').click(function(){
+          var hexValue;
+          if (!$.colorPickerAligned) {
+            createColorPicker();
+          }
+          $.alignMenu($.oColorPickerDialog, 'tbl_single_col_bg_color');
+          $.tblfocusedProperty = 'tbl_single_col_bg_color';
+          if ($.rowVAlignsMenu) {
+            $.rowVAlignsMenu.hide();
+          }
+          if ($.borderWidthsMenu) {
+            $.borderWidthsMenu.hide();
+          }
+          $.oColorPickerDialog.setHeader('Please choose a color for: Single Column Background color');
+          $.oColorPickerDialog.show();
+          hexValue = $.singleColBgColorPickerButton.get('value');
+          if (hexValue) {
+            return colorPickerButtonClick(hexValue);
+          }
+        });
+        return $('.text-input').change(function(){
+          var selParams;
+          selParams = {
+            tblPropertyChange: true
+          };
+          if (this.id === 'tbl_width') {
+            selParams.tblWidth = true;
+            selParams.attrName = 'width';
+          } else {
+            if (this.id === 'tbl_height') {
+              selParams.tblHeight = true;
+              selParams.attrName = 'height';
+            } else {
+              if (this.id === 'tbl_col_width') {
+                selParams.tblColWidth = true;
+                selParams.attrName = 'width';
+              } else {
+                if (this.id === 'tbl_row_height') {
+                  selParams.tblCellHeight = true;
+                  selParams.attrName = 'height';
+                } else {
+                  if (this.id === 'tbl_cell_padding') {
+                    selParams.tblCellPadding = true;
+                    selParams.attrName = 'padding';
+                  } else {
+                    if (this.id === 'tbl_cell_font_size') {
+                      selParams.tblCellFontSize = true;
+                      selParams.attrName = 'fontSize';
+                    } else {
+                      if (this.id === 'img_width') {
+                        selParams.imgWidth = true;
+                        selParams.attrName = 'width';
+                      } else {
+                        if (this.id === 'img_height') {
+                          selParams.imgHeight = true;
+                          selParams.attrName = 'height';
+                        }
+                      }
+                    }
+                  }
+                }
+              }
+            }
+          }
+          selParams.attrValue = this.value;
+          this.value = '';
+          $('#text_input_message').text('Ok');
+          $('#text_input_message').removeAttr('style');
+          $('#text_input_message').fadeOut('slow');
+          return context.ace.callWithAce(function(ace){
+            return ace.ace_doDatatableOptions(selParams);
+          }, 'tblOptions', true);
+        });
+      };
+      matrixTable = '<table id=\'matrix_table\'class=\'matrix-table\'><caption></caption>    <tr value=1><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=2 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=3 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=4><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=5 ><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=6><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=7><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=8><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=9><td value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr>    <tr value=10><td height=10 value=1> </td><td value=2> </td><td value=3> </td><td value=4> </td><td value=5> </td><td value=6> </td><td value=7> </td><td value=8> </td><td value=9> </td><td value=10> </td><td value=11> </td><td value=12> </td><td value=13> </td><td value=14> </td><td value=15> </td><td value=16> </td><td value=17> </td><td value=18> </td><td value=19> </td><td value=20> </td></tr></table>';
+      $.tblContextMenu = new YAHOO.widget.ContextMenu('tbl_context_menu', {
+        iframe: true,
+        zindex: 500,
+        shadow: false,
+        position: 'dynamic',
+        keepopen: true,
+        clicktohide: true
+      });
+      $.tblContextMenu.addItems([
+        [{
+          text: 'Insert Table',
+          submenu: {
+            id: 'tbl_insert',
+            itemData: ['<div id=\'select_matrix\'>0 X 0</div>']
+          }
+        }], ['Insert Row Above', 'Insert Row Below', 'Insert Column Right', 'Insert Column Left'], ['Delete Row', 'Delete Column', 'Delete Table'], [{
+          id: 'tbl_prop_menu_item',
+          text: 'Table Properties',
+          onclick: {
+            fn: showTblPropPanel
+          }
+        }]
+      ]);
+      subMenus = $.tblContextMenu.getSubmenus();
+      subMenus[0].setFooter(matrixTable);
+      $.tblContextMenu.render(document.body);
+      $.alignMenu = function(menu, id, addX, addY, scrollY){
+        var region;
+        region = YAHOO.util.Dom.getRegion(id);
+        if (typeof id === 'string' && (id === 'tbl-menu' || id === 'upload_image_cont')) {
+          return menu.cfg.setProperty('xy', [region.left, region.bottom]);
+        } else {
+          if (typeof id === 'string') {
+            return menu.cfg.setProperty('xy', [region.right, region.top]);
+          } else {
+            return menu.cfg.setProperty('xy', [30 + addX, 36 + addY - scrollY]);
+          }
+        }
+      };
+      $('table td').hover(function(){
+        var x, lresult$, y, results$ = [];
+        x = 0;
+        while (x <= $(this).index()) {
+          lresult$ = [];
+          y = 0;
+          while (y <= $(this).parent().index()) {
+            $(this).parent().parent().children().eq(y).children().eq(x).addClass('selected');
+            y++;
+          }
+          lresult$.push(x++);
+          results$.push(lresult$);
+        }
+        return results$;
+      }, function(){
+        return $('table td').removeClass('selected');
+      });
+      $('table td').hover(function(){
+        var xVal, yVal;
+        xVal = this.getAttribute('value');
+        yVal = $(this).closest('tr')[0].getAttribute('value');
+        return $('#select_matrix').html(xVal + ' X ' + yVal);
+      });
+      $('td', '#matrix_table').click(function(e){
+        context.ace.callWithAce(function(ace){
+          return ace.ace_doDatatableOptions('addTbl', 'addTblX' + $('#select_matrix').text());
+        }, 'tblOptions', true);
+        return false;
+      });
+      $.tblContextMenu.subscribe('click', function(p_sType, p_aArgs){
+        var oEvent, oMenuItem, tblReq, disabled, id;
+        oEvent = p_aArgs[0];
+        oMenuItem = p_aArgs[1];
+        if (oMenuItem) {
+          tblReq = oMenuItem.cfg.getProperty('text');
+          disabled = oMenuItem.cfg.getProperty('disabled');
+          if (disabled) {
+            return;
+          }
+          id = '';
+          switch (tblReq) {
+          case 'Insert Table':
+            id = 'addTbl';
+            break;
+          case 'Insert Row Above':
+            id = 'addTblRowA';
+            break;
+          case 'Insert Row Below':
+            id = 'addTblRowB';
+            break;
+          case 'Insert Column Left':
+            id = 'addTblColL';
+            break;
+          case 'Insert Column Right':
+            id = 'addTblColR';
+            break;
+          case 'Delete Table':
+            id = 'delTbl';
+            break;
+          case 'Delete Image':
+            id = 'delImg';
+            break;
+          case 'Delete Row':
+            id = 'delTblRow';
+            break;
+          case 'Delete Column':
+            id = 'delTblCol';
+          }
+          context.ace.callWithAce(function(ace){
+            return ace.ace_doDatatableOptions(id);
+          }, 'tblOptions', true);
+          return false;
+        }
+      });
+    }
+    if (!init) {
+      $.alignMenu($.tblContextMenu, 'tbl-menu');
+      return $.tblContextMenu.show();
+    }
+  };
+  $('#tbl-menu').click($.createTableMenu);
+  YAHOO.util.Dom.addClass(document.body, 'yui-skin-sam');
+  $('body').append($('<div id="yui-picker-panel" class="yui-picker-panel">' + '<div class="hd">Please choose a color:</div>' + '<div class="bd">' + '\t<div class="yui-picker" id="color-picker-menu"></div>' + '</div>' + '<div class="ft"></div>' + '</div>'));
+  $('body').append($('<div id="yui-tbl-prop-panel" class="yui-picker-panel">' + '<div class="hd">Table/Image Properties</div>' + '<div class="bd">' + '\t<div class="yui-picker" id="tbl-props"></div>' + '</div>' + '<div class="ft"></div>' + '</div>'));
+  return $.createTableMenu(true);
+};
\ No newline at end of file
diff --git a/static/js/datatables.js b/static/js/datatables.js
new file mode 100644
index 0000000..9a88ee5
--- /dev/null
+++ b/static/js/datatables.js
@@ -0,0 +1,1376 @@
+var _, Ace2Common, Changeset, escapedJSON, fromEscapedJSON, Datatables;
+_ = require('ep_etherpad-lite/static/js/underscore');
+if (!(typeof require === 'undefined')) {
+  if (typeof Ace2Common === 'undefined') {
+    Ace2Common = require('ep_etherpad-lite/static/js/ace2_common');
+  }
+  if (typeof Changeset === 'undefined') {
+    Changeset = require('ep_etherpad-lite/static/js/Changeset');
+  }
+}
+escapedJSON = function(it){
+  var ret;
+  ret = JSON.stringify(it).replace(/\\u(....)|\\(.)/g, function(_, _1, _2){
+    if (_1) {
+      return String.fromCharCode(parseInt(_1, 16));
+    } else {
+      return "\\" + _1.charCodeAt(0) + ';';
+    }
+  }).replace(/"/g, '\uF134').replace(/\\(\d+);/g, function(_, _1){
+    return "\\" + String.fromCharCode(_1);
+  });
+  return ret;
+};
+fromEscapedJSON = function(it){
+  var ret;
+  ret = JSON.parse(it.replace(/(\\|")/g, '\\$1').replace(/\uF134/g, '"'));
+  return ret;
+};
+exports.aceInitialized = function(hook, context){
+  var editorInfo;
+  editorInfo = context.editorInfo;
+  return editorInfo.ace_doDatatableOptions = _(Datatables.doDatatableOptions).bind(context);
+};
+exports.acePostWriteDomLineHTML = function(hook_name, args, cb){
+  var children, i, lineText, dtAttrs, results$ = [];
+  children = args.node.children;
+  i = 0;
+  while (i < children.length) {
+    if (args.node.children[i].className.indexOf('list') !== -1 || args.node.children[i].className.indexOf('tag') !== -1 || args.node.children[i].className.indexOf('url') !== -1) {
+      continue;
+    }
+    lineText = '';
+    if (args.node.children[i].innerText) {
+      lineText = args.node.children[i].innerText;
+    } else {
+      lineText = args.node.children[i].textContent;
+    }
+    if (lineText && lineText.indexOf('\uFFF9') !== -1) {
+      dtAttrs = typeof exports.Datatables !== 'undefined' ? exports.Datatables.attributes : null;
+      dtAttrs = dtAttrs || '';
+      DatatablesRenderer.render({}, args.node.children[i], dtAttrs);
+      exports.Datatables.attributes = null;
+    }
+    results$.push(i++);
+  }
+  return results$;
+};
+exports.eejsBlock_scripts = function(hook_name, args, cb){
+  return args.content = args.content + require('ep_etherpad-lite/node/eejs/').require('ep_tables/templates/datatablesScripts.ejs');
+};
+exports.eejsBlock_editbarMenuLeft = function(hook_name, args, cb){
+  return args.content = args.content + require('ep_etherpad-lite/node/eejs/').require('ep_tables/templates/datatablesEditbarButtons.ejs');
+};
+exports.eejsBlock_styles = function(hook_name, args, cb){
+  return args.content = require('ep_etherpad-lite/node/eejs/').require('ep_tables/templates/styles.ejs') + args.content;
+};
+exports.aceAttribsToClasses = function(hook, context){
+  Datatables.attributes = null;
+  if (context.key === 'tblProp') {
+    Datatables.attributes = context.value;
+    return ['tblProp:' + context.value];
+  }
+};
+exports.aceStartLineAndCharForPoint = function(hook, context){
+  var selStart, error;
+  selStart = null;
+  try {
+    Datatables.context = context;
+    if (Datatables.isFocused()) {
+      selStart = Datatables.getLineAndCharForPoint();
+    }
+  } catch (e$) {
+    error = e$;
+    top.console.log('error ' + error);
+    top.console.log('context rep' + Datatables.context.rep);
+  }
+  return selStart;
+};
+exports.aceEndLineAndCharForPoint = function(hook, context){
+  var selEndLine, error;
+  selEndLine = null;
+  try {
+    Datatables.context = context;
+    if (Datatables.isFocused()) {
+      selEndLine = Datatables.getLineAndCharForPoint();
+    }
+  } catch (e$) {
+    error = e$;
+    top.console.log('error ' + error);
+    top.console.log('context rep' + Datatables.context.rep);
+  }
+  return selEndLine;
+};
+exports.aceKeyEvent = function(hook, context){
+  var specialHandled, evt, type, keyCode, isTypeForSpecialKey, isTypeForCmdKey, which, e;
+  specialHandled = false;
+  try {
+    Datatables.context = context;
+    if (Datatables.isFocused()) {
+      evt = context.evt;
+      type = evt.type;
+      keyCode = evt.keyCode;
+      isTypeForSpecialKey = Ace2Common.browser.msie || Ace2Common.browser.safari
+        ? type === 'keydown'
+        : type === 'keypress';
+      isTypeForCmdKey = Ace2Common.browser.msie || Ace2Common.browser.safari
+        ? type === 'keydown'
+        : type === 'keypress';
+      which = evt.which;
+      if (!specialHandled && isTypeForSpecialKey && keyCode === 9 && !(evt.metaKey || evt.ctrlKey)) {
+        context.editorInfo.ace_fastIncorp(5);
+        evt.preventDefault();
+        Datatables.performDocumentTableTabKey();
+        specialHandled = true;
+      }
+      if (!specialHandled && isTypeForSpecialKey && keyCode === 13) {
+        context.editorInfo.ace_fastIncorp(5);
+        evt.preventDefault();
+        Datatables.doReturnKey();
+        specialHandled = true;
+      }
+      if (!specialHandled && isTypeForSpecialKey && (keyCode === Datatables.vars.JS_KEY_CODE_DEL || keyCode === Datatables.vars.JS_KEY_CODE_BS || String.fromCharCode(which).toLowerCase() === 'h' && evt.ctrlKey)) {
+        context.editorInfo.ace_fastIncorp(20);
+        evt.preventDefault();
+        specialHandled = true;
+        if (Datatables.isCellDeleteOk(keyCode)) {
+          Datatables.doDeleteKey();
+        }
+      }
+    }
+  } catch (e$) {
+    e = e$;
+  }
+  return specialHandled;
+};
+if (typeof Datatables === 'undefined') {
+  Datatables = function(){
+    var nodeText, dt;
+    nodeText = function(n){
+      var text, el, els, excluded, i, iLen;
+      text = [];
+      el = void 8;
+      els = n.childNodes;
+      excluded = {
+        noscript: 'noscript',
+        script: 'script'
+      };
+      i = 0;
+      iLen = els.length;
+      while (i < iLen) {
+        el = els[i];
+        if (el.nodeType === 1 && el.tagName.toLowerCase() in excluded) {
+          text.push(nodeText(el));
+        } else if (el.nodeType === 3) {
+          text.push(el.data);
+        }
+        i++;
+      }
+      return text.join('');
+    };
+    dt = {
+      defaults: {
+        tblProps: {
+          borderWidth: '1',
+          cellAttrs: [],
+          width: '6',
+          rowAttrs: {},
+          colAttrs: [],
+          authors: {}
+        }
+      },
+      config: {},
+      vars: {
+        OVERHEAD_LEN_PRE: '{\uF134payload":[[\uF134'.length,
+        OVERHEAD_LEN_MID: '\uF134,\uF134'.length,
+        OVERHEAD_LEN_ROW_START: '[\uF134'.length,
+        OVERHEAD_LEN_ROW_END: '\uF134],'.length,
+        JS_KEY_CODE_BS: 8,
+        JS_KEY_CODE_DEL: 46,
+        TBL_OPTIONS: ['addTbl', 'addTblRowA', 'addTblRowB', 'addTblColL', 'addTblColR', 'delTbl', 'delTblRow', 'delTblCol', 'delImg']
+      },
+      context: null
+    };
+    dt.isFocused = function(){
+      var line, currLineText;
+      if (!this.context.rep.selStart || !this.context.rep.selEnd) {
+        return false;
+      }
+      line = this.context.rep.lines.atIndex(this.context.rep.selStart[0]);
+      if (!line) {
+        return false;
+      }
+      currLineText = line.text || '';
+      if (currLineText.indexOf('\uFFF9') === -1) {
+        return false;
+      }
+      return true;
+    };
+    dt._getRowEndOffset = function(rowStartOffset, tds){
+      var rowEndOffset, i, len, overHeadLen;
+      rowEndOffset = rowStartOffset + this.vars.OVERHEAD_LEN_ROW_START;
+      i = 0;
+      len = tds.length;
+      while (i < len) {
+        overHeadLen = this.vars.OVERHEAD_LEN_MID;
+        if (i === len - 1) {
+          overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
+        }
+        rowEndOffset += tds[i].length + overHeadLen;
+        i++;
+      }
+      return rowEndOffset;
+    };
+    dt.getFocusedTdInfo = function(payload, colStart){
+      var payloadOffset, rowStartOffset, payloadSum, rIndex, rLen, tds, tIndex, tLen, overHeadLen, leftOverTdTxtLen, cellCaretPos, rowEndOffset;
+      payloadOffset = colStart - this.vars.OVERHEAD_LEN_PRE;
+      rowStartOffset = 0;
+      payloadSum = 0;
+      rIndex = 0;
+      rLen = payload.length;
+      while (rIndex < rLen) {
+        tds = payload[rIndex];
+        tIndex = 0;
+        tLen = tds.length;
+        while (tIndex < tLen) {
+          overHeadLen = this.vars.OVERHEAD_LEN_MID;
+          if (tIndex === tLen - 1) {
+            overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
+          }
+          payloadSum += tds[tIndex].length + overHeadLen;
+          if (payloadSum >= payloadOffset) {
+            if (payloadSum === payloadOffset) {
+              tIndex++;
+            }
+            leftOverTdTxtLen = payloadSum - payloadOffset === 0
+              ? payload[rIndex][tIndex].length + this.vars.OVERHEAD_LEN_MID
+              : payloadSum - payloadOffset;
+            cellCaretPos = tds[tIndex].length - leftOverTdTxtLen - overHeadLen;
+            rowEndOffset = this._getRowEndOffset(rowStartOffset, tds);
+            return {
+              row: rIndex,
+              td: tIndex,
+              leftOverTdTxtLen: leftOverTdTxtLen,
+              rowStartOffset: rowStartOffset,
+              rowEndOffset: rowEndOffset,
+              cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
+              cellEndOffset: payloadSum,
+              cellCaretPos: cellCaretPos
+            };
+          }
+          tIndex++;
+        }
+        rowStartOffset = payloadSum;
+        payloadSum += this.vars.OVERHEAD_LEN_ROW_START;
+        rIndex++;
+      }
+    };
+    dt.printCaretPos = function(start, end){
+      top.console.log(JSON.stringify(start));
+      return top.console.log(JSON.stringify(end));
+    };
+    dt.doDatatableOptions = function(cmd, xByY){
+      Datatables.context = this;
+      if (typeof cmd === 'object' && cmd.tblPropertyChange) {
+        return Datatables.updateTableProperties(cmd);
+      } else {
+        switch (cmd) {
+        case Datatables.vars.TBL_OPTIONS[0]:
+          return Datatables.addTable(xByY);
+        case Datatables.vars.TBL_OPTIONS[1]:
+          return Datatables.insertTblRow('addA');
+        case Datatables.vars.TBL_OPTIONS[2]:
+          return Datatables.insertTblRow('addB');
+        case Datatables.vars.TBL_OPTIONS[3]:
+          return Datatables.insertTblColumn('addL');
+        case Datatables.vars.TBL_OPTIONS[4]:
+          return Datatables.insertTblColumn('addR');
+        case Datatables.vars.TBL_OPTIONS[5]:
+          return Datatables.deleteTable();
+        case Datatables.vars.TBL_OPTIONS[6]:
+          return Datatables.deleteTblRow();
+        case Datatables.vars.TBL_OPTIONS[7]:
+          return Datatables.deleteTblColumn();
+        }
+      }
+    };
+    dt.addTable = function(tableObj){
+      var rep, start, end, line, hasMoreRows, isRowAddition, table, currLineText, authors, xByYSelect, cols, rows, jsoStrTblProp, i;
+      rep = this.context.rep;
+      start = rep.selStart;
+      end = rep.selEnd;
+      line = rep.lines.atIndex(rep.selStart[0]);
+      hasMoreRows = null;
+      isRowAddition = null;
+      if (tableObj) {
+        hasMoreRows = tableObj.hasMoreRows;
+        isRowAddition = tableObj.isRowAddition;
+      }
+      if (isRowAddition) {
+        table = fromEscapedJSON(tableObj.tblString);
+        insertTblRowBelow(0, table);
+        performDocApplyTblAttrToRow(rep.selStart, JSON.stringify(table.tblProperties));
+        return;
+      }
+      if (line) {
+        currLineText = line.text;
+        if (!(currLineText.indexOf('\uFFF9') === -1)) {
+          for (;;) {
+            rep.selStart[0] = rep.selStart[0] + 1;
+            currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+            if (!(currLineText.indexOf('\uFFF9') !== -1)) {
+              break;
+            }
+          }
+          rep.selEnd[1] = rep.selStart[1] = currLineText.length;
+          this.context.editorInfo.ace_doReturnKey();
+          this.context.editorInfo.ace_doReturnKey();
+        } else {
+          rep.selEnd[1] = rep.selStart[1] = currLineText.length;
+          this.context.editorInfo.ace_doReturnKey();
+        }
+      }
+      if (tableObj == null) {
+        authors = {};
+        this.insertTblRowBelow(3);
+        this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
+        this.insertTblRowBelow(3);
+        this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
+        this.insertTblRowBelow(3);
+        this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
+        this.context.editorInfo.ace_doReturnKey();
+        this.updateAuthorAndCaretPos(rep.selStart[0] - 3);
+        return;
+      }
+      xByYSelect = typeof tableObj === 'object'
+        ? null
+        : tableObj.split('X');
+      if (xByYSelect != null && xByYSelect.length === 3) {
+        cols = parseInt(xByYSelect[1]);
+        rows = parseInt(xByYSelect[2]);
+        jsoStrTblProp = JSON.stringify(this.createDefaultTblProperties());
+        authors = {};
+        i = 0;
+        while (i < rows) {
+          this.insertTblRowBelow(cols);
+          if (i === 0) {
+            this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
+          } else {
+            this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
+          }
+          i++;
+        }
+        this.updateAuthorAndCaretPos(rep.selStart[0] - rows + 1);
+        return;
+      }
+      return newText;
+    };
+    dt.insertTblRow = function(aboveOrBelow){
+      var func, rep, newText, currLineText, payload, currTdInfo, currRow, lastRowOffSet, start, end, updateEvenOddBgColor, e;
+      func = 'insertTblRow()';
+      rep = this.context.rep;
+      try {
+        newText = '';
+        currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+        payload = fromEscapedJSON(currLineText).payload;
+        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+        currRow = currTdInfo.row;
+        lastRowOffSet = 0;
+        start = [];
+        end = [];
+        start[0] = rep.selStart[0];
+        start[1] = rep.selStart[1];
+        end[0] = rep.selStart[0];
+        end[1] = rep.selStart[1];
+        if (aboveOrBelow === 'addA') {
+          rep.selStart[0] = rep.selEnd[0] = rep.selStart[0] - 1;
+          this.insertTblRowBelow(payload[0].length);
+        } else {
+          this.insertTblRowBelow(payload[0].length);
+        }
+        this.context.editorInfo.ace_performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
+        this.updateAuthorAndCaretPos(rep.selStart[0]);
+        updateEvenOddBgColor = true;
+        return this.sanitizeTblProperties(rep.selStart, updateEvenOddBgColor);
+      } catch (e$) {
+        return e = e$;
+      }
+    };
+    dt.deleteTable = function(){
+      var rep, func, start, end, line, numOfLinesAbove, numOfLinesBelow, e;
+      rep = this.context.rep;
+      func = 'deleteTable()';
+      start = rep.seStart;
+      end = rep.seEnd;
+      try {
+        line = rep.selStart[0] - 1;
+        numOfLinesAbove = 0;
+        numOfLinesBelow = 0;
+        while (!(rep.lines.atIndex(line).text.indexOf('\uFFF9') === -1)) {
+          numOfLinesAbove++;
+          line--;
+        }
+        line = rep.selEnd[0] + 1;
+        while (!(rep.lines.atIndex(line).text.indexOf('\uFFF9') === -1)) {
+          numOfLinesBelow++;
+          line++;
+        }
+        rep.selStart[1] = 0;
+        rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
+        rep.selEnd[0] = rep.selEnd[0] + numOfLinesBelow;
+        rep.selEnd[1] = rep.lines.atIndex(rep.selEnd[0]).text.length;
+        return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+      } catch (e$) {
+        return e = e$;
+      }
+    };
+    dt.deleteTblRow = function(){
+      var func, rep, currLineText, updateEvenOddBgColor, e;
+      func = 'deleteTblRow()';
+      rep = this.context.rep;
+      try {
+        currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+        if (currLineText.indexOf('\uFFF9') === -1) {
+          return;
+        }
+        rep.selEnd[0] = rep.selStart[0] + 1;
+        rep.selStart[1] = 0;
+        rep.selEnd[1] = 0;
+        this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+        currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+        if (currLineText.indexOf('\uFFF9') === -1) {
+          return;
+        }
+        this.updateAuthorAndCaretPos(rep.selStart[0], 0, 0);
+        updateEvenOddBgColor = true;
+        return this.sanitizeTblProperties(rep.selStart, updateEvenOddBgColor);
+      } catch (e$) {
+        return e = e$;
+      }
+    };
+    dt.updateTableProperties = function(props){
+      var rep, currTd, currLine, currLineText, tblJSONObj, payload, currTdInfo, start, numOfLinesAbove, tempStart, results$ = [];
+      rep = this.context.rep;
+      currTd = null;
+      if (props.tblColWidth || props.tblSingleColBgColor || props.tblColVAlign) {
+        currLine = rep.lines.atIndex(rep.selStart[0]);
+        currLineText = currLine.text;
+        tblJSONObj = fromEscapedJSON(currLineText);
+        payload = tblJSONObj.payload;
+        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+        currTd = currTdInfo.td;
+      }
+      if (props.tblWidth || props.tblHeight || props.tblBorderWidth || props.tblBorderColor || props.tblColWidth || props.tblSingleColBgColor || props.tblEvenRowBgColor || props.tblOddRowBgColor || props.tblColVAlign) {
+        start = [];
+        start[0] = rep.selStart[0];
+        start[1] = rep.selStart[1];
+        numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
+        tempStart = [];
+        tempStart[0] = start[0] - numOfLinesAbove;
+        tempStart[1] = start[1];
+        while (tempStart[0] < rep.lines.length() && rep.lines.atIndex(tempStart[0]).text.indexOf('\uFFF9') !== -1) {
+          if (props.tblEvenRowBgColor && tempStart[0] % 2 !== 0) {
+            tempStart[0] = tempStart[0] + 1;
+            continue;
+          } else {
+            if (props.tblOddRowBgColor && tempStart[0] % 2 === 0) {
+              tempStart[0] = tempStart[0] + 1;
+              continue;
+            }
+          }
+          this.updateTablePropertiesHelper(props, tempStart, currTd);
+          results$.push(tempStart[0] = tempStart[0] + 1);
+        }
+        return results$;
+      } else {
+        start = [];
+        start[0] = rep.selStart[0];
+        start[1] = rep.selStart[1];
+        return this.updateTablePropertiesHelper(props, start, currTd);
+      }
+    };
+    dt.addCellAttr = function(start, tblJSONObj, tblProperties, attrName, attrValue){
+      var rep, payload, currTdInfo, currRow, currTd, cellAttrs, row, cell;
+      rep = this.context.rep;
+      payload = tblJSONObj.payload;
+      currTdInfo = this.getFocusedTdInfo(payload, start[1]);
+      currRow = currTdInfo.row;
+      currTd = currTdInfo.td;
+      cellAttrs = tblProperties.cellAttrs;
+      row = cellAttrs[currRow];
+      if (row == null || typeof row === 'undefined') {
+        row = [];
+      }
+      cell = row[currTd];
+      if (cell == null || typeof cell === 'undefined') {
+        cell = {};
+      }
+      if (attrName === 'fontWeight' || attrName === 'fontStyle' || attrName === 'textDecoration') {
+        if (cell[attrName] === attrValue) {
+          attrValue = '';
+        }
+      } else if (cell[attrName] === attrValue) {
+        return false;
+      }
+      cell[attrName] = attrValue;
+      row[currTd] = cell;
+      cellAttrs[currRow] = row;
+      tblProperties.cellAttrs = cellAttrs;
+      return tblProperties;
+    };
+    dt.addRowAttr = function(tblJSONObj, tblProperties, attrName, attrValue){
+      var rep, rowAttrs, payload, currTdInfo, currRow, singleRowAttrs;
+      rep = this.context.rep;
+      rowAttrs = tblProperties.rowAttrs;
+      if (attrName === 'bgColor') {
+        payload = tblJSONObj.payload;
+        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+        currRow = currTdInfo.row;
+        singleRowAttrs = rowAttrs.singleRowAttrs;
+        if (singleRowAttrs == null || typeof singleRowAttrs === 'undefined') {
+          singleRowAttrs = [];
+        }
+        if (singleRowAttrs[currRow] == null || typeof singleRowAttrs[currRow] === 'undefined') {
+          singleRowAttrs[currRow] = {};
+        } else if (singleRowAttrs[currRow][attrName] === attrValue) {
+          return false;
+        }
+        singleRowAttrs[currRow][attrName] = attrValue;
+        rowAttrs.singleRowAttrs = singleRowAttrs;
+      } else {
+        if (rowAttrs[attrName] === attrValue) {
+          return false;
+        }
+        rowAttrs[attrName] = attrValue;
+      }
+      tblProperties.rowAttrs = rowAttrs;
+      return tblProperties;
+    };
+    dt.addColumnAttr = function(start, tblJSONObj, tblProperties, attrName, attrValue, currTd){
+      var payload, currTdInfo, colAttrs;
+      payload = tblJSONObj.payload;
+      currTdInfo = this.getFocusedTdInfo(payload, start[1]);
+      colAttrs = tblProperties.colAttrs;
+      if (colAttrs == null || typeof colAttrs === 'undefined') {
+        colAttrs = [];
+      }
+      if (colAttrs[currTd] == null || typeof colAttrs[currTd] === 'undefined') {
+        colAttrs[currTd] = {};
+      } else if (colAttrs[currTd][attrName] === attrValue) {
+        return false;
+      }
+      colAttrs[currTd][attrName] = attrValue;
+      tblProperties.colAttrs = colAttrs;
+      return tblProperties;
+    };
+    dt.updateTablePropertiesHelper = function(props, start, currTd){
+      var rep, lastTblPropertyUsed, currLine, currLineText, tblJSONObj, tblProperties, update, currAttrValue, tblProps, e;
+      rep = this.context.rep;
+      lastTblPropertyUsed = 'updateTableProperties';
+      start = start || rep.selStart;
+      if (!start) {
+        return;
+      }
+      currLine = rep.lines.atIndex(start[0]);
+      currLineText = currLine.text;
+      if (currLineText.indexOf('\uFFF9') === -1) {
+        return true;
+      }
+      try {
+        tblJSONObj = fromEscapedJSON(currLineText);
+        tblProperties = this.getLineTableProperty(start[0]);
+        update = false;
+        if (props.tblWidth || props.tblHeight || props.tblBorderWidth || props.tblBorderColor) {
+          currAttrValue = tblProperties[props.attrName];
+          if (props.attrValue != null && (typeof currAttrValue === 'undefined' || currAttrValue !== props.attrValue)) {
+            tblProperties[props.attrName] = props.attrValue;
+            update = true;
+          }
+        }
+        if (props.tblCellFontWeight || props.tblCellFontStyle || props.tblCellTextDecoration) {
+          tblProps = this.addCellAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue);
+          if (tblProps) {
+            tblProperties = tblProps;
+            update = true;
+          }
+        }
+        if (props.tblCellFontSize || props.tblCellBgColor || props.tblCellHeight || props.tblCellPadding || props.tblcellVAlign) {
+          tblProps = this.addCellAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue);
+          if (tblProps) {
+            tblProperties = tblProps;
+            update = true;
+          }
+        }
+        if (props.tblEvenRowBgColor || props.tblOddRowBgColor) {
+          tblProps = this.addRowAttr(tblJSONObj, tblProperties, props.attrName, props.attrValue);
+          if (tblProps) {
+            tblProperties = tblProps;
+            update = true;
+          }
+        }
+        if (props.tblSingleRowBgColor || props.tblRowVAlign) {
+          tblProps = this.addRowAttr(tblJSONObj, tblProperties, props.attrName, props.attrValue);
+          if (tblProps) {
+            tblProperties = tblProps;
+            update = true;
+          }
+        }
+        if (props.tblColWidth || props.tblSingleColBgColor || props.tblColVAlign) {
+          tblProps = this.addColumnAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue, currTd);
+          if (tblProps) {
+            tblProperties = tblProps;
+            update = true;
+          }
+        }
+        if (update) {
+          return this.updateTblPropInAPool(-1, -1, tblProperties, start);
+        }
+      } catch (e$) {
+        return e = e$;
+      }
+    };
+    dt.updateAuthorAndCaretPos = function(magicDomLineNum, tblRowNum, tblColNum){
+      var rep, row, col;
+      rep = this.context.rep;
+      rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
+      rep.selStart[0] = rep.selEnd[0] = magicDomLineNum;
+      row = typeof tblRowNum === 'undefined' || tblRowNum == null ? 0 : tblRowNum;
+      col = typeof tblColNum === 'undefined' || tblRowNum == null ? 0 : tblColNum;
+      this.updateTblPropInAPool(row, col, null, rep.selStart);
+      rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
+      return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+    };
+    dt.insertTblRowBelow = function(numOfRows, table){
+      var rep, currLineText, payload, tblPayload, tblRows, i, tableObj;
+      rep = this.rep;
+      currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+      payload = [[]];
+      if (!numOfRows && numOfRows !== 0) {
+        tblPayload = fromEscapedJSON(currLineText).payload;
+        numOfRows = tblPayload[0].length;
+      }
+      tblRows = new Array(numOfRows);
+      if (!(numOfRows === 0)) {
+        i = 0;
+        while (i < tblRows.length) {
+          tblRows[i] = ' ';
+          i++;
+        }
+      }
+      payload = [tblRows];
+      if (table) {
+        payload = table.payload;
+      }
+      tableObj = {
+        payload: payload,
+        tblId: 1,
+        tblClass: '\uFFF9',
+        trClass: 'alst',
+        tdClass: 'hide-el'
+      };
+      rep.selEnd[1] = rep.selStart[1] = currLineText.length;
+      this.context.editorInfo.ace_doReturnKey();
+      return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, escapedJSON(tableObj));
+    };
+    dt.createDefaultTblProperties = function(authors){
+      var rep, defTblProp, prevLine, jsoTblProp, prevLineText, nextLine, nextLineText, jsoStrTblProp;
+      rep = this.context.rep;
+      defTblProp = {
+        borderWidth: '1',
+        cellAttrs: [],
+        width: '6',
+        rowAttrs: {},
+        colAttrs: [],
+        authors: {}
+      };
+      if (authors) {
+        defTblProp['authors'] = authors;
+      }
+      prevLine = rep.lines.atIndex(rep.selEnd[0] - 1);
+      jsoTblProp = null;
+      if (prevLine) {
+        prevLineText = prevLine.text;
+        if (!(prevLineText.indexOf('\uFFF9') === -1)) {
+          jsoTblProp = this.getLineTableProperty(rep.selStart[0] - 1);
+        }
+      }
+      if (!jsoTblProp) {
+        nextLine = rep.lines.atIndex(rep.selEnd[0] - 1);
+        if (nextLine) {
+          nextLineText = nextLine.text;
+          if (!(nextLineText.indexOf('\uFFF9') === -1)) {
+            jsoTblProp = this.getLineTableProperty(rep.selStart[0] + 1);
+          }
+        }
+      }
+      if (jsoTblProp) {
+        defTblProp.borderWidth = jsoTblProp.borderWidth;
+        defTblProp.borderColor = jsoTblProp.borderColor;
+        defTblProp.width = jsoTblProp.width;
+        defTblProp.height = jsoTblProp.height;
+        defTblProp.colAttrs = jsoTblProp.colAttrs;
+      }
+      jsoStrTblProp = JSON.stringify(defTblProp);
+      return jsoStrTblProp;
+    };
+    dt.performDocApplyTblAttrToRow = function(start, jsoStrTblProp){
+      var tempStart, tempEnd;
+      tempStart = [];
+      tempEnd = [];
+      tempStart[0] = start[0];
+      tempEnd[0] = start[0];
+      tempStart[1] = 0;
+      tempEnd[1] = this.context.rep.lines.atIndex(start[0]).text.length;
+      return this.context.editorInfo.ace_performDocumentApplyAttributesToRange(tempStart, tempEnd, [['tblProp', jsoStrTblProp]]);
+    };
+    dt.performDocumentTableTabKey = function(){
+      var context, rep, currLine, currLineText, tblJSONObj, payload, currTdInfo, leftOverTdTxtLen, currRow, currTd, nextLine, nextLineText, updateEvenOddBgColor, start, nextTdTxtLen, e;
+      try {
+        context = this.context;
+        rep = context.rep;
+        currLine = rep.lines.atIndex(rep.selStart[0]);
+        currLineText = currLine.text;
+        tblJSONObj = fromEscapedJSON(currLineText);
+        payload = tblJSONObj.payload;
+        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+        leftOverTdTxtLen = currTdInfo.leftOverTdTxtLen;
+        currRow = currTdInfo.row;
+        currTd = currTdInfo.td;
+        if (typeof payload[currRow][currTd + 1] === 'undefined') {
+          currRow += 1;
+          nextLine = rep.lines.atIndex(rep.selStart[0] + 1);
+          nextLineText = nextLine.text;
+          updateEvenOddBgColor = false;
+          if (nextLineText == null || nextLineText === '' || nextLineText.indexOf('\uFFF9') === -1) {
+            this.insertTblRowBelow(null, null);
+            this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
+            rep.selEnd[1] = rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE;
+            updateEvenOddBgColor = true;
+          } else {
+            currTd = -1;
+            rep.selStart[0] = rep.selEnd[0] = rep.selStart[0] + 1;
+            tblJSONObj = fromEscapedJSON(nextLineText);
+            payload = tblJSONObj.payload;
+            leftOverTdTxtLen = payload[0][0].length;
+            rep.selEnd[1] = rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE + leftOverTdTxtLen;
+          }
+          context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+          start = [];
+          start[0] = rep.selStart[0];
+          start[1] = rep.selStart[1];
+          return dt.updateTblCellAuthor(0, 0, null, start, updateEvenOddBgColor);
+        } else {
+          nextTdTxtLen = typeof payload[currRow] === 'undefined'
+            ? -leftOverTdTxtLen
+            : payload[currRow][currTd + 1].length;
+          payload = tblJSONObj.payload;
+          rep.selStart[1] = rep.selEnd[1] = rep.selEnd[1] + nextTdTxtLen + leftOverTdTxtLen;
+          context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+          return dt.updateTblPropInAPool(currRow, currTd + 1, null, rep.selStart);
+        }
+      } catch (e$) {
+        return e = e$;
+      }
+    };
+    dt.getTdInfo = function(payload, tdIndex){
+      var rep, startOffset, rowStartOffset, payloadSum, tds, tIndex, tLen, overHeadLen;
+      rep = this.context.rep;
+      startOffset = this.vars.OVERHEAD_LEN_PRE;
+      rowStartOffset = startOffset;
+      payloadSum = startOffset;
+      tds = payload[0];
+      tIndex = 0;
+      tLen = tds.length;
+      while (tIndex < tLen) {
+        overHeadLen = this.vars.OVERHEAD_LEN_MID;
+        if (tIndex === tLen - 1) {
+          overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
+        }
+        payloadSum += tds[tIndex].length + overHeadLen;
+        if (tIndex >= tdIndex) {
+          return {
+            cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
+            cellEndOffset: payloadSum
+          };
+        }
+        tIndex++;
+      }
+    };
+    dt.getNextTdInfo = function(payload, currTdInfo){
+      var rep, startOffset, rowStartOffset, payloadSum, tds, tIndex, tLen, overHeadLen, leftOverTdTxtLen, rowEndOffset, tdInfo;
+      rep = this.context.rep;
+      startOffset = currTdInfo.rowEndOffset;
+      rowStartOffset = startOffset;
+      payloadSum = startOffset;
+      tds = payload[currTdInfo.row];
+      tIndex = 0;
+      tLen = tds.length;
+      while (tIndex < tLen) {
+        overHeadLen = this.vars.OVERHEAD_LEN_MID;
+        if (tIndex === tLen - 1) {
+          overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
+        }
+        payloadSum += tds[tIndex].length + overHeadLen;
+        if (tIndex >= currTdInfo.td) {
+          leftOverTdTxtLen = payloadSum - startOffset === 0
+            ? payload[currTdInfo.row + 1][tIndex].length + this.vars.OVERHEAD_LEN_MID
+            : payloadSum - startOffset;
+          rowEndOffset = this._getRowEndOffset(rowStartOffset, tds);
+          tdInfo = {
+            row: currTdInfo.row + 1,
+            td: tIndex,
+            leftOverTdTxtLen: leftOverTdTxtLen,
+            rowStartOffset: rowStartOffset,
+            rowEndOffset: rowEndOffset,
+            cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
+            cellEndOffset: payloadSum
+          };
+          return tdInfo;
+        }
+        tIndex++;
+      }
+    };
+    dt.insertTblColumn = function(leftOrRight, start, end){
+      var rep, func, currLineText, tblJSONObj, payload, currTdInfo, currTd, numOfLinesAbove, cellPos, newText, updateEvenOddBgColor, updateColAttrs, e;
+      rep = this.context.rep;
+      func = 'insertTblColumn()';
+      try {
+        currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+        tblJSONObj = fromEscapedJSON(currLineText);
+        payload = tblJSONObj.payload;
+        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+        currTd = currTdInfo.td;
+        start = [];
+        end = [];
+        start[0] = rep.selStart[0];
+        start[1] = rep.selStart[1];
+        end[0] = rep.selEnd[0];
+        end[1] = rep.selEnd[1];
+        if (leftOrRight === 'addL') {
+          currTd -= 1;
+        }
+        numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
+        rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
+        while (rep.selStart[0] < rep.lines.length() && rep.lines.atIndex(rep.selStart[0]).text.indexOf('\uFFF9') !== -1) {
+          currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+          tblJSONObj = fromEscapedJSON(currLineText);
+          payload = tblJSONObj.payload;
+          cellPos = this.getTdInfo(payload, currTd).cellEndOffset;
+          newText = '" ",';
+          if (currTd === payload[0].length - 1) {
+            rep.selStart[1] = rep.selEnd[1] = cellPos - this.vars.OVERHEAD_LEN_ROW_END + 1;
+            newText = '," "';
+          } else {
+            if (currTd === -1) {
+              rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE - 1;
+            } else {
+              rep.selStart[1] = rep.selEnd[1] = cellPos - 1;
+            }
+          }
+          this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, newText);
+          rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] + 1;
+        }
+        rep.selStart = start;
+        rep.selEnd = end;
+        if (leftOrRight === 'addL') {
+          rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
+          rep.selStart[0] = rep.selEnd[0] = rep.selStart[0];
+          this.updateTblPropInAPool(0, 0, null, rep.selStart);
+          rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
+        }
+        currTd++;
+        updateEvenOddBgColor = false;
+        updateColAttrs = true;
+        this.sanitizeTblProperties(start, updateEvenOddBgColor, updateColAttrs, currTd, 'add');
+        return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+      } catch (e$) {
+        return e = e$;
+      }
+    };
+    dt.deleteTblColumn = function(){
+      var func, rep, currLineText, tblJSONObj, payload, currTdInfo, currTd, start, end, numOfLinesAbove, cellTdInfo, newText, updateEvenOddBgColor, updateColAttrs, e;
+      func = 'deleteTblColumn()';
+      rep = this.context.rep;
+      try {
+        currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+        tblJSONObj = fromEscapedJSON(currLineText);
+        payload = tblJSONObj.payload;
+        if (payload[0].length === 1) {
+          deleteTable();
+        }
+        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+        currTd = currTdInfo.td;
+        start = [];
+        end = [];
+        start[0] = rep.selStart[0];
+        start[1] = rep.selStart[1];
+        end[0] = rep.selEnd[0];
+        end[1] = rep.selEnd[1];
+        numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
+        rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
+        while (rep.selStart[0] < rep.lines.length() && rep.lines.atIndex(rep.selStart[0]).text.indexOf('\uFFF9') !== -1) {
+          currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+          tblJSONObj = fromEscapedJSON(currLineText);
+          payload = tblJSONObj.payload;
+          cellTdInfo = this.getTdInfo(payload, currTd);
+          newText = '" ",';
+          if (currTd === payload[0].length - 1) {
+            rep.selStart[1] = cellTdInfo.cellStartOffset - 2;
+            rep.selEnd[1] = cellTdInfo.cellEndOffset - 2;
+          } else {
+            if (currTd === 0) {
+              rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE - 1;
+              rep.selEnd[1] = cellTdInfo.cellEndOffset - 1;
+            } else {
+              rep.selStart[1] = cellTdInfo.cellStartOffset - 1;
+              rep.selEnd[1] = cellTdInfo.cellEndOffset - 1;
+            }
+          }
+          this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+          rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] + 1;
+        }
+        rep.selStart = start;
+        rep.selEnd = end;
+        updateEvenOddBgColor = false;
+        updateColAttrs = true;
+        this.sanitizeTblProperties(start, updateEvenOddBgColor, updateColAttrs, currTd, 'del');
+        return this.updateAuthorAndCaretPos(rep.selStart[0], 0, 0);
+      } catch (e$) {
+        return e = e$;
+      }
+    };
+    dt.insertTblRowBelow = function(numOfRows, table){
+      var context, rep, currLineText, payload, tblPayload, tblRows, i, tableObj;
+      context = this.context;
+      rep = context.rep;
+      currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+      payload = [[]];
+      if (!numOfRows && numOfRows !== 0) {
+        tblPayload = fromEscapedJSON(currLineText).payload;
+        numOfRows = tblPayload[0].length;
+      }
+      tblRows = new Array(numOfRows);
+      if (!(numOfRows === 0)) {
+        i = 0;
+        while (i < tblRows.length) {
+          tblRows[i] = ' ';
+          i++;
+        }
+      }
+      payload = [tblRows];
+      if (table) {
+        payload = table.payload;
+      }
+      tableObj = {
+        payload: payload,
+        tblId: 1,
+        tblClass: '\uFFF9',
+        trClass: 'alst',
+        tdClass: 'hide-el'
+      };
+      rep.selEnd[1] = rep.selStart[1] = currLineText.length;
+      this.context.editorInfo.ace_inCallStackIfNecessary('newline', this.context.editorInfo.ace_doReturnKey);
+      return context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, escapedJSON(tableObj));
+    };
+    dt.doReturnKey = function(){
+      var context, rep, start, end, lastTblPropertyUsed, currLine, currLineText, func, currCarretPos, newText, jsonObj, payloadStr, error, e;
+      context = this.context;
+      rep = context.rep;
+      start = rep.seStart;
+      end = rep.selEnd;
+      lastTblPropertyUsed = 'doTableReturnKey';
+      currLine = rep.lines.atIndex(rep.selStart[0]);
+      currLineText = currLine.text;
+      if (!(currLineText.indexOf('\uFFF9') === -1)) {
+        func = 'doTableReturnKey()';
+        try {
+          currCarretPos = rep.selStart[1];
+          if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '","') {
+            return true;
+          } else {
+            if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) === '","') {
+              return true;
+            } else {
+              if (currCarretPos < this.vars.OVERHEAD_LEN_PRE) {
+                return true;
+              } else if (currCarretPos > currLineText.length) {
+                return true;
+              }
+            }
+          }
+          start = rep.selStart;
+          end = rep.selEnd;
+          newText = ' /r/n ';
+          start[1] = currCarretPos;
+          end[1] = currCarretPos;
+          try {
+            jsonObj = fromEscapedJSON(currLineText.substring(0, start[1]) + newText + currLineText.substring(start[1]));
+            payloadStr = escapedJSON(jsonObj.payload);
+            if (currCarretPos > payloadStr.length + this.vars.OVERHEAD_LEN_PRE - 2) {
+              return true;
+            }
+          } catch (e$) {
+            error = e$;
+            return true;
+          }
+          context.editorInfo.ace_performDocumentReplaceRange(start, end, newText);
+        } catch (e$) {
+          e = e$;
+        }
+        return true;
+      }
+    };
+    dt.isCellDeleteOk = function(keyCode){
+      var context, rep, start, end, currLine, currLineText, isDeleteAccepted, tblJSONObj, table, currTdInfo, cellEntryLen, currCarretPos, error;
+      context = this.context;
+      rep = context.rep;
+      start = rep.selStart;
+      end = rep.selEnd;
+      currLine = rep.lines.atIndex(rep.selStart[0]);
+      currLineText = currLine.text;
+      if (currLineText.indexOf('\uFFF9') === -1) {
+        return true;
+      }
+      isDeleteAccepted = false;
+      try {
+        tblJSONObj = fromEscapedJSON(currLineText);
+        table = tblJSONObj.payload;
+        currTdInfo = this.getFocusedTdInfo(table, rep.selStart[1]);
+        cellEntryLen = table[currTdInfo.row][currTdInfo.td].length;
+        currCarretPos = rep.selStart[1];
+        if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '","') {
+          return false;
+        } else {
+          if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) === '","') {
+            return false;
+          }
+        }
+        switch (keyCode) {
+        case this.vars.JS_KEY_CODE_BS:
+          if (cellEntryLen !== 0 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
+            isDeleteAccepted = true;
+          }
+          break;
+        case this.vars.JS_KEY_CODE_DEL:
+          return false;
+          if (cellEntryLen !== 0 && currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID > 0) {
+            isDeleteAccepted = true;
+          }
+          break;
+        default:
+          if (cellEntryLen !== 0 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
+            isDeleteAccepted = true;
+          }
+        }
+      } catch (e$) {
+        error = e$;
+        isDeleteAccepted = false;
+      }
+      return isDeleteAccepted;
+    };
+    dt.nodeTextPlain = function(n){
+      return n.innerText || n.textContent || n.nodeValue || '';
+    };
+    dt.toString = function(){
+      return 'ep_tables';
+    };
+    dt.getLineAndCharForPoint = function(){
+      var context, point, root, N, ln, n, col, parNode, prevSib, textLen, lineEntry, lineNum;
+      context = this.context;
+      point = context.point;
+      root = context.root;
+      if (point.node === root) {
+        if (point.index === 0) {
+          return [0, 0];
+        } else {
+          N = this.context.rep.lines.length();
+          ln = this.context.rep.lines.atIndex(N - 1);
+          return [N - 1, ln.text.length];
+        }
+      } else {
+        n = point.node;
+        col = 0;
+        if (nodeText(n) || point.index > 0) {
+          col = point.index;
+        }
+        parNode = void 8;
+        prevSib = void 8;
+        while (!((parNode = n.parentNode) === root)) {
+          if (prevSib = n.previousSibling) {
+            n = prevSib;
+            textLen = nodeText(n).length === 0
+              ? this.nodeTextPlain(n).length
+              : nodeText(n).length;
+            col += textLen;
+          } else {
+            n = parNode;
+          }
+        }
+        if (n.id === '') {
+          console.debug('BAD');
+        }
+        if (n.firstChild && context.editorInfo.ace_isBlockElement(n.firstChild)) {
+          col += 1;
+        }
+        lineEntry = this.context.rep.lines.atKey(n.id);
+        lineNum = this.context.rep.lines.indexOfEntry(lineEntry);
+        return [lineNum, col];
+      }
+    };
+    dt.doDeleteKey = function(){
+      var context, evt, handled, rep, editorInfo, lineNum, col, lineEntry, lineText, lineMarker, col2, tabSize, toDelete, theLine, action, prevLineListType, thisLineListType, prevLineEntry, prevLineBlank, docChar, deleteBackTo, returnKeyWitinTblOffset, line;
+      context = this.context;
+      evt = context.evt || {};
+      handled = false;
+      rep = this.context.rep;
+      editorInfo = context.editorInfo;
+      if (rep.selStart) {
+        if (editorInfo.ace_isCaret()) {
+          lineNum = editorInfo.ace_caretLine();
+          col = editorInfo.ace_caretColumn();
+          lineEntry = rep.lines.atIndex(lineNum);
+          lineText = lineEntry.text;
+          lineMarker = lineEntry.lineMarker;
+          if (/^ +$/.exec(lineText.substring(lineMarker, col))) {
+            col2 = col - lineMarker;
+            tabSize = ''.length;
+            toDelete = (col2 - 1) % tabSize + 1;
+            editorInfo.ace_performDocumentReplaceRange([lineNum, col - toDelete], [lineNum, col], '');
+            handled = true;
+          }
+        }
+        if (!handled) {
+          if (editorInfo.ace_isCaret()) {
+            theLine = editorInfo.ace_caretLine();
+            lineEntry = rep.lines.atIndex(theLine);
+            if (editorInfo.ace_caretColumn() <= lineEntry.lineMarker) {
+              action = 'delete_newline';
+              prevLineListType = theLine > 0 ? editorInfo.ace_getLineListType(theLine - 1) : '';
+              thisLineListType = editorInfo.ace_getLineListType(theLine);
+              prevLineEntry = theLine > 0 && rep.lines.atIndex(theLine - 1);
+              prevLineBlank = prevLineEntry && prevLineEntry.text.length === prevLineEntry.lineMarker;
+              if (thisLineListType) {
+                if (prevLineBlank && !prevLineListType) {
+                  editorInfo.ace_performDocumentReplaceRange([theLine - 1, prevLineEntry.text.length], [theLine, 0], '');
+                } else {
+                  editorInfo.ace_performDocumentReplaceRange([theLine, 0], [theLine, lineEntry.lineMarker], '');
+                }
+              } else {
+                if (theLine > 0) {
+                  editorInfo.ace_performDocumentReplaceRange([theLine - 1, prevLineEntry.text.length], [theLine, 0], '');
+                }
+              }
+            } else {
+              docChar = editorInfo.ace_caretDocChar();
+              if (docChar > 0) {
+                if (evt.metaKey || evt.ctrlKey || evt.altKey) {
+                  deleteBackTo = docChar - 1;
+                  while (deleteBackTo > lineEntry.lineMarker && editorInfo.ace_isWordChar(rep.alltext.charAt(deleteBackTo - 1))) {
+                    deleteBackTo--;
+                  }
+                  editorInfo.ace_performDocumentReplaceCharRange(deleteBackTo, docChar, '');
+                } else {
+                  returnKeyWitinTblOffset = 0;
+                  if (lineText.substring(col - 5, col) === '/r/n ') {
+                    returnKeyWitinTblOffset = 4;
+                  }
+                  editorInfo.ace_performDocumentReplaceCharRange(docChar - 1 - returnKeyWitinTblOffset, docChar, '');
+                }
+              }
+            }
+          } else {
+            editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+          }
+        }
+      }
+      line = editorInfo.ace_caretLine();
+      if (line !== -1 && editorInfo.ace_renumberList(line + 1) === null) {
+        return editorInfo.ace_renumberList(line);
+      }
+    };
+    dt.getLineTableProperty = function(lineNum){
+      var rep, aline, opIter, tblJSString, error;
+      rep = this.context.rep;
+      aline = rep.alines[lineNum];
+      if (aline) {
+        opIter = Changeset.opIterator(aline);
+        if (opIter.hasNext()) {
+          tblJSString = Changeset.opAttributeValue(opIter.next(), 'tblProp', rep.apool);
+          try {
+            return JSON.parse(tblJSString);
+          } catch (e$) {
+            error = e$;
+            return this.defaults.tblProps;
+          }
+        }
+      }
+      return this.defaults.tblProps;
+    };
+    dt.updateTblPropInAPool = function(row, td, jsoTblProp, start){
+      var rep, tblProps, editorInfo, thisAuthor, authorInfos, jsoStrTblProp, attrStart, attrEnd, e;
+      try {
+        rep = this.context.rep;
+        tblProps = void 8;
+        editorInfo = this.context.editorInfo;
+        thisAuthor = editorInfo.ace_getAuthor();
+        authorInfos = editorInfo.ace_getAuthorInfos();
+        if (typeof jsoTblProp === 'undefined' || jsoTblProp == null) {
+          jsoTblProp = this.getLineTableProperty(start[0]);
+        }
+        if (row !== -1 && td !== -1) {
+          jsoTblProp['authors'][thisAuthor] = {
+            row: row,
+            cell: td,
+            colorId: authorInfos[thisAuthor].bgcolor
+          };
+        }
+        jsoStrTblProp = JSON.stringify(jsoTblProp);
+        attrStart = [];
+        attrEnd = [];
+        attrStart[0] = start[0];
+        attrStart[1] = 0;
+        attrEnd[0] = start[0];
+        attrEnd[1] = rep.lines.atIndex(start[0]).text.length;
+        return editorInfo.ace_performDocumentApplyAttributesToRange(attrStart, attrEnd, [['tblProp', jsoStrTblProp]]);
+      } catch (e$) {
+        return e = e$;
+      }
+    };
+    dt.getCurrTblOddEvenRowBgColor = function(startRowNum, currRowNum){
+      var rowBgColors, jsoTblProp1, jsoTblProp2;
+      rowBgColors = {
+        oddBgColor: null,
+        evenBgColor: null
+      };
+      if (!(startRowNum === currRowNum)) {
+        jsoTblProp1 = this.getLineTableProperty(startRowNum);
+        jsoTblProp2 = this.getLineTableProperty(startRowNum + 1);
+        rowBgColors.evenBgColor = jsoTblProp1['rowAttrs']['evenBgColor'] || jsoTblProp2['rowAttrs']['evenBgColor'];
+        rowBgColors.oddBgColor = jsoTblProp1['rowAttrs']['oddBgColor'] || jsoTblProp2['rowAttrs']['oddBgColor'];
+      }
+      return rowBgColors;
+    };
+    dt.getTblAboveRowsFromCurFocus = function(start){
+      var rep, numOfLinesAbove, line;
+      rep = this.context.rep;
+      numOfLinesAbove = 0;
+      line = start[0] - 1;
+      while (!(rep.lines.atIndex(line).text.indexOf('\uFFF9') === -1)) {
+        numOfLinesAbove++;
+        line--;
+      }
+      return numOfLinesAbove;
+    };
+    dt.updateTableIndices = function(tblProperties, currTd, addOrDel){
+      var cellAttrs, rIndex, rLen, cellAttr, colAttrs;
+      cellAttrs = tblProperties.cellAttrs;
+      rIndex = 0;
+      rLen = cellAttrs.length;
+      while (rIndex < rLen) {
+        cellAttr = cellAttrs[rIndex];
+        if (addOrDel === 'add') {
+          if (cellAttr) {
+            cellAttr.splice(currTd, 0, null);
+          }
+        } else {
+          if (cellAttr) {
+            cellAttr.splice(currTd, 1);
+          }
+        }
+        rIndex++;
+      }
+      colAttrs = tblProperties.colAttrs;
+      if (addOrDel === 'add') {
+        if (colAttrs) {
+          colAttrs.splice(currTd, 0, null);
+        }
+      } else {
+        if (colAttrs) {
+          colAttrs.splice(currTd, 1);
+        }
+      }
+      return tblProperties;
+    };
+    dt.sanitizeTblProperties = function(start, updateEvenOddBgColor, updateColAttrs, currTd, addOrDel){
+      var rep, editorInfo, thisAuthor, numOfLinesAbove, tempStart, evenOddRowBgColors, jsoTblProp, update, results$ = [];
+      rep = this.context.rep;
+      editorInfo = this.context.editorInfo;
+      thisAuthor = editorInfo.ace_getAuthor();
+      numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
+      tempStart = [];
+      tempStart[0] = start[0] - numOfLinesAbove;
+      evenOddRowBgColors = {};
+      updateEvenOddBgColor;
+      while (tempStart[0] < rep.lines.length() && rep.lines.atIndex(tempStart[0]).text.indexOf('\uFFF9') !== -1) {
+        jsoTblProp = this.getLineTableProperty(tempStart[0]);
+        update = false;
+        if (tempStart[0] !== start[0] && jsoTblProp['authors'] && jsoTblProp['authors'][thisAuthor]) {
+          delete jsoTblProp['authors'][thisAuthor];
+          update = true;
+        }
+        if (updateColAttrs) {
+          jsoTblProp = this.updateTableIndices(jsoTblProp, currTd, addOrDel);
+          update = true;
+        }
+        if (tempStart[0] !== start[0] && updateEvenOddBgColor) {
+          delete jsoTblProp['rowAttrs']['oddBgColor'];
+          delete jsoTblProp['rowAttrs']['evenBgColor'];
+          update = true;
+        }
+        if (update) {
+          this.updateTblPropInAPool(-1, -1, jsoTblProp, tempStart);
+        }
+        results$.push(tempStart[0] = tempStart[0] + 1);
+      }
+      return results$;
+    };
+    dt.updateTblPropInAPool = function(row, td, jsoTblProp, start){
+      var rep, editorInfo, thisAuthor, authorInfos, tblProps, jsoStrTblProp, attrStart, attrEnd, e;
+      try {
+        rep = this.context.rep;
+        editorInfo = this.context.editorInfo;
+        thisAuthor = editorInfo.ace_getAuthor();
+        authorInfos = editorInfo.ace_getAuthorInfos();
+        tblProps = void 8;
+        if (typeof jsoTblProp === 'undefined' || jsoTblProp == null) {
+          jsoTblProp = this.getLineTableProperty(start[0]);
+        }
+        if (row !== -1 && td !== -1) {
+          jsoTblProp['authors'][thisAuthor] = {
+            row: row,
+            cell: td,
+            colorId: authorInfos[thisAuthor].bgcolor
+          };
+        }
+        jsoStrTblProp = JSON.stringify(jsoTblProp);
+        attrStart = [];
+        attrEnd = [];
+        attrStart[0] = start[0];
+        attrStart[1] = 0;
+        attrEnd[0] = start[0];
+        attrEnd[1] = rep.lines.atIndex(start[0]).text.length;
+        return editorInfo.ace_performDocumentApplyAttributesToRange(attrStart, attrEnd, [['tblProp', jsoStrTblProp]]);
+      } catch (e$) {
+        return e = e$;
+      }
+    };
+    dt.updateTblCellAuthor = function(row, td, tblProperties, start, updateEvenOddBgColor){
+      var tempStart, e;
+      try {
+        this.updateTblPropInAPool(row, td, tblProperties, start);
+        tempStart = [];
+        tempStart[0] = start[0];
+        tempStart[1] = start[1];
+        return this.sanitizeTblProperties(tempStart, updateEvenOddBgColor);
+      } catch (e$) {
+        return e = e$;
+      }
+    };
+    return dt;
+  }();
+}
+if (typeof exports !== 'undefined') {
+  exports.Datatables = Datatables;
+} else {
+  null;
+}
\ No newline at end of file

From 336120752ca3043f888b511248fb9bad7f4e666c Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Wed, 31 Oct 2012 14:52:39 +0800
Subject: [PATCH 10/36] modernize the Datatables class

---
 src/js/datatables.ls    |   99 +-
 static/js/datatables.js | 2226 +++++++++++++++++++--------------------
 2 files changed, 1157 insertions(+), 1168 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index c4f3de3..2cb4a8c 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -105,8 +105,7 @@ exports.aceKeyEvent = (hook, context) ->
   catch
   specialHandled
 
-if typeof Datatables is 'undefined'
-  Datatables = do ->
+class Datatables
     nodeText = (n) ->
       text = []
       el = void
@@ -122,17 +121,16 @@ if typeof Datatables is 'undefined'
         if el.nodeType is 1 and el.tagName.toLowerCase! of excluded then text.push nodeText el else if el.nodeType is 3 then text.push el.data
         i++
       text.join ''
-    dt = {
-      defaults: {tblProps: {
+    @defaults= {tblProps: {
         borderWidth: '1'
         cellAttrs: []
         width: '6'
         rowAttrs: {}
         colAttrs: []
         authors: {}
-      }}
-      config: {}
-      vars: {
+    }}
+    @config= {}
+    @vars= {
         OVERHEAD_LEN_PRE: '{\uF134payload":[[\uF134'.length
         OVERHEAD_LEN_MID: '\uF134,\uF134'.length
         OVERHEAD_LEN_ROW_START: '[\uF134'.length
@@ -150,17 +148,16 @@ if typeof Datatables is 'undefined'
           'delTblCol'
           'delImg'
         ]
-      }
-      context: null
     }
-    dt.isFocused = ->
+    context: null
+    @isFocused = ->
       return false if not @context.rep.selStart or not @context.rep.selEnd
       line = @context.rep.lines.atIndex @context.rep.selStart.0
       if not line then return false
       currLineText = line.text or ''
       if (currLineText.indexOf '\uFFF9') is -1 then return false
       true
-    dt._getRowEndOffset = (rowStartOffset, tds) ->
+    @_getRowEndOffset = (rowStartOffset, tds) ->
       rowEndOffset = rowStartOffset + @vars.OVERHEAD_LEN_ROW_START
       i = 0
       len = tds.length
@@ -170,7 +167,7 @@ if typeof Datatables is 'undefined'
         rowEndOffset += tds[i].length + overHeadLen
         i++
       rowEndOffset
-    dt.getFocusedTdInfo = (payload, colStart) ->
+    @getFocusedTdInfo = (payload, colStart) ->
       payloadOffset = colStart - @vars.OVERHEAD_LEN_PRE
       rowStartOffset = 0
       payloadSum = 0
@@ -203,10 +200,10 @@ if typeof Datatables is 'undefined'
         rowStartOffset = payloadSum
         payloadSum += @vars.OVERHEAD_LEN_ROW_START
         rIndex++
-    dt.printCaretPos = (start, end) ->
+    @printCaretPos = (start, end) ->
       top.console.log JSON.stringify start
       top.console.log JSON.stringify end
-    dt.doDatatableOptions = (cmd, xByY) ->
+    @doDatatableOptions = (cmd, xByY) ->
       Datatables.context = this
       if typeof cmd is 'object' and cmd.tblPropertyChange
         Datatables.updateTableProperties cmd
@@ -228,7 +225,7 @@ if typeof Datatables is 'undefined'
           Datatables.deleteTblRow!
         case Datatables.vars.TBL_OPTIONS.7
           Datatables.deleteTblColumn!
-    dt.addTable = (tableObj) ->
+    @addTable = (tableObj) ->
       rep = @context.rep
       start = rep.selStart
       end = rep.selEnd
@@ -281,7 +278,7 @@ if typeof Datatables is 'undefined'
         @updateAuthorAndCaretPos rep.selStart.0 - rows + 1
         return 
       newText
-    dt.insertTblRow = (aboveOrBelow) ->
+    @insertTblRow = (aboveOrBelow) ->
       func = 'insertTblRow()'
       rep = @context.rep
       try
@@ -307,7 +304,7 @@ if typeof Datatables is 'undefined'
         updateEvenOddBgColor = true
         @sanitizeTblProperties rep.selStart, updateEvenOddBgColor
       catch
-    dt.deleteTable = ->
+    @deleteTable = ->
       rep = @context.rep
       func = 'deleteTable()'
       start = rep.seStart
@@ -329,7 +326,7 @@ if typeof Datatables is 'undefined'
         rep.selEnd.1 = (rep.lines.atIndex rep.selEnd.0).text.length
         @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
       catch
-    dt.deleteTblRow = ->
+    @deleteTblRow = ->
       func = 'deleteTblRow()'
       rep = @context.rep
       try
@@ -345,7 +342,7 @@ if typeof Datatables is 'undefined'
         updateEvenOddBgColor = true
         @sanitizeTblProperties rep.selStart, updateEvenOddBgColor
       catch
-    dt.updateTableProperties = (props) ->
+    @updateTableProperties = (props) ->
       rep = @context.rep
       currTd = null
       if props.tblColWidth or props.tblSingleColBgColor or props.tblColVAlign
@@ -378,7 +375,7 @@ if typeof Datatables is 'undefined'
         start.0 = rep.selStart.0
         start.1 = rep.selStart.1
         @updateTablePropertiesHelper props, start, currTd
-    dt.addCellAttr = (start, tblJSONObj, tblProperties, attrName, attrValue) ->
+    @addCellAttr = (start, tblJSONObj, tblProperties, attrName, attrValue) ->
       rep = @context.rep
       payload = tblJSONObj.payload
       currTdInfo = @getFocusedTdInfo payload, start.1
@@ -395,7 +392,7 @@ if typeof Datatables is 'undefined'
       cellAttrs[currRow] = row
       tblProperties.cellAttrs = cellAttrs
       tblProperties
-    dt.addRowAttr = (tblJSONObj, tblProperties, attrName, attrValue) ->
+    @addRowAttr = (tblJSONObj, tblProperties, attrName, attrValue) ->
       rep = @context.rep
       rowAttrs = tblProperties.rowAttrs
       if attrName is 'bgColor'
@@ -412,7 +409,7 @@ if typeof Datatables is 'undefined'
         rowAttrs[attrName] = attrValue
       tblProperties.rowAttrs = rowAttrs
       tblProperties
-    dt.addColumnAttr = (start, tblJSONObj, tblProperties, attrName, attrValue, currTd) ->
+    @addColumnAttr = (start, tblJSONObj, tblProperties, attrName, attrValue, currTd) ->
       payload = tblJSONObj.payload
       currTdInfo = @getFocusedTdInfo payload, start.1
       colAttrs = tblProperties.colAttrs
@@ -421,7 +418,7 @@ if typeof Datatables is 'undefined'
       colAttrs[currTd][attrName] = attrValue
       tblProperties.colAttrs = colAttrs
       tblProperties
-    dt.updateTablePropertiesHelper = (props, start, currTd) ->
+    @updateTablePropertiesHelper = (props, start, currTd) ->
       rep = @context.rep
       lastTblPropertyUsed = 'updateTableProperties'
       start = start or rep.selStart
@@ -465,7 +462,7 @@ if typeof Datatables is 'undefined'
             update = true
         if update then @updateTblPropInAPool -1, -1, tblProperties, start
       catch)
-    dt.updateAuthorAndCaretPos = (magicDomLineNum, tblRowNum, tblColNum) ->
+    @updateAuthorAndCaretPos = (magicDomLineNum, tblRowNum, tblColNum) ->
       rep = @context.rep
       rep.selStart.1 = rep.selEnd.1 = @vars.OVERHEAD_LEN_PRE
       rep.selStart.0 = rep.selEnd.0 = magicDomLineNum
@@ -474,7 +471,7 @@ if typeof Datatables is 'undefined'
       @updateTblPropInAPool row, col, null, rep.selStart
       rep.selStart.1 = rep.selEnd.1 = @vars.OVERHEAD_LEN_PRE
       @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
-    dt.insertTblRowBelow = (numOfRows, table) ->
+    @insertTblRowBelow = (numOfRows, table) ->
       rep = @rep
       currLineText = (rep.lines.atIndex rep.selStart.0).text
       payload = [[]]
@@ -499,7 +496,7 @@ if typeof Datatables is 'undefined'
       rep.selEnd.1 = rep.selStart.1 = currLineText.length
       @context.editorInfo.ace_doReturnKey!
       @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, escapedJSON tableObj
-    dt.createDefaultTblProperties = (authors) ->
+    @createDefaultTblProperties = (authors) ->
       rep = @context.rep
       defTblProp = {
         borderWidth: '1'
@@ -528,7 +525,7 @@ if typeof Datatables is 'undefined'
         defTblProp.colAttrs = jsoTblProp.colAttrs
       jsoStrTblProp = JSON.stringify defTblProp
       jsoStrTblProp
-    dt.performDocApplyTblAttrToRow = (start, jsoStrTblProp) ->
+    @performDocApplyTblAttrToRow = (start, jsoStrTblProp) ->
       tempStart = []
       tempEnd = []
       tempStart.0 = start.0
@@ -536,7 +533,7 @@ if typeof Datatables is 'undefined'
       tempStart.1 = 0
       tempEnd.1 = (@context.rep.lines.atIndex start.0).text.length
       @context.editorInfo.ace_performDocumentApplyAttributesToRange tempStart, tempEnd, [['tblProp', jsoStrTblProp]]
-    dt.performDocumentTableTabKey = ->
+    @performDocumentTableTabKey = ->
       try
         context = @context
         rep = context.rep
@@ -569,15 +566,15 @@ if typeof Datatables is 'undefined'
           start = []
           start.0 = rep.selStart.0
           start.1 = rep.selStart.1
-          dt.updateTblCellAuthor 0, 0, null, start, updateEvenOddBgColor
+          @updateTblCellAuthor 0, 0, null, start, updateEvenOddBgColor
         else
           nextTdTxtLen = if typeof payload[currRow] is 'undefined' then -leftOverTdTxtLen else payload[currRow][currTd + 1].length
           payload = tblJSONObj.payload
           rep.selStart.1 = rep.selEnd.1 = rep.selEnd.1 + nextTdTxtLen + leftOverTdTxtLen
           context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
-          dt.updateTblPropInAPool currRow, currTd + 1, null, rep.selStart
+          @updateTblPropInAPool currRow, currTd + 1, null, rep.selStart
       catch
-    dt.getTdInfo = (payload, tdIndex) ->
+    @getTdInfo = (payload, tdIndex) ->
       rep = @context.rep
       startOffset = @vars.OVERHEAD_LEN_PRE
       rowStartOffset = startOffset
@@ -595,7 +592,7 @@ if typeof Datatables is 'undefined'
             cellEndOffset: payloadSum
           }
         tIndex++
-    dt.getNextTdInfo = (payload, currTdInfo) ->
+    @getNextTdInfo = (payload, currTdInfo) ->
       rep = @context.rep
       startOffset = currTdInfo.rowEndOffset
       rowStartOffset = startOffset
@@ -621,7 +618,7 @@ if typeof Datatables is 'undefined'
           }
           return tdInfo
         tIndex++
-    dt.insertTblColumn = (leftOrRight, start, end) ->
+    @insertTblColumn = (leftOrRight, start, end) ->
       rep = @context.rep
       func = 'insertTblColumn()'
       try
@@ -665,7 +662,7 @@ if typeof Datatables is 'undefined'
         @sanitizeTblProperties start, updateEvenOddBgColor, updateColAttrs, currTd, 'add'
         @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
       catch
-    dt.deleteTblColumn = ->
+    @deleteTblColumn = ->
       func = 'deleteTblColumn()'
       rep = @context.rep
       try
@@ -708,7 +705,7 @@ if typeof Datatables is 'undefined'
         @sanitizeTblProperties start, updateEvenOddBgColor, updateColAttrs, currTd, 'del'
         @updateAuthorAndCaretPos rep.selStart.0, 0, 0
       catch
-    dt.insertTblRowBelow = (numOfRows, table) ->
+    @insertTblRowBelow = (numOfRows, table) ->
       context = @context
       rep = context.rep
       currLineText = (rep.lines.atIndex rep.selStart.0).text
@@ -734,7 +731,7 @@ if typeof Datatables is 'undefined'
       rep.selEnd.1 = rep.selStart.1 = currLineText.length
       @context.editorInfo.ace_inCallStackIfNecessary 'newline', @context.editorInfo.ace_doReturnKey
       context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, escapedJSON tableObj
-    dt.doReturnKey = ->
+    @doReturnKey = ->
       context = @context
       rep = context.rep
       start = rep.seStart
@@ -767,7 +764,7 @@ if typeof Datatables is 'undefined'
           context.editorInfo.ace_performDocumentReplaceRange start, end, newText
         catch
         true
-    dt.isCellDeleteOk = (keyCode) ->
+    @isCellDeleteOk = (keyCode) ->
       context = @context
       rep = context.rep
       start = rep.selStart
@@ -797,9 +794,9 @@ if typeof Datatables is 'undefined'
       catch error
         isDeleteAccepted = false)
       isDeleteAccepted
-    dt.nodeTextPlain = (n) -> n.innerText or n.textContent or n.nodeValue or ''
-    dt.toString = -> 'ep_tables'
-    dt.getLineAndCharForPoint = ->
+    @nodeTextPlain = (n) -> n.innerText or n.textContent or n.nodeValue or ''
+    @toString = -> 'ep_tables'
+    @getLineAndCharForPoint = ->
       context = @context
       point = context.point
       root = context.root
@@ -828,7 +825,7 @@ if typeof Datatables is 'undefined'
         lineEntry = @context.rep.lines.atKey n.id
         lineNum = @context.rep.lines.indexOfEntry lineEntry
         [lineNum, col]
-    dt.doDeleteKey = ->
+    @doDeleteKey = ->
       context = @context
       evt = context.evt or {}
       handled = false
@@ -881,7 +878,7 @@ if typeof Datatables is 'undefined'
             editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
       line = editorInfo.ace_caretLine!
       if line isnt -1 and (editorInfo.ace_renumberList line + 1) is null then editorInfo.ace_renumberList line
-    dt.getLineTableProperty = (lineNum) ->
+    @getLineTableProperty = (lineNum) ->
       rep = @context.rep
       aline = rep.alines[lineNum]
       if aline
@@ -893,7 +890,7 @@ if typeof Datatables is 'undefined'
           catch error
             return @defaults.tblProps
       @defaults.tblProps
-    dt.updateTblPropInAPool = (row, td, jsoTblProp, start) ->
+    @updateTblPropInAPool = (row, td, jsoTblProp, start) ->
       try
         rep = @context.rep
         tblProps = void
@@ -916,7 +913,7 @@ if typeof Datatables is 'undefined'
         attrEnd.1 = (rep.lines.atIndex start.0).text.length
         editorInfo.ace_performDocumentApplyAttributesToRange attrStart, attrEnd, [['tblProp', jsoStrTblProp]]
       catch
-    dt.getCurrTblOddEvenRowBgColor = (startRowNum, currRowNum) ->
+    @getCurrTblOddEvenRowBgColor = (startRowNum, currRowNum) ->
       rowBgColors = {
         oddBgColor: null
         evenBgColor: null
@@ -927,7 +924,7 @@ if typeof Datatables is 'undefined'
         rowBgColors.evenBgColor = jsoTblProp1.'rowAttrs'.'evenBgColor' or jsoTblProp2.'rowAttrs'.'evenBgColor'
         rowBgColors.oddBgColor = jsoTblProp1.'rowAttrs'.'oddBgColor' or jsoTblProp2.'rowAttrs'.'oddBgColor'
       rowBgColors
-    dt.getTblAboveRowsFromCurFocus = (start) ->
+    @getTblAboveRowsFromCurFocus = (start) ->
       rep = @context.rep
       numOfLinesAbove = 0
       line = start.0 - 1
@@ -935,7 +932,7 @@ if typeof Datatables is 'undefined'
         numOfLinesAbove++
         line--
       numOfLinesAbove
-    dt.updateTableIndices = (tblProperties, currTd, addOrDel) ->
+    @updateTableIndices = (tblProperties, currTd, addOrDel) ->
       cellAttrs = tblProperties.cellAttrs
       rIndex = 0
       rLen = cellAttrs.length
@@ -946,7 +943,7 @@ if typeof Datatables is 'undefined'
       colAttrs = tblProperties.colAttrs
       if addOrDel is 'add' then colAttrs.splice currTd, 0, null if colAttrs else colAttrs.splice currTd, 1 if colAttrs
       tblProperties
-    dt.sanitizeTblProperties = (start, updateEvenOddBgColor, updateColAttrs, currTd, addOrDel) ->
+    @sanitizeTblProperties = (start, updateEvenOddBgColor, updateColAttrs, currTd, addOrDel) ->
       rep = @context.rep
       editorInfo = @context.editorInfo
       thisAuthor = editorInfo.ace_getAuthor!
@@ -970,7 +967,7 @@ if typeof Datatables is 'undefined'
           update = true
         if update then @updateTblPropInAPool -1, -1, jsoTblProp, tempStart
         tempStart.0 = tempStart.0 + 1
-    dt.updateTblPropInAPool = (row, td, jsoTblProp, start) ->
+    @updateTblPropInAPool = (row, td, jsoTblProp, start) ->
       try
         rep = @context.rep
         editorInfo = @context.editorInfo
@@ -993,14 +990,12 @@ if typeof Datatables is 'undefined'
         attrEnd.1 = (rep.lines.atIndex start.0).text.length
         editorInfo.ace_performDocumentApplyAttributesToRange attrStart, attrEnd, [['tblProp', jsoStrTblProp]]
       catch
-    dt.updateTblCellAuthor = (row, td, tblProperties, start, updateEvenOddBgColor) ->
+    @updateTblCellAuthor = (row, td, tblProperties, start, updateEvenOddBgColor) ->
       try
         @updateTblPropInAPool row, td, tblProperties, start
         tempStart = []
         tempStart.0 = start.0
         tempStart.1 = start.1
         @sanitizeTblProperties tempStart, updateEvenOddBgColor
-      catch
-    dt
 
-if typeof exports isnt 'undefined' then exports.Datatables = Datatables else null
+exports?Datatables = Datatables
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 9a88ee5..b465bdb 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -143,1234 +143,1228 @@ exports.aceKeyEvent = function(hook, context){
   }
   return specialHandled;
 };
-if (typeof Datatables === 'undefined') {
-  Datatables = function(){
-    var nodeText, dt;
-    nodeText = function(n){
-      var text, el, els, excluded, i, iLen;
-      text = [];
-      el = void 8;
-      els = n.childNodes;
-      excluded = {
-        noscript: 'noscript',
-        script: 'script'
-      };
-      i = 0;
-      iLen = els.length;
-      while (i < iLen) {
-        el = els[i];
-        if (el.nodeType === 1 && el.tagName.toLowerCase() in excluded) {
-          text.push(nodeText(el));
-        } else if (el.nodeType === 3) {
-          text.push(el.data);
-        }
-        i++;
-      }
-      return text.join('');
+Datatables = (function(){
+  Datatables.displayName = 'Datatables';
+  var nodeText, prototype = Datatables.prototype, constructor = Datatables;
+  nodeText = function(n){
+    var text, el, els, excluded, i, iLen;
+    text = [];
+    el = void 8;
+    els = n.childNodes;
+    excluded = {
+      noscript: 'noscript',
+      script: 'script'
     };
-    dt = {
-      defaults: {
-        tblProps: {
-          borderWidth: '1',
-          cellAttrs: [],
-          width: '6',
-          rowAttrs: {},
-          colAttrs: [],
-          authors: {}
-        }
-      },
-      config: {},
-      vars: {
-        OVERHEAD_LEN_PRE: '{\uF134payload":[[\uF134'.length,
-        OVERHEAD_LEN_MID: '\uF134,\uF134'.length,
-        OVERHEAD_LEN_ROW_START: '[\uF134'.length,
-        OVERHEAD_LEN_ROW_END: '\uF134],'.length,
-        JS_KEY_CODE_BS: 8,
-        JS_KEY_CODE_DEL: 46,
-        TBL_OPTIONS: ['addTbl', 'addTblRowA', 'addTblRowB', 'addTblColL', 'addTblColR', 'delTbl', 'delTblRow', 'delTblCol', 'delImg']
-      },
-      context: null
-    };
-    dt.isFocused = function(){
-      var line, currLineText;
-      if (!this.context.rep.selStart || !this.context.rep.selEnd) {
-        return false;
-      }
-      line = this.context.rep.lines.atIndex(this.context.rep.selStart[0]);
-      if (!line) {
-        return false;
+    i = 0;
+    iLen = els.length;
+    while (i < iLen) {
+      el = els[i];
+      if (el.nodeType === 1 && el.tagName.toLowerCase() in excluded) {
+        text.push(nodeText(el));
+      } else if (el.nodeType === 3) {
+        text.push(el.data);
       }
-      currLineText = line.text || '';
-      if (currLineText.indexOf('\uFFF9') === -1) {
-        return false;
+      i++;
+    }
+    return text.join('');
+  };
+  Datatables.defaults = {
+    tblProps: {
+      borderWidth: '1',
+      cellAttrs: [],
+      width: '6',
+      rowAttrs: {},
+      colAttrs: [],
+      authors: {}
+    }
+  };
+  Datatables.config = {};
+  Datatables.vars = {
+    OVERHEAD_LEN_PRE: '{\uF134payload":[[\uF134'.length,
+    OVERHEAD_LEN_MID: '\uF134,\uF134'.length,
+    OVERHEAD_LEN_ROW_START: '[\uF134'.length,
+    OVERHEAD_LEN_ROW_END: '\uF134],'.length,
+    JS_KEY_CODE_BS: 8,
+    JS_KEY_CODE_DEL: 46,
+    TBL_OPTIONS: ['addTbl', 'addTblRowA', 'addTblRowB', 'addTblColL', 'addTblColR', 'delTbl', 'delTblRow', 'delTblCol', 'delImg']
+  };
+  prototype.context = null;
+  Datatables.isFocused = function(){
+    var line, currLineText;
+    if (!this.context.rep.selStart || !this.context.rep.selEnd) {
+      return false;
+    }
+    line = this.context.rep.lines.atIndex(this.context.rep.selStart[0]);
+    if (!line) {
+      return false;
+    }
+    currLineText = line.text || '';
+    if (currLineText.indexOf('\uFFF9') === -1) {
+      return false;
+    }
+    return true;
+  };
+  Datatables._getRowEndOffset = function(rowStartOffset, tds){
+    var rowEndOffset, i, len, overHeadLen;
+    rowEndOffset = rowStartOffset + this.vars.OVERHEAD_LEN_ROW_START;
+    i = 0;
+    len = tds.length;
+    while (i < len) {
+      overHeadLen = this.vars.OVERHEAD_LEN_MID;
+      if (i === len - 1) {
+        overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
       }
-      return true;
-    };
-    dt._getRowEndOffset = function(rowStartOffset, tds){
-      var rowEndOffset, i, len, overHeadLen;
-      rowEndOffset = rowStartOffset + this.vars.OVERHEAD_LEN_ROW_START;
-      i = 0;
-      len = tds.length;
-      while (i < len) {
+      rowEndOffset += tds[i].length + overHeadLen;
+      i++;
+    }
+    return rowEndOffset;
+  };
+  Datatables.getFocusedTdInfo = function(payload, colStart){
+    var payloadOffset, rowStartOffset, payloadSum, rIndex, rLen, tds, tIndex, tLen, overHeadLen, leftOverTdTxtLen, cellCaretPos, rowEndOffset;
+    payloadOffset = colStart - this.vars.OVERHEAD_LEN_PRE;
+    rowStartOffset = 0;
+    payloadSum = 0;
+    rIndex = 0;
+    rLen = payload.length;
+    while (rIndex < rLen) {
+      tds = payload[rIndex];
+      tIndex = 0;
+      tLen = tds.length;
+      while (tIndex < tLen) {
         overHeadLen = this.vars.OVERHEAD_LEN_MID;
-        if (i === len - 1) {
+        if (tIndex === tLen - 1) {
           overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
         }
-        rowEndOffset += tds[i].length + overHeadLen;
-        i++;
-      }
-      return rowEndOffset;
-    };
-    dt.getFocusedTdInfo = function(payload, colStart){
-      var payloadOffset, rowStartOffset, payloadSum, rIndex, rLen, tds, tIndex, tLen, overHeadLen, leftOverTdTxtLen, cellCaretPos, rowEndOffset;
-      payloadOffset = colStart - this.vars.OVERHEAD_LEN_PRE;
-      rowStartOffset = 0;
-      payloadSum = 0;
-      rIndex = 0;
-      rLen = payload.length;
-      while (rIndex < rLen) {
-        tds = payload[rIndex];
-        tIndex = 0;
-        tLen = tds.length;
-        while (tIndex < tLen) {
-          overHeadLen = this.vars.OVERHEAD_LEN_MID;
-          if (tIndex === tLen - 1) {
-            overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
-          }
-          payloadSum += tds[tIndex].length + overHeadLen;
-          if (payloadSum >= payloadOffset) {
-            if (payloadSum === payloadOffset) {
-              tIndex++;
-            }
-            leftOverTdTxtLen = payloadSum - payloadOffset === 0
-              ? payload[rIndex][tIndex].length + this.vars.OVERHEAD_LEN_MID
-              : payloadSum - payloadOffset;
-            cellCaretPos = tds[tIndex].length - leftOverTdTxtLen - overHeadLen;
-            rowEndOffset = this._getRowEndOffset(rowStartOffset, tds);
-            return {
-              row: rIndex,
-              td: tIndex,
-              leftOverTdTxtLen: leftOverTdTxtLen,
-              rowStartOffset: rowStartOffset,
-              rowEndOffset: rowEndOffset,
-              cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
-              cellEndOffset: payloadSum,
-              cellCaretPos: cellCaretPos
-            };
+        payloadSum += tds[tIndex].length + overHeadLen;
+        if (payloadSum >= payloadOffset) {
+          if (payloadSum === payloadOffset) {
+            tIndex++;
           }
-          tIndex++;
-        }
-        rowStartOffset = payloadSum;
-        payloadSum += this.vars.OVERHEAD_LEN_ROW_START;
-        rIndex++;
-      }
-    };
-    dt.printCaretPos = function(start, end){
-      top.console.log(JSON.stringify(start));
-      return top.console.log(JSON.stringify(end));
-    };
-    dt.doDatatableOptions = function(cmd, xByY){
-      Datatables.context = this;
-      if (typeof cmd === 'object' && cmd.tblPropertyChange) {
-        return Datatables.updateTableProperties(cmd);
-      } else {
-        switch (cmd) {
-        case Datatables.vars.TBL_OPTIONS[0]:
-          return Datatables.addTable(xByY);
-        case Datatables.vars.TBL_OPTIONS[1]:
-          return Datatables.insertTblRow('addA');
-        case Datatables.vars.TBL_OPTIONS[2]:
-          return Datatables.insertTblRow('addB');
-        case Datatables.vars.TBL_OPTIONS[3]:
-          return Datatables.insertTblColumn('addL');
-        case Datatables.vars.TBL_OPTIONS[4]:
-          return Datatables.insertTblColumn('addR');
-        case Datatables.vars.TBL_OPTIONS[5]:
-          return Datatables.deleteTable();
-        case Datatables.vars.TBL_OPTIONS[6]:
-          return Datatables.deleteTblRow();
-        case Datatables.vars.TBL_OPTIONS[7]:
-          return Datatables.deleteTblColumn();
+          leftOverTdTxtLen = payloadSum - payloadOffset === 0
+            ? payload[rIndex][tIndex].length + this.vars.OVERHEAD_LEN_MID
+            : payloadSum - payloadOffset;
+          cellCaretPos = tds[tIndex].length - leftOverTdTxtLen - overHeadLen;
+          rowEndOffset = this._getRowEndOffset(rowStartOffset, tds);
+          return {
+            row: rIndex,
+            td: tIndex,
+            leftOverTdTxtLen: leftOverTdTxtLen,
+            rowStartOffset: rowStartOffset,
+            rowEndOffset: rowEndOffset,
+            cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
+            cellEndOffset: payloadSum,
+            cellCaretPos: cellCaretPos
+          };
         }
+        tIndex++;
       }
-    };
-    dt.addTable = function(tableObj){
-      var rep, start, end, line, hasMoreRows, isRowAddition, table, currLineText, authors, xByYSelect, cols, rows, jsoStrTblProp, i;
-      rep = this.context.rep;
-      start = rep.selStart;
-      end = rep.selEnd;
-      line = rep.lines.atIndex(rep.selStart[0]);
-      hasMoreRows = null;
-      isRowAddition = null;
-      if (tableObj) {
-        hasMoreRows = tableObj.hasMoreRows;
-        isRowAddition = tableObj.isRowAddition;
-      }
-      if (isRowAddition) {
-        table = fromEscapedJSON(tableObj.tblString);
-        insertTblRowBelow(0, table);
-        performDocApplyTblAttrToRow(rep.selStart, JSON.stringify(table.tblProperties));
-        return;
+      rowStartOffset = payloadSum;
+      payloadSum += this.vars.OVERHEAD_LEN_ROW_START;
+      rIndex++;
+    }
+  };
+  Datatables.printCaretPos = function(start, end){
+    top.console.log(JSON.stringify(start));
+    return top.console.log(JSON.stringify(end));
+  };
+  Datatables.doDatatableOptions = function(cmd, xByY){
+    Datatables.context = this;
+    if (typeof cmd === 'object' && cmd.tblPropertyChange) {
+      return Datatables.updateTableProperties(cmd);
+    } else {
+      switch (cmd) {
+      case Datatables.vars.TBL_OPTIONS[0]:
+        return Datatables.addTable(xByY);
+      case Datatables.vars.TBL_OPTIONS[1]:
+        return Datatables.insertTblRow('addA');
+      case Datatables.vars.TBL_OPTIONS[2]:
+        return Datatables.insertTblRow('addB');
+      case Datatables.vars.TBL_OPTIONS[3]:
+        return Datatables.insertTblColumn('addL');
+      case Datatables.vars.TBL_OPTIONS[4]:
+        return Datatables.insertTblColumn('addR');
+      case Datatables.vars.TBL_OPTIONS[5]:
+        return Datatables.deleteTable();
+      case Datatables.vars.TBL_OPTIONS[6]:
+        return Datatables.deleteTblRow();
+      case Datatables.vars.TBL_OPTIONS[7]:
+        return Datatables.deleteTblColumn();
       }
-      if (line) {
-        currLineText = line.text;
-        if (!(currLineText.indexOf('\uFFF9') === -1)) {
-          for (;;) {
-            rep.selStart[0] = rep.selStart[0] + 1;
-            currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-            if (!(currLineText.indexOf('\uFFF9') !== -1)) {
-              break;
-            }
+    }
+  };
+  Datatables.addTable = function(tableObj){
+    var rep, start, end, line, hasMoreRows, isRowAddition, table, currLineText, authors, xByYSelect, cols, rows, jsoStrTblProp, i;
+    rep = this.context.rep;
+    start = rep.selStart;
+    end = rep.selEnd;
+    line = rep.lines.atIndex(rep.selStart[0]);
+    hasMoreRows = null;
+    isRowAddition = null;
+    if (tableObj) {
+      hasMoreRows = tableObj.hasMoreRows;
+      isRowAddition = tableObj.isRowAddition;
+    }
+    if (isRowAddition) {
+      table = fromEscapedJSON(tableObj.tblString);
+      insertTblRowBelow(0, table);
+      performDocApplyTblAttrToRow(rep.selStart, JSON.stringify(table.tblProperties));
+      return;
+    }
+    if (line) {
+      currLineText = line.text;
+      if (!(currLineText.indexOf('\uFFF9') === -1)) {
+        for (;;) {
+          rep.selStart[0] = rep.selStart[0] + 1;
+          currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+          if (!(currLineText.indexOf('\uFFF9') !== -1)) {
+            break;
           }
-          rep.selEnd[1] = rep.selStart[1] = currLineText.length;
-          this.context.editorInfo.ace_doReturnKey();
-          this.context.editorInfo.ace_doReturnKey();
-        } else {
-          rep.selEnd[1] = rep.selStart[1] = currLineText.length;
-          this.context.editorInfo.ace_doReturnKey();
         }
-      }
-      if (tableObj == null) {
-        authors = {};
-        this.insertTblRowBelow(3);
-        this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
-        this.insertTblRowBelow(3);
-        this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
-        this.insertTblRowBelow(3);
-        this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
+        rep.selEnd[1] = rep.selStart[1] = currLineText.length;
+        this.context.editorInfo.ace_doReturnKey();
+        this.context.editorInfo.ace_doReturnKey();
+      } else {
+        rep.selEnd[1] = rep.selStart[1] = currLineText.length;
         this.context.editorInfo.ace_doReturnKey();
-        this.updateAuthorAndCaretPos(rep.selStart[0] - 3);
-        return;
-      }
-      xByYSelect = typeof tableObj === 'object'
-        ? null
-        : tableObj.split('X');
-      if (xByYSelect != null && xByYSelect.length === 3) {
-        cols = parseInt(xByYSelect[1]);
-        rows = parseInt(xByYSelect[2]);
-        jsoStrTblProp = JSON.stringify(this.createDefaultTblProperties());
-        authors = {};
-        i = 0;
-        while (i < rows) {
-          this.insertTblRowBelow(cols);
-          if (i === 0) {
-            this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
-          } else {
-            this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
-          }
-          i++;
-        }
-        this.updateAuthorAndCaretPos(rep.selStart[0] - rows + 1);
-        return;
       }
-      return newText;
-    };
-    dt.insertTblRow = function(aboveOrBelow){
-      var func, rep, newText, currLineText, payload, currTdInfo, currRow, lastRowOffSet, start, end, updateEvenOddBgColor, e;
-      func = 'insertTblRow()';
-      rep = this.context.rep;
-      try {
-        newText = '';
-        currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-        payload = fromEscapedJSON(currLineText).payload;
-        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-        currRow = currTdInfo.row;
-        lastRowOffSet = 0;
-        start = [];
-        end = [];
-        start[0] = rep.selStart[0];
-        start[1] = rep.selStart[1];
-        end[0] = rep.selStart[0];
-        end[1] = rep.selStart[1];
-        if (aboveOrBelow === 'addA') {
-          rep.selStart[0] = rep.selEnd[0] = rep.selStart[0] - 1;
-          this.insertTblRowBelow(payload[0].length);
+    }
+    if (tableObj == null) {
+      authors = {};
+      this.insertTblRowBelow(3);
+      this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
+      this.insertTblRowBelow(3);
+      this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
+      this.insertTblRowBelow(3);
+      this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
+      this.context.editorInfo.ace_doReturnKey();
+      this.updateAuthorAndCaretPos(rep.selStart[0] - 3);
+      return;
+    }
+    xByYSelect = typeof tableObj === 'object'
+      ? null
+      : tableObj.split('X');
+    if (xByYSelect != null && xByYSelect.length === 3) {
+      cols = parseInt(xByYSelect[1]);
+      rows = parseInt(xByYSelect[2]);
+      jsoStrTblProp = JSON.stringify(this.createDefaultTblProperties());
+      authors = {};
+      i = 0;
+      while (i < rows) {
+        this.insertTblRowBelow(cols);
+        if (i === 0) {
+          this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
         } else {
-          this.insertTblRowBelow(payload[0].length);
+          this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties(authors));
         }
-        this.context.editorInfo.ace_performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
-        this.updateAuthorAndCaretPos(rep.selStart[0]);
-        updateEvenOddBgColor = true;
-        return this.sanitizeTblProperties(rep.selStart, updateEvenOddBgColor);
-      } catch (e$) {
-        return e = e$;
+        i++;
       }
-    };
-    dt.deleteTable = function(){
-      var rep, func, start, end, line, numOfLinesAbove, numOfLinesBelow, e;
-      rep = this.context.rep;
-      func = 'deleteTable()';
-      start = rep.seStart;
-      end = rep.seEnd;
-      try {
-        line = rep.selStart[0] - 1;
-        numOfLinesAbove = 0;
-        numOfLinesBelow = 0;
-        while (!(rep.lines.atIndex(line).text.indexOf('\uFFF9') === -1)) {
-          numOfLinesAbove++;
-          line--;
-        }
-        line = rep.selEnd[0] + 1;
-        while (!(rep.lines.atIndex(line).text.indexOf('\uFFF9') === -1)) {
-          numOfLinesBelow++;
-          line++;
-        }
-        rep.selStart[1] = 0;
-        rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
-        rep.selEnd[0] = rep.selEnd[0] + numOfLinesBelow;
-        rep.selEnd[1] = rep.lines.atIndex(rep.selEnd[0]).text.length;
-        return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
-      } catch (e$) {
-        return e = e$;
+      this.updateAuthorAndCaretPos(rep.selStart[0] - rows + 1);
+      return;
+    }
+    return newText;
+  };
+  Datatables.insertTblRow = function(aboveOrBelow){
+    var func, rep, newText, currLineText, payload, currTdInfo, currRow, lastRowOffSet, start, end, updateEvenOddBgColor, e;
+    func = 'insertTblRow()';
+    rep = this.context.rep;
+    try {
+      newText = '';
+      currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+      payload = fromEscapedJSON(currLineText).payload;
+      currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+      currRow = currTdInfo.row;
+      lastRowOffSet = 0;
+      start = [];
+      end = [];
+      start[0] = rep.selStart[0];
+      start[1] = rep.selStart[1];
+      end[0] = rep.selStart[0];
+      end[1] = rep.selStart[1];
+      if (aboveOrBelow === 'addA') {
+        rep.selStart[0] = rep.selEnd[0] = rep.selStart[0] - 1;
+        this.insertTblRowBelow(payload[0].length);
+      } else {
+        this.insertTblRowBelow(payload[0].length);
       }
-    };
-    dt.deleteTblRow = function(){
-      var func, rep, currLineText, updateEvenOddBgColor, e;
-      func = 'deleteTblRow()';
-      rep = this.context.rep;
-      try {
-        currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-        if (currLineText.indexOf('\uFFF9') === -1) {
-          return;
-        }
-        rep.selEnd[0] = rep.selStart[0] + 1;
-        rep.selStart[1] = 0;
-        rep.selEnd[1] = 0;
-        this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
-        currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-        if (currLineText.indexOf('\uFFF9') === -1) {
-          return;
-        }
-        this.updateAuthorAndCaretPos(rep.selStart[0], 0, 0);
-        updateEvenOddBgColor = true;
-        return this.sanitizeTblProperties(rep.selStart, updateEvenOddBgColor);
-      } catch (e$) {
-        return e = e$;
+      this.context.editorInfo.ace_performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
+      this.updateAuthorAndCaretPos(rep.selStart[0]);
+      updateEvenOddBgColor = true;
+      return this.sanitizeTblProperties(rep.selStart, updateEvenOddBgColor);
+    } catch (e$) {
+      return e = e$;
+    }
+  };
+  Datatables.deleteTable = function(){
+    var rep, func, start, end, line, numOfLinesAbove, numOfLinesBelow, e;
+    rep = this.context.rep;
+    func = 'deleteTable()';
+    start = rep.seStart;
+    end = rep.seEnd;
+    try {
+      line = rep.selStart[0] - 1;
+      numOfLinesAbove = 0;
+      numOfLinesBelow = 0;
+      while (!(rep.lines.atIndex(line).text.indexOf('\uFFF9') === -1)) {
+        numOfLinesAbove++;
+        line--;
       }
-    };
-    dt.updateTableProperties = function(props){
-      var rep, currTd, currLine, currLineText, tblJSONObj, payload, currTdInfo, start, numOfLinesAbove, tempStart, results$ = [];
-      rep = this.context.rep;
-      currTd = null;
-      if (props.tblColWidth || props.tblSingleColBgColor || props.tblColVAlign) {
-        currLine = rep.lines.atIndex(rep.selStart[0]);
-        currLineText = currLine.text;
-        tblJSONObj = fromEscapedJSON(currLineText);
-        payload = tblJSONObj.payload;
-        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-        currTd = currTdInfo.td;
+      line = rep.selEnd[0] + 1;
+      while (!(rep.lines.atIndex(line).text.indexOf('\uFFF9') === -1)) {
+        numOfLinesBelow++;
+        line++;
       }
-      if (props.tblWidth || props.tblHeight || props.tblBorderWidth || props.tblBorderColor || props.tblColWidth || props.tblSingleColBgColor || props.tblEvenRowBgColor || props.tblOddRowBgColor || props.tblColVAlign) {
-        start = [];
-        start[0] = rep.selStart[0];
-        start[1] = rep.selStart[1];
-        numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
-        tempStart = [];
-        tempStart[0] = start[0] - numOfLinesAbove;
-        tempStart[1] = start[1];
-        while (tempStart[0] < rep.lines.length() && rep.lines.atIndex(tempStart[0]).text.indexOf('\uFFF9') !== -1) {
-          if (props.tblEvenRowBgColor && tempStart[0] % 2 !== 0) {
+      rep.selStart[1] = 0;
+      rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
+      rep.selEnd[0] = rep.selEnd[0] + numOfLinesBelow;
+      rep.selEnd[1] = rep.lines.atIndex(rep.selEnd[0]).text.length;
+      return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+    } catch (e$) {
+      return e = e$;
+    }
+  };
+  Datatables.deleteTblRow = function(){
+    var func, rep, currLineText, updateEvenOddBgColor, e;
+    func = 'deleteTblRow()';
+    rep = this.context.rep;
+    try {
+      currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+      if (currLineText.indexOf('\uFFF9') === -1) {
+        return;
+      }
+      rep.selEnd[0] = rep.selStart[0] + 1;
+      rep.selStart[1] = 0;
+      rep.selEnd[1] = 0;
+      this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+      currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+      if (currLineText.indexOf('\uFFF9') === -1) {
+        return;
+      }
+      this.updateAuthorAndCaretPos(rep.selStart[0], 0, 0);
+      updateEvenOddBgColor = true;
+      return this.sanitizeTblProperties(rep.selStart, updateEvenOddBgColor);
+    } catch (e$) {
+      return e = e$;
+    }
+  };
+  Datatables.updateTableProperties = function(props){
+    var rep, currTd, currLine, currLineText, tblJSONObj, payload, currTdInfo, start, numOfLinesAbove, tempStart, results$ = [];
+    rep = this.context.rep;
+    currTd = null;
+    if (props.tblColWidth || props.tblSingleColBgColor || props.tblColVAlign) {
+      currLine = rep.lines.atIndex(rep.selStart[0]);
+      currLineText = currLine.text;
+      tblJSONObj = fromEscapedJSON(currLineText);
+      payload = tblJSONObj.payload;
+      currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+      currTd = currTdInfo.td;
+    }
+    if (props.tblWidth || props.tblHeight || props.tblBorderWidth || props.tblBorderColor || props.tblColWidth || props.tblSingleColBgColor || props.tblEvenRowBgColor || props.tblOddRowBgColor || props.tblColVAlign) {
+      start = [];
+      start[0] = rep.selStart[0];
+      start[1] = rep.selStart[1];
+      numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
+      tempStart = [];
+      tempStart[0] = start[0] - numOfLinesAbove;
+      tempStart[1] = start[1];
+      while (tempStart[0] < rep.lines.length() && rep.lines.atIndex(tempStart[0]).text.indexOf('\uFFF9') !== -1) {
+        if (props.tblEvenRowBgColor && tempStart[0] % 2 !== 0) {
+          tempStart[0] = tempStart[0] + 1;
+          continue;
+        } else {
+          if (props.tblOddRowBgColor && tempStart[0] % 2 === 0) {
             tempStart[0] = tempStart[0] + 1;
             continue;
-          } else {
-            if (props.tblOddRowBgColor && tempStart[0] % 2 === 0) {
-              tempStart[0] = tempStart[0] + 1;
-              continue;
-            }
           }
-          this.updateTablePropertiesHelper(props, tempStart, currTd);
-          results$.push(tempStart[0] = tempStart[0] + 1);
         }
-        return results$;
-      } else {
-        start = [];
-        start[0] = rep.selStart[0];
-        start[1] = rep.selStart[1];
-        return this.updateTablePropertiesHelper(props, start, currTd);
+        this.updateTablePropertiesHelper(props, tempStart, currTd);
+        results$.push(tempStart[0] = tempStart[0] + 1);
       }
-    };
-    dt.addCellAttr = function(start, tblJSONObj, tblProperties, attrName, attrValue){
-      var rep, payload, currTdInfo, currRow, currTd, cellAttrs, row, cell;
-      rep = this.context.rep;
+      return results$;
+    } else {
+      start = [];
+      start[0] = rep.selStart[0];
+      start[1] = rep.selStart[1];
+      return this.updateTablePropertiesHelper(props, start, currTd);
+    }
+  };
+  Datatables.addCellAttr = function(start, tblJSONObj, tblProperties, attrName, attrValue){
+    var rep, payload, currTdInfo, currRow, currTd, cellAttrs, row, cell;
+    rep = this.context.rep;
+    payload = tblJSONObj.payload;
+    currTdInfo = this.getFocusedTdInfo(payload, start[1]);
+    currRow = currTdInfo.row;
+    currTd = currTdInfo.td;
+    cellAttrs = tblProperties.cellAttrs;
+    row = cellAttrs[currRow];
+    if (row == null || typeof row === 'undefined') {
+      row = [];
+    }
+    cell = row[currTd];
+    if (cell == null || typeof cell === 'undefined') {
+      cell = {};
+    }
+    if (attrName === 'fontWeight' || attrName === 'fontStyle' || attrName === 'textDecoration') {
+      if (cell[attrName] === attrValue) {
+        attrValue = '';
+      }
+    } else if (cell[attrName] === attrValue) {
+      return false;
+    }
+    cell[attrName] = attrValue;
+    row[currTd] = cell;
+    cellAttrs[currRow] = row;
+    tblProperties.cellAttrs = cellAttrs;
+    return tblProperties;
+  };
+  Datatables.addRowAttr = function(tblJSONObj, tblProperties, attrName, attrValue){
+    var rep, rowAttrs, payload, currTdInfo, currRow, singleRowAttrs;
+    rep = this.context.rep;
+    rowAttrs = tblProperties.rowAttrs;
+    if (attrName === 'bgColor') {
       payload = tblJSONObj.payload;
-      currTdInfo = this.getFocusedTdInfo(payload, start[1]);
+      currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
       currRow = currTdInfo.row;
-      currTd = currTdInfo.td;
-      cellAttrs = tblProperties.cellAttrs;
-      row = cellAttrs[currRow];
-      if (row == null || typeof row === 'undefined') {
-        row = [];
+      singleRowAttrs = rowAttrs.singleRowAttrs;
+      if (singleRowAttrs == null || typeof singleRowAttrs === 'undefined') {
+        singleRowAttrs = [];
       }
-      cell = row[currTd];
-      if (cell == null || typeof cell === 'undefined') {
-        cell = {};
+      if (singleRowAttrs[currRow] == null || typeof singleRowAttrs[currRow] === 'undefined') {
+        singleRowAttrs[currRow] = {};
+      } else if (singleRowAttrs[currRow][attrName] === attrValue) {
+        return false;
       }
-      if (attrName === 'fontWeight' || attrName === 'fontStyle' || attrName === 'textDecoration') {
-        if (cell[attrName] === attrValue) {
-          attrValue = '';
-        }
-      } else if (cell[attrName] === attrValue) {
+      singleRowAttrs[currRow][attrName] = attrValue;
+      rowAttrs.singleRowAttrs = singleRowAttrs;
+    } else {
+      if (rowAttrs[attrName] === attrValue) {
         return false;
       }
-      cell[attrName] = attrValue;
-      row[currTd] = cell;
-      cellAttrs[currRow] = row;
-      tblProperties.cellAttrs = cellAttrs;
-      return tblProperties;
-    };
-    dt.addRowAttr = function(tblJSONObj, tblProperties, attrName, attrValue){
-      var rep, rowAttrs, payload, currTdInfo, currRow, singleRowAttrs;
-      rep = this.context.rep;
-      rowAttrs = tblProperties.rowAttrs;
-      if (attrName === 'bgColor') {
-        payload = tblJSONObj.payload;
-        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-        currRow = currTdInfo.row;
-        singleRowAttrs = rowAttrs.singleRowAttrs;
-        if (singleRowAttrs == null || typeof singleRowAttrs === 'undefined') {
-          singleRowAttrs = [];
+      rowAttrs[attrName] = attrValue;
+    }
+    tblProperties.rowAttrs = rowAttrs;
+    return tblProperties;
+  };
+  Datatables.addColumnAttr = function(start, tblJSONObj, tblProperties, attrName, attrValue, currTd){
+    var payload, currTdInfo, colAttrs;
+    payload = tblJSONObj.payload;
+    currTdInfo = this.getFocusedTdInfo(payload, start[1]);
+    colAttrs = tblProperties.colAttrs;
+    if (colAttrs == null || typeof colAttrs === 'undefined') {
+      colAttrs = [];
+    }
+    if (colAttrs[currTd] == null || typeof colAttrs[currTd] === 'undefined') {
+      colAttrs[currTd] = {};
+    } else if (colAttrs[currTd][attrName] === attrValue) {
+      return false;
+    }
+    colAttrs[currTd][attrName] = attrValue;
+    tblProperties.colAttrs = colAttrs;
+    return tblProperties;
+  };
+  Datatables.updateTablePropertiesHelper = function(props, start, currTd){
+    var rep, lastTblPropertyUsed, currLine, currLineText, tblJSONObj, tblProperties, update, currAttrValue, tblProps, e;
+    rep = this.context.rep;
+    lastTblPropertyUsed = 'updateTableProperties';
+    start = start || rep.selStart;
+    if (!start) {
+      return;
+    }
+    currLine = rep.lines.atIndex(start[0]);
+    currLineText = currLine.text;
+    if (currLineText.indexOf('\uFFF9') === -1) {
+      return true;
+    }
+    try {
+      tblJSONObj = fromEscapedJSON(currLineText);
+      tblProperties = this.getLineTableProperty(start[0]);
+      update = false;
+      if (props.tblWidth || props.tblHeight || props.tblBorderWidth || props.tblBorderColor) {
+        currAttrValue = tblProperties[props.attrName];
+        if (props.attrValue != null && (typeof currAttrValue === 'undefined' || currAttrValue !== props.attrValue)) {
+          tblProperties[props.attrName] = props.attrValue;
+          update = true;
         }
-        if (singleRowAttrs[currRow] == null || typeof singleRowAttrs[currRow] === 'undefined') {
-          singleRowAttrs[currRow] = {};
-        } else if (singleRowAttrs[currRow][attrName] === attrValue) {
-          return false;
+      }
+      if (props.tblCellFontWeight || props.tblCellFontStyle || props.tblCellTextDecoration) {
+        tblProps = this.addCellAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue);
+        if (tblProps) {
+          tblProperties = tblProps;
+          update = true;
         }
-        singleRowAttrs[currRow][attrName] = attrValue;
-        rowAttrs.singleRowAttrs = singleRowAttrs;
-      } else {
-        if (rowAttrs[attrName] === attrValue) {
-          return false;
+      }
+      if (props.tblCellFontSize || props.tblCellBgColor || props.tblCellHeight || props.tblCellPadding || props.tblcellVAlign) {
+        tblProps = this.addCellAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue);
+        if (tblProps) {
+          tblProperties = tblProps;
+          update = true;
         }
-        rowAttrs[attrName] = attrValue;
       }
-      tblProperties.rowAttrs = rowAttrs;
-      return tblProperties;
-    };
-    dt.addColumnAttr = function(start, tblJSONObj, tblProperties, attrName, attrValue, currTd){
-      var payload, currTdInfo, colAttrs;
-      payload = tblJSONObj.payload;
-      currTdInfo = this.getFocusedTdInfo(payload, start[1]);
-      colAttrs = tblProperties.colAttrs;
-      if (colAttrs == null || typeof colAttrs === 'undefined') {
-        colAttrs = [];
+      if (props.tblEvenRowBgColor || props.tblOddRowBgColor) {
+        tblProps = this.addRowAttr(tblJSONObj, tblProperties, props.attrName, props.attrValue);
+        if (tblProps) {
+          tblProperties = tblProps;
+          update = true;
+        }
       }
-      if (colAttrs[currTd] == null || typeof colAttrs[currTd] === 'undefined') {
-        colAttrs[currTd] = {};
-      } else if (colAttrs[currTd][attrName] === attrValue) {
-        return false;
+      if (props.tblSingleRowBgColor || props.tblRowVAlign) {
+        tblProps = this.addRowAttr(tblJSONObj, tblProperties, props.attrName, props.attrValue);
+        if (tblProps) {
+          tblProperties = tblProps;
+          update = true;
+        }
       }
-      colAttrs[currTd][attrName] = attrValue;
-      tblProperties.colAttrs = colAttrs;
-      return tblProperties;
-    };
-    dt.updateTablePropertiesHelper = function(props, start, currTd){
-      var rep, lastTblPropertyUsed, currLine, currLineText, tblJSONObj, tblProperties, update, currAttrValue, tblProps, e;
-      rep = this.context.rep;
-      lastTblPropertyUsed = 'updateTableProperties';
-      start = start || rep.selStart;
-      if (!start) {
-        return;
+      if (props.tblColWidth || props.tblSingleColBgColor || props.tblColVAlign) {
+        tblProps = this.addColumnAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue, currTd);
+        if (tblProps) {
+          tblProperties = tblProps;
+          update = true;
+        }
       }
-      currLine = rep.lines.atIndex(start[0]);
-      currLineText = currLine.text;
-      if (currLineText.indexOf('\uFFF9') === -1) {
-        return true;
+      if (update) {
+        return this.updateTblPropInAPool(-1, -1, tblProperties, start);
       }
-      try {
-        tblJSONObj = fromEscapedJSON(currLineText);
-        tblProperties = this.getLineTableProperty(start[0]);
-        update = false;
-        if (props.tblWidth || props.tblHeight || props.tblBorderWidth || props.tblBorderColor) {
-          currAttrValue = tblProperties[props.attrName];
-          if (props.attrValue != null && (typeof currAttrValue === 'undefined' || currAttrValue !== props.attrValue)) {
-            tblProperties[props.attrName] = props.attrValue;
-            update = true;
-          }
-        }
-        if (props.tblCellFontWeight || props.tblCellFontStyle || props.tblCellTextDecoration) {
-          tblProps = this.addCellAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue);
-          if (tblProps) {
-            tblProperties = tblProps;
-            update = true;
-          }
-        }
-        if (props.tblCellFontSize || props.tblCellBgColor || props.tblCellHeight || props.tblCellPadding || props.tblcellVAlign) {
-          tblProps = this.addCellAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue);
-          if (tblProps) {
-            tblProperties = tblProps;
-            update = true;
-          }
-        }
-        if (props.tblEvenRowBgColor || props.tblOddRowBgColor) {
-          tblProps = this.addRowAttr(tblJSONObj, tblProperties, props.attrName, props.attrValue);
-          if (tblProps) {
-            tblProperties = tblProps;
-            update = true;
-          }
-        }
-        if (props.tblSingleRowBgColor || props.tblRowVAlign) {
-          tblProps = this.addRowAttr(tblJSONObj, tblProperties, props.attrName, props.attrValue);
-          if (tblProps) {
-            tblProperties = tblProps;
-            update = true;
-          }
-        }
-        if (props.tblColWidth || props.tblSingleColBgColor || props.tblColVAlign) {
-          tblProps = this.addColumnAttr(start, tblJSONObj, tblProperties, props.attrName, props.attrValue, currTd);
-          if (tblProps) {
-            tblProperties = tblProps;
-            update = true;
-          }
-        }
-        if (update) {
-          return this.updateTblPropInAPool(-1, -1, tblProperties, start);
-        }
-      } catch (e$) {
-        return e = e$;
+    } catch (e$) {
+      return e = e$;
+    }
+  };
+  Datatables.updateAuthorAndCaretPos = function(magicDomLineNum, tblRowNum, tblColNum){
+    var rep, row, col;
+    rep = this.context.rep;
+    rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
+    rep.selStart[0] = rep.selEnd[0] = magicDomLineNum;
+    row = typeof tblRowNum === 'undefined' || tblRowNum == null ? 0 : tblRowNum;
+    col = typeof tblColNum === 'undefined' || tblRowNum == null ? 0 : tblColNum;
+    this.updateTblPropInAPool(row, col, null, rep.selStart);
+    rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
+    return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+  };
+  Datatables.insertTblRowBelow = function(numOfRows, table){
+    var rep, currLineText, payload, tblPayload, tblRows, i, tableObj;
+    rep = this.rep;
+    currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+    payload = [[]];
+    if (!numOfRows && numOfRows !== 0) {
+      tblPayload = fromEscapedJSON(currLineText).payload;
+      numOfRows = tblPayload[0].length;
+    }
+    tblRows = new Array(numOfRows);
+    if (!(numOfRows === 0)) {
+      i = 0;
+      while (i < tblRows.length) {
+        tblRows[i] = ' ';
+        i++;
       }
+    }
+    payload = [tblRows];
+    if (table) {
+      payload = table.payload;
+    }
+    tableObj = {
+      payload: payload,
+      tblId: 1,
+      tblClass: '\uFFF9',
+      trClass: 'alst',
+      tdClass: 'hide-el'
     };
-    dt.updateAuthorAndCaretPos = function(magicDomLineNum, tblRowNum, tblColNum){
-      var rep, row, col;
-      rep = this.context.rep;
-      rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
-      rep.selStart[0] = rep.selEnd[0] = magicDomLineNum;
-      row = typeof tblRowNum === 'undefined' || tblRowNum == null ? 0 : tblRowNum;
-      col = typeof tblColNum === 'undefined' || tblRowNum == null ? 0 : tblColNum;
-      this.updateTblPropInAPool(row, col, null, rep.selStart);
-      rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
-      return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+    rep.selEnd[1] = rep.selStart[1] = currLineText.length;
+    this.context.editorInfo.ace_doReturnKey();
+    return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, escapedJSON(tableObj));
+  };
+  Datatables.createDefaultTblProperties = function(authors){
+    var rep, defTblProp, prevLine, jsoTblProp, prevLineText, nextLine, nextLineText, jsoStrTblProp;
+    rep = this.context.rep;
+    defTblProp = {
+      borderWidth: '1',
+      cellAttrs: [],
+      width: '6',
+      rowAttrs: {},
+      colAttrs: [],
+      authors: {}
     };
-    dt.insertTblRowBelow = function(numOfRows, table){
-      var rep, currLineText, payload, tblPayload, tblRows, i, tableObj;
-      rep = this.rep;
-      currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-      payload = [[]];
-      if (!numOfRows && numOfRows !== 0) {
-        tblPayload = fromEscapedJSON(currLineText).payload;
-        numOfRows = tblPayload[0].length;
+    if (authors) {
+      defTblProp['authors'] = authors;
+    }
+    prevLine = rep.lines.atIndex(rep.selEnd[0] - 1);
+    jsoTblProp = null;
+    if (prevLine) {
+      prevLineText = prevLine.text;
+      if (!(prevLineText.indexOf('\uFFF9') === -1)) {
+        jsoTblProp = this.getLineTableProperty(rep.selStart[0] - 1);
       }
-      tblRows = new Array(numOfRows);
-      if (!(numOfRows === 0)) {
-        i = 0;
-        while (i < tblRows.length) {
-          tblRows[i] = ' ';
-          i++;
+    }
+    if (!jsoTblProp) {
+      nextLine = rep.lines.atIndex(rep.selEnd[0] - 1);
+      if (nextLine) {
+        nextLineText = nextLine.text;
+        if (!(nextLineText.indexOf('\uFFF9') === -1)) {
+          jsoTblProp = this.getLineTableProperty(rep.selStart[0] + 1);
         }
       }
-      payload = [tblRows];
-      if (table) {
-        payload = table.payload;
-      }
-      tableObj = {
-        payload: payload,
-        tblId: 1,
-        tblClass: '\uFFF9',
-        trClass: 'alst',
-        tdClass: 'hide-el'
-      };
-      rep.selEnd[1] = rep.selStart[1] = currLineText.length;
-      this.context.editorInfo.ace_doReturnKey();
-      return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, escapedJSON(tableObj));
-    };
-    dt.createDefaultTblProperties = function(authors){
-      var rep, defTblProp, prevLine, jsoTblProp, prevLineText, nextLine, nextLineText, jsoStrTblProp;
-      rep = this.context.rep;
-      defTblProp = {
-        borderWidth: '1',
-        cellAttrs: [],
-        width: '6',
-        rowAttrs: {},
-        colAttrs: [],
-        authors: {}
-      };
-      if (authors) {
-        defTblProp['authors'] = authors;
-      }
-      prevLine = rep.lines.atIndex(rep.selEnd[0] - 1);
-      jsoTblProp = null;
-      if (prevLine) {
-        prevLineText = prevLine.text;
-        if (!(prevLineText.indexOf('\uFFF9') === -1)) {
-          jsoTblProp = this.getLineTableProperty(rep.selStart[0] - 1);
+    }
+    if (jsoTblProp) {
+      defTblProp.borderWidth = jsoTblProp.borderWidth;
+      defTblProp.borderColor = jsoTblProp.borderColor;
+      defTblProp.width = jsoTblProp.width;
+      defTblProp.height = jsoTblProp.height;
+      defTblProp.colAttrs = jsoTblProp.colAttrs;
+    }
+    jsoStrTblProp = JSON.stringify(defTblProp);
+    return jsoStrTblProp;
+  };
+  Datatables.performDocApplyTblAttrToRow = function(start, jsoStrTblProp){
+    var tempStart, tempEnd;
+    tempStart = [];
+    tempEnd = [];
+    tempStart[0] = start[0];
+    tempEnd[0] = start[0];
+    tempStart[1] = 0;
+    tempEnd[1] = this.context.rep.lines.atIndex(start[0]).text.length;
+    return this.context.editorInfo.ace_performDocumentApplyAttributesToRange(tempStart, tempEnd, [['tblProp', jsoStrTblProp]]);
+  };
+  Datatables.performDocumentTableTabKey = function(){
+    var context, rep, currLine, currLineText, tblJSONObj, payload, currTdInfo, leftOverTdTxtLen, currRow, currTd, nextLine, nextLineText, updateEvenOddBgColor, start, nextTdTxtLen, e;
+    try {
+      context = this.context;
+      rep = context.rep;
+      currLine = rep.lines.atIndex(rep.selStart[0]);
+      currLineText = currLine.text;
+      tblJSONObj = fromEscapedJSON(currLineText);
+      payload = tblJSONObj.payload;
+      currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+      leftOverTdTxtLen = currTdInfo.leftOverTdTxtLen;
+      currRow = currTdInfo.row;
+      currTd = currTdInfo.td;
+      if (typeof payload[currRow][currTd + 1] === 'undefined') {
+        currRow += 1;
+        nextLine = rep.lines.atIndex(rep.selStart[0] + 1);
+        nextLineText = nextLine.text;
+        updateEvenOddBgColor = false;
+        if (nextLineText == null || nextLineText === '' || nextLineText.indexOf('\uFFF9') === -1) {
+          this.insertTblRowBelow(null, null);
+          this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
+          rep.selEnd[1] = rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE;
+          updateEvenOddBgColor = true;
+        } else {
+          currTd = -1;
+          rep.selStart[0] = rep.selEnd[0] = rep.selStart[0] + 1;
+          tblJSONObj = fromEscapedJSON(nextLineText);
+          payload = tblJSONObj.payload;
+          leftOverTdTxtLen = payload[0][0].length;
+          rep.selEnd[1] = rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE + leftOverTdTxtLen;
         }
+        context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+        start = [];
+        start[0] = rep.selStart[0];
+        start[1] = rep.selStart[1];
+        return this.updateTblCellAuthor(0, 0, null, start, updateEvenOddBgColor);
+      } else {
+        nextTdTxtLen = typeof payload[currRow] === 'undefined'
+          ? -leftOverTdTxtLen
+          : payload[currRow][currTd + 1].length;
+        payload = tblJSONObj.payload;
+        rep.selStart[1] = rep.selEnd[1] = rep.selEnd[1] + nextTdTxtLen + leftOverTdTxtLen;
+        context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+        return this.updateTblPropInAPool(currRow, currTd + 1, null, rep.selStart);
       }
-      if (!jsoTblProp) {
-        nextLine = rep.lines.atIndex(rep.selEnd[0] - 1);
-        if (nextLine) {
-          nextLineText = nextLine.text;
-          if (!(nextLineText.indexOf('\uFFF9') === -1)) {
-            jsoTblProp = this.getLineTableProperty(rep.selStart[0] + 1);
-          }
-        }
+    } catch (e$) {
+      return e = e$;
+    }
+  };
+  Datatables.getTdInfo = function(payload, tdIndex){
+    var rep, startOffset, rowStartOffset, payloadSum, tds, tIndex, tLen, overHeadLen;
+    rep = this.context.rep;
+    startOffset = this.vars.OVERHEAD_LEN_PRE;
+    rowStartOffset = startOffset;
+    payloadSum = startOffset;
+    tds = payload[0];
+    tIndex = 0;
+    tLen = tds.length;
+    while (tIndex < tLen) {
+      overHeadLen = this.vars.OVERHEAD_LEN_MID;
+      if (tIndex === tLen - 1) {
+        overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
       }
-      if (jsoTblProp) {
-        defTblProp.borderWidth = jsoTblProp.borderWidth;
-        defTblProp.borderColor = jsoTblProp.borderColor;
-        defTblProp.width = jsoTblProp.width;
-        defTblProp.height = jsoTblProp.height;
-        defTblProp.colAttrs = jsoTblProp.colAttrs;
+      payloadSum += tds[tIndex].length + overHeadLen;
+      if (tIndex >= tdIndex) {
+        return {
+          cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
+          cellEndOffset: payloadSum
+        };
       }
-      jsoStrTblProp = JSON.stringify(defTblProp);
-      return jsoStrTblProp;
-    };
-    dt.performDocApplyTblAttrToRow = function(start, jsoStrTblProp){
-      var tempStart, tempEnd;
-      tempStart = [];
-      tempEnd = [];
-      tempStart[0] = start[0];
-      tempEnd[0] = start[0];
-      tempStart[1] = 0;
-      tempEnd[1] = this.context.rep.lines.atIndex(start[0]).text.length;
-      return this.context.editorInfo.ace_performDocumentApplyAttributesToRange(tempStart, tempEnd, [['tblProp', jsoStrTblProp]]);
-    };
-    dt.performDocumentTableTabKey = function(){
-      var context, rep, currLine, currLineText, tblJSONObj, payload, currTdInfo, leftOverTdTxtLen, currRow, currTd, nextLine, nextLineText, updateEvenOddBgColor, start, nextTdTxtLen, e;
-      try {
-        context = this.context;
-        rep = context.rep;
-        currLine = rep.lines.atIndex(rep.selStart[0]);
-        currLineText = currLine.text;
-        tblJSONObj = fromEscapedJSON(currLineText);
-        payload = tblJSONObj.payload;
-        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-        leftOverTdTxtLen = currTdInfo.leftOverTdTxtLen;
-        currRow = currTdInfo.row;
-        currTd = currTdInfo.td;
-        if (typeof payload[currRow][currTd + 1] === 'undefined') {
-          currRow += 1;
-          nextLine = rep.lines.atIndex(rep.selStart[0] + 1);
-          nextLineText = nextLine.text;
-          updateEvenOddBgColor = false;
-          if (nextLineText == null || nextLineText === '' || nextLineText.indexOf('\uFFF9') === -1) {
-            this.insertTblRowBelow(null, null);
-            this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
-            rep.selEnd[1] = rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE;
-            updateEvenOddBgColor = true;
-          } else {
-            currTd = -1;
-            rep.selStart[0] = rep.selEnd[0] = rep.selStart[0] + 1;
-            tblJSONObj = fromEscapedJSON(nextLineText);
-            payload = tblJSONObj.payload;
-            leftOverTdTxtLen = payload[0][0].length;
-            rep.selEnd[1] = rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE + leftOverTdTxtLen;
-          }
-          context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
-          start = [];
-          start[0] = rep.selStart[0];
-          start[1] = rep.selStart[1];
-          return dt.updateTblCellAuthor(0, 0, null, start, updateEvenOddBgColor);
-        } else {
-          nextTdTxtLen = typeof payload[currRow] === 'undefined'
-            ? -leftOverTdTxtLen
-            : payload[currRow][currTd + 1].length;
-          payload = tblJSONObj.payload;
-          rep.selStart[1] = rep.selEnd[1] = rep.selEnd[1] + nextTdTxtLen + leftOverTdTxtLen;
-          context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
-          return dt.updateTblPropInAPool(currRow, currTd + 1, null, rep.selStart);
-        }
-      } catch (e$) {
-        return e = e$;
+      tIndex++;
+    }
+  };
+  Datatables.getNextTdInfo = function(payload, currTdInfo){
+    var rep, startOffset, rowStartOffset, payloadSum, tds, tIndex, tLen, overHeadLen, leftOverTdTxtLen, rowEndOffset, tdInfo;
+    rep = this.context.rep;
+    startOffset = currTdInfo.rowEndOffset;
+    rowStartOffset = startOffset;
+    payloadSum = startOffset;
+    tds = payload[currTdInfo.row];
+    tIndex = 0;
+    tLen = tds.length;
+    while (tIndex < tLen) {
+      overHeadLen = this.vars.OVERHEAD_LEN_MID;
+      if (tIndex === tLen - 1) {
+        overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
       }
-    };
-    dt.getTdInfo = function(payload, tdIndex){
-      var rep, startOffset, rowStartOffset, payloadSum, tds, tIndex, tLen, overHeadLen;
-      rep = this.context.rep;
-      startOffset = this.vars.OVERHEAD_LEN_PRE;
-      rowStartOffset = startOffset;
-      payloadSum = startOffset;
-      tds = payload[0];
-      tIndex = 0;
-      tLen = tds.length;
-      while (tIndex < tLen) {
-        overHeadLen = this.vars.OVERHEAD_LEN_MID;
-        if (tIndex === tLen - 1) {
-          overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
-        }
-        payloadSum += tds[tIndex].length + overHeadLen;
-        if (tIndex >= tdIndex) {
-          return {
-            cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
-            cellEndOffset: payloadSum
-          };
-        }
-        tIndex++;
+      payloadSum += tds[tIndex].length + overHeadLen;
+      if (tIndex >= currTdInfo.td) {
+        leftOverTdTxtLen = payloadSum - startOffset === 0
+          ? payload[currTdInfo.row + 1][tIndex].length + this.vars.OVERHEAD_LEN_MID
+          : payloadSum - startOffset;
+        rowEndOffset = this._getRowEndOffset(rowStartOffset, tds);
+        tdInfo = {
+          row: currTdInfo.row + 1,
+          td: tIndex,
+          leftOverTdTxtLen: leftOverTdTxtLen,
+          rowStartOffset: rowStartOffset,
+          rowEndOffset: rowEndOffset,
+          cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
+          cellEndOffset: payloadSum
+        };
+        return tdInfo;
       }
-    };
-    dt.getNextTdInfo = function(payload, currTdInfo){
-      var rep, startOffset, rowStartOffset, payloadSum, tds, tIndex, tLen, overHeadLen, leftOverTdTxtLen, rowEndOffset, tdInfo;
-      rep = this.context.rep;
-      startOffset = currTdInfo.rowEndOffset;
-      rowStartOffset = startOffset;
-      payloadSum = startOffset;
-      tds = payload[currTdInfo.row];
-      tIndex = 0;
-      tLen = tds.length;
-      while (tIndex < tLen) {
-        overHeadLen = this.vars.OVERHEAD_LEN_MID;
-        if (tIndex === tLen - 1) {
-          overHeadLen = this.vars.OVERHEAD_LEN_ROW_END;
-        }
-        payloadSum += tds[tIndex].length + overHeadLen;
-        if (tIndex >= currTdInfo.td) {
-          leftOverTdTxtLen = payloadSum - startOffset === 0
-            ? payload[currTdInfo.row + 1][tIndex].length + this.vars.OVERHEAD_LEN_MID
-            : payloadSum - startOffset;
-          rowEndOffset = this._getRowEndOffset(rowStartOffset, tds);
-          tdInfo = {
-            row: currTdInfo.row + 1,
-            td: tIndex,
-            leftOverTdTxtLen: leftOverTdTxtLen,
-            rowStartOffset: rowStartOffset,
-            rowEndOffset: rowEndOffset,
-            cellStartOffset: payloadSum - tds[tIndex].length - overHeadLen,
-            cellEndOffset: payloadSum
-          };
-          return tdInfo;
-        }
-        tIndex++;
+      tIndex++;
+    }
+  };
+  Datatables.insertTblColumn = function(leftOrRight, start, end){
+    var rep, func, currLineText, tblJSONObj, payload, currTdInfo, currTd, numOfLinesAbove, cellPos, newText, updateEvenOddBgColor, updateColAttrs, e;
+    rep = this.context.rep;
+    func = 'insertTblColumn()';
+    try {
+      currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+      tblJSONObj = fromEscapedJSON(currLineText);
+      payload = tblJSONObj.payload;
+      currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+      currTd = currTdInfo.td;
+      start = [];
+      end = [];
+      start[0] = rep.selStart[0];
+      start[1] = rep.selStart[1];
+      end[0] = rep.selEnd[0];
+      end[1] = rep.selEnd[1];
+      if (leftOrRight === 'addL') {
+        currTd -= 1;
       }
-    };
-    dt.insertTblColumn = function(leftOrRight, start, end){
-      var rep, func, currLineText, tblJSONObj, payload, currTdInfo, currTd, numOfLinesAbove, cellPos, newText, updateEvenOddBgColor, updateColAttrs, e;
-      rep = this.context.rep;
-      func = 'insertTblColumn()';
-      try {
+      numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
+      rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
+      while (rep.selStart[0] < rep.lines.length() && rep.lines.atIndex(rep.selStart[0]).text.indexOf('\uFFF9') !== -1) {
         currLineText = rep.lines.atIndex(rep.selStart[0]).text;
         tblJSONObj = fromEscapedJSON(currLineText);
         payload = tblJSONObj.payload;
-        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-        currTd = currTdInfo.td;
-        start = [];
-        end = [];
-        start[0] = rep.selStart[0];
-        start[1] = rep.selStart[1];
-        end[0] = rep.selEnd[0];
-        end[1] = rep.selEnd[1];
-        if (leftOrRight === 'addL') {
-          currTd -= 1;
-        }
-        numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
-        rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
-        while (rep.selStart[0] < rep.lines.length() && rep.lines.atIndex(rep.selStart[0]).text.indexOf('\uFFF9') !== -1) {
-          currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-          tblJSONObj = fromEscapedJSON(currLineText);
-          payload = tblJSONObj.payload;
-          cellPos = this.getTdInfo(payload, currTd).cellEndOffset;
-          newText = '" ",';
-          if (currTd === payload[0].length - 1) {
-            rep.selStart[1] = rep.selEnd[1] = cellPos - this.vars.OVERHEAD_LEN_ROW_END + 1;
-            newText = '," "';
+        cellPos = this.getTdInfo(payload, currTd).cellEndOffset;
+        newText = '" ",';
+        if (currTd === payload[0].length - 1) {
+          rep.selStart[1] = rep.selEnd[1] = cellPos - this.vars.OVERHEAD_LEN_ROW_END + 1;
+          newText = '," "';
+        } else {
+          if (currTd === -1) {
+            rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE - 1;
           } else {
-            if (currTd === -1) {
-              rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE - 1;
-            } else {
-              rep.selStart[1] = rep.selEnd[1] = cellPos - 1;
-            }
+            rep.selStart[1] = rep.selEnd[1] = cellPos - 1;
           }
-          this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, newText);
-          rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] + 1;
-        }
-        rep.selStart = start;
-        rep.selEnd = end;
-        if (leftOrRight === 'addL') {
-          rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
-          rep.selStart[0] = rep.selEnd[0] = rep.selStart[0];
-          this.updateTblPropInAPool(0, 0, null, rep.selStart);
-          rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
         }
-        currTd++;
-        updateEvenOddBgColor = false;
-        updateColAttrs = true;
-        this.sanitizeTblProperties(start, updateEvenOddBgColor, updateColAttrs, currTd, 'add');
-        return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
-      } catch (e$) {
-        return e = e$;
+        this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, newText);
+        rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] + 1;
       }
-    };
-    dt.deleteTblColumn = function(){
-      var func, rep, currLineText, tblJSONObj, payload, currTdInfo, currTd, start, end, numOfLinesAbove, cellTdInfo, newText, updateEvenOddBgColor, updateColAttrs, e;
-      func = 'deleteTblColumn()';
-      rep = this.context.rep;
-      try {
+      rep.selStart = start;
+      rep.selEnd = end;
+      if (leftOrRight === 'addL') {
+        rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
+        rep.selStart[0] = rep.selEnd[0] = rep.selStart[0];
+        this.updateTblPropInAPool(0, 0, null, rep.selStart);
+        rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
+      }
+      currTd++;
+      updateEvenOddBgColor = false;
+      updateColAttrs = true;
+      this.sanitizeTblProperties(start, updateEvenOddBgColor, updateColAttrs, currTd, 'add');
+      return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+    } catch (e$) {
+      return e = e$;
+    }
+  };
+  Datatables.deleteTblColumn = function(){
+    var func, rep, currLineText, tblJSONObj, payload, currTdInfo, currTd, start, end, numOfLinesAbove, cellTdInfo, newText, updateEvenOddBgColor, updateColAttrs, e;
+    func = 'deleteTblColumn()';
+    rep = this.context.rep;
+    try {
+      currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+      tblJSONObj = fromEscapedJSON(currLineText);
+      payload = tblJSONObj.payload;
+      if (payload[0].length === 1) {
+        deleteTable();
+      }
+      currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
+      currTd = currTdInfo.td;
+      start = [];
+      end = [];
+      start[0] = rep.selStart[0];
+      start[1] = rep.selStart[1];
+      end[0] = rep.selEnd[0];
+      end[1] = rep.selEnd[1];
+      numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
+      rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
+      while (rep.selStart[0] < rep.lines.length() && rep.lines.atIndex(rep.selStart[0]).text.indexOf('\uFFF9') !== -1) {
         currLineText = rep.lines.atIndex(rep.selStart[0]).text;
         tblJSONObj = fromEscapedJSON(currLineText);
         payload = tblJSONObj.payload;
-        if (payload[0].length === 1) {
-          deleteTable();
-        }
-        currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
-        currTd = currTdInfo.td;
-        start = [];
-        end = [];
-        start[0] = rep.selStart[0];
-        start[1] = rep.selStart[1];
-        end[0] = rep.selEnd[0];
-        end[1] = rep.selEnd[1];
-        numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
-        rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] - numOfLinesAbove;
-        while (rep.selStart[0] < rep.lines.length() && rep.lines.atIndex(rep.selStart[0]).text.indexOf('\uFFF9') !== -1) {
-          currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-          tblJSONObj = fromEscapedJSON(currLineText);
-          payload = tblJSONObj.payload;
-          cellTdInfo = this.getTdInfo(payload, currTd);
-          newText = '" ",';
-          if (currTd === payload[0].length - 1) {
-            rep.selStart[1] = cellTdInfo.cellStartOffset - 2;
-            rep.selEnd[1] = cellTdInfo.cellEndOffset - 2;
+        cellTdInfo = this.getTdInfo(payload, currTd);
+        newText = '" ",';
+        if (currTd === payload[0].length - 1) {
+          rep.selStart[1] = cellTdInfo.cellStartOffset - 2;
+          rep.selEnd[1] = cellTdInfo.cellEndOffset - 2;
+        } else {
+          if (currTd === 0) {
+            rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE - 1;
+            rep.selEnd[1] = cellTdInfo.cellEndOffset - 1;
           } else {
-            if (currTd === 0) {
-              rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE - 1;
-              rep.selEnd[1] = cellTdInfo.cellEndOffset - 1;
-            } else {
-              rep.selStart[1] = cellTdInfo.cellStartOffset - 1;
-              rep.selEnd[1] = cellTdInfo.cellEndOffset - 1;
-            }
+            rep.selStart[1] = cellTdInfo.cellStartOffset - 1;
+            rep.selEnd[1] = cellTdInfo.cellEndOffset - 1;
           }
-          this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
-          rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] + 1;
-        }
-        rep.selStart = start;
-        rep.selEnd = end;
-        updateEvenOddBgColor = false;
-        updateColAttrs = true;
-        this.sanitizeTblProperties(start, updateEvenOddBgColor, updateColAttrs, currTd, 'del');
-        return this.updateAuthorAndCaretPos(rep.selStart[0], 0, 0);
-      } catch (e$) {
-        return e = e$;
-      }
-    };
-    dt.insertTblRowBelow = function(numOfRows, table){
-      var context, rep, currLineText, payload, tblPayload, tblRows, i, tableObj;
-      context = this.context;
-      rep = context.rep;
-      currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-      payload = [[]];
-      if (!numOfRows && numOfRows !== 0) {
-        tblPayload = fromEscapedJSON(currLineText).payload;
-        numOfRows = tblPayload[0].length;
-      }
-      tblRows = new Array(numOfRows);
-      if (!(numOfRows === 0)) {
-        i = 0;
-        while (i < tblRows.length) {
-          tblRows[i] = ' ';
-          i++;
         }
+        this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+        rep.selEnd[0] = rep.selStart[0] = rep.selStart[0] + 1;
       }
-      payload = [tblRows];
-      if (table) {
-        payload = table.payload;
+      rep.selStart = start;
+      rep.selEnd = end;
+      updateEvenOddBgColor = false;
+      updateColAttrs = true;
+      this.sanitizeTblProperties(start, updateEvenOddBgColor, updateColAttrs, currTd, 'del');
+      return this.updateAuthorAndCaretPos(rep.selStart[0], 0, 0);
+    } catch (e$) {
+      return e = e$;
+    }
+  };
+  Datatables.insertTblRowBelow = function(numOfRows, table){
+    var context, rep, currLineText, payload, tblPayload, tblRows, i, tableObj;
+    context = this.context;
+    rep = context.rep;
+    currLineText = rep.lines.atIndex(rep.selStart[0]).text;
+    payload = [[]];
+    if (!numOfRows && numOfRows !== 0) {
+      tblPayload = fromEscapedJSON(currLineText).payload;
+      numOfRows = tblPayload[0].length;
+    }
+    tblRows = new Array(numOfRows);
+    if (!(numOfRows === 0)) {
+      i = 0;
+      while (i < tblRows.length) {
+        tblRows[i] = ' ';
+        i++;
       }
-      tableObj = {
-        payload: payload,
-        tblId: 1,
-        tblClass: '\uFFF9',
-        trClass: 'alst',
-        tdClass: 'hide-el'
-      };
-      rep.selEnd[1] = rep.selStart[1] = currLineText.length;
-      this.context.editorInfo.ace_inCallStackIfNecessary('newline', this.context.editorInfo.ace_doReturnKey);
-      return context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, escapedJSON(tableObj));
+    }
+    payload = [tblRows];
+    if (table) {
+      payload = table.payload;
+    }
+    tableObj = {
+      payload: payload,
+      tblId: 1,
+      tblClass: '\uFFF9',
+      trClass: 'alst',
+      tdClass: 'hide-el'
     };
-    dt.doReturnKey = function(){
-      var context, rep, start, end, lastTblPropertyUsed, currLine, currLineText, func, currCarretPos, newText, jsonObj, payloadStr, error, e;
-      context = this.context;
-      rep = context.rep;
-      start = rep.seStart;
-      end = rep.selEnd;
-      lastTblPropertyUsed = 'doTableReturnKey';
-      currLine = rep.lines.atIndex(rep.selStart[0]);
-      currLineText = currLine.text;
-      if (!(currLineText.indexOf('\uFFF9') === -1)) {
-        func = 'doTableReturnKey()';
-        try {
-          currCarretPos = rep.selStart[1];
-          if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '","') {
+    rep.selEnd[1] = rep.selStart[1] = currLineText.length;
+    this.context.editorInfo.ace_inCallStackIfNecessary('newline', this.context.editorInfo.ace_doReturnKey);
+    return context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, escapedJSON(tableObj));
+  };
+  Datatables.doReturnKey = function(){
+    var context, rep, start, end, lastTblPropertyUsed, currLine, currLineText, func, currCarretPos, newText, jsonObj, payloadStr, error, e;
+    context = this.context;
+    rep = context.rep;
+    start = rep.seStart;
+    end = rep.selEnd;
+    lastTblPropertyUsed = 'doTableReturnKey';
+    currLine = rep.lines.atIndex(rep.selStart[0]);
+    currLineText = currLine.text;
+    if (!(currLineText.indexOf('\uFFF9') === -1)) {
+      func = 'doTableReturnKey()';
+      try {
+        currCarretPos = rep.selStart[1];
+        if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '","') {
+          return true;
+        } else {
+          if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) === '","') {
             return true;
           } else {
-            if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) === '","') {
+            if (currCarretPos < this.vars.OVERHEAD_LEN_PRE) {
               return true;
-            } else {
-              if (currCarretPos < this.vars.OVERHEAD_LEN_PRE) {
-                return true;
-              } else if (currCarretPos > currLineText.length) {
-                return true;
-              }
-            }
-          }
-          start = rep.selStart;
-          end = rep.selEnd;
-          newText = ' /r/n ';
-          start[1] = currCarretPos;
-          end[1] = currCarretPos;
-          try {
-            jsonObj = fromEscapedJSON(currLineText.substring(0, start[1]) + newText + currLineText.substring(start[1]));
-            payloadStr = escapedJSON(jsonObj.payload);
-            if (currCarretPos > payloadStr.length + this.vars.OVERHEAD_LEN_PRE - 2) {
+            } else if (currCarretPos > currLineText.length) {
               return true;
             }
-          } catch (e$) {
-            error = e$;
+          }
+        }
+        start = rep.selStart;
+        end = rep.selEnd;
+        newText = ' /r/n ';
+        start[1] = currCarretPos;
+        end[1] = currCarretPos;
+        try {
+          jsonObj = fromEscapedJSON(currLineText.substring(0, start[1]) + newText + currLineText.substring(start[1]));
+          payloadStr = escapedJSON(jsonObj.payload);
+          if (currCarretPos > payloadStr.length + this.vars.OVERHEAD_LEN_PRE - 2) {
             return true;
           }
-          context.editorInfo.ace_performDocumentReplaceRange(start, end, newText);
         } catch (e$) {
-          e = e$;
+          error = e$;
+          return true;
         }
-        return true;
-      }
-    };
-    dt.isCellDeleteOk = function(keyCode){
-      var context, rep, start, end, currLine, currLineText, isDeleteAccepted, tblJSONObj, table, currTdInfo, cellEntryLen, currCarretPos, error;
-      context = this.context;
-      rep = context.rep;
-      start = rep.selStart;
-      end = rep.selEnd;
-      currLine = rep.lines.atIndex(rep.selStart[0]);
-      currLineText = currLine.text;
-      if (currLineText.indexOf('\uFFF9') === -1) {
-        return true;
+        context.editorInfo.ace_performDocumentReplaceRange(start, end, newText);
+      } catch (e$) {
+        e = e$;
       }
-      isDeleteAccepted = false;
-      try {
-        tblJSONObj = fromEscapedJSON(currLineText);
-        table = tblJSONObj.payload;
-        currTdInfo = this.getFocusedTdInfo(table, rep.selStart[1]);
-        cellEntryLen = table[currTdInfo.row][currTdInfo.td].length;
-        currCarretPos = rep.selStart[1];
-        if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '","') {
-          return false;
-        } else {
-          if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) === '","') {
-            return false;
-          }
-        }
-        switch (keyCode) {
-        case this.vars.JS_KEY_CODE_BS:
-          if (cellEntryLen !== 0 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
-            isDeleteAccepted = true;
-          }
-          break;
-        case this.vars.JS_KEY_CODE_DEL:
+      return true;
+    }
+  };
+  Datatables.isCellDeleteOk = function(keyCode){
+    var context, rep, start, end, currLine, currLineText, isDeleteAccepted, tblJSONObj, table, currTdInfo, cellEntryLen, currCarretPos, error;
+    context = this.context;
+    rep = context.rep;
+    start = rep.selStart;
+    end = rep.selEnd;
+    currLine = rep.lines.atIndex(rep.selStart[0]);
+    currLineText = currLine.text;
+    if (currLineText.indexOf('\uFFF9') === -1) {
+      return true;
+    }
+    isDeleteAccepted = false;
+    try {
+      tblJSONObj = fromEscapedJSON(currLineText);
+      table = tblJSONObj.payload;
+      currTdInfo = this.getFocusedTdInfo(table, rep.selStart[1]);
+      cellEntryLen = table[currTdInfo.row][currTdInfo.td].length;
+      currCarretPos = rep.selStart[1];
+      if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '","') {
+        return false;
+      } else {
+        if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) === '","') {
           return false;
-          if (cellEntryLen !== 0 && currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID > 0) {
-            isDeleteAccepted = true;
-          }
-          break;
-        default:
-          if (cellEntryLen !== 0 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
-            isDeleteAccepted = true;
-          }
         }
-      } catch (e$) {
-        error = e$;
-        isDeleteAccepted = false;
       }
-      return isDeleteAccepted;
-    };
-    dt.nodeTextPlain = function(n){
-      return n.innerText || n.textContent || n.nodeValue || '';
-    };
-    dt.toString = function(){
-      return 'ep_tables';
-    };
-    dt.getLineAndCharForPoint = function(){
-      var context, point, root, N, ln, n, col, parNode, prevSib, textLen, lineEntry, lineNum;
-      context = this.context;
-      point = context.point;
-      root = context.root;
-      if (point.node === root) {
-        if (point.index === 0) {
-          return [0, 0];
-        } else {
-          N = this.context.rep.lines.length();
-          ln = this.context.rep.lines.atIndex(N - 1);
-          return [N - 1, ln.text.length];
+      switch (keyCode) {
+      case this.vars.JS_KEY_CODE_BS:
+        if (cellEntryLen !== 0 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
+          isDeleteAccepted = true;
         }
-      } else {
-        n = point.node;
-        col = 0;
-        if (nodeText(n) || point.index > 0) {
-          col = point.index;
+        break;
+      case this.vars.JS_KEY_CODE_DEL:
+        return false;
+        if (cellEntryLen !== 0 && currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID > 0) {
+          isDeleteAccepted = true;
         }
-        parNode = void 8;
-        prevSib = void 8;
-        while (!((parNode = n.parentNode) === root)) {
-          if (prevSib = n.previousSibling) {
-            n = prevSib;
-            textLen = nodeText(n).length === 0
-              ? this.nodeTextPlain(n).length
-              : nodeText(n).length;
-            col += textLen;
-          } else {
-            n = parNode;
-          }
+        break;
+      default:
+        if (cellEntryLen !== 0 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
+          isDeleteAccepted = true;
         }
-        if (n.id === '') {
-          console.debug('BAD');
+      }
+    } catch (e$) {
+      error = e$;
+      isDeleteAccepted = false;
+    }
+    return isDeleteAccepted;
+  };
+  Datatables.nodeTextPlain = function(n){
+    return n.innerText || n.textContent || n.nodeValue || '';
+  };
+  Datatables.toString = function(){
+    return 'ep_tables';
+  };
+  Datatables.getLineAndCharForPoint = function(){
+    var context, point, root, N, ln, n, col, parNode, prevSib, textLen, lineEntry, lineNum;
+    context = this.context;
+    point = context.point;
+    root = context.root;
+    if (point.node === root) {
+      if (point.index === 0) {
+        return [0, 0];
+      } else {
+        N = this.context.rep.lines.length();
+        ln = this.context.rep.lines.atIndex(N - 1);
+        return [N - 1, ln.text.length];
+      }
+    } else {
+      n = point.node;
+      col = 0;
+      if (nodeText(n) || point.index > 0) {
+        col = point.index;
+      }
+      parNode = void 8;
+      prevSib = void 8;
+      while (!((parNode = n.parentNode) === root)) {
+        if (prevSib = n.previousSibling) {
+          n = prevSib;
+          textLen = nodeText(n).length === 0
+            ? this.nodeTextPlain(n).length
+            : nodeText(n).length;
+          col += textLen;
+        } else {
+          n = parNode;
         }
-        if (n.firstChild && context.editorInfo.ace_isBlockElement(n.firstChild)) {
-          col += 1;
+      }
+      if (n.id === '') {
+        console.debug('BAD');
+      }
+      if (n.firstChild && context.editorInfo.ace_isBlockElement(n.firstChild)) {
+        col += 1;
+      }
+      lineEntry = this.context.rep.lines.atKey(n.id);
+      lineNum = this.context.rep.lines.indexOfEntry(lineEntry);
+      return [lineNum, col];
+    }
+  };
+  Datatables.doDeleteKey = function(){
+    var context, evt, handled, rep, editorInfo, lineNum, col, lineEntry, lineText, lineMarker, col2, tabSize, toDelete, theLine, action, prevLineListType, thisLineListType, prevLineEntry, prevLineBlank, docChar, deleteBackTo, returnKeyWitinTblOffset, line;
+    context = this.context;
+    evt = context.evt || {};
+    handled = false;
+    rep = this.context.rep;
+    editorInfo = context.editorInfo;
+    if (rep.selStart) {
+      if (editorInfo.ace_isCaret()) {
+        lineNum = editorInfo.ace_caretLine();
+        col = editorInfo.ace_caretColumn();
+        lineEntry = rep.lines.atIndex(lineNum);
+        lineText = lineEntry.text;
+        lineMarker = lineEntry.lineMarker;
+        if (/^ +$/.exec(lineText.substring(lineMarker, col))) {
+          col2 = col - lineMarker;
+          tabSize = ''.length;
+          toDelete = (col2 - 1) % tabSize + 1;
+          editorInfo.ace_performDocumentReplaceRange([lineNum, col - toDelete], [lineNum, col], '');
+          handled = true;
         }
-        lineEntry = this.context.rep.lines.atKey(n.id);
-        lineNum = this.context.rep.lines.indexOfEntry(lineEntry);
-        return [lineNum, col];
       }
-    };
-    dt.doDeleteKey = function(){
-      var context, evt, handled, rep, editorInfo, lineNum, col, lineEntry, lineText, lineMarker, col2, tabSize, toDelete, theLine, action, prevLineListType, thisLineListType, prevLineEntry, prevLineBlank, docChar, deleteBackTo, returnKeyWitinTblOffset, line;
-      context = this.context;
-      evt = context.evt || {};
-      handled = false;
-      rep = this.context.rep;
-      editorInfo = context.editorInfo;
-      if (rep.selStart) {
+      if (!handled) {
         if (editorInfo.ace_isCaret()) {
-          lineNum = editorInfo.ace_caretLine();
-          col = editorInfo.ace_caretColumn();
-          lineEntry = rep.lines.atIndex(lineNum);
-          lineText = lineEntry.text;
-          lineMarker = lineEntry.lineMarker;
-          if (/^ +$/.exec(lineText.substring(lineMarker, col))) {
-            col2 = col - lineMarker;
-            tabSize = ''.length;
-            toDelete = (col2 - 1) % tabSize + 1;
-            editorInfo.ace_performDocumentReplaceRange([lineNum, col - toDelete], [lineNum, col], '');
-            handled = true;
-          }
-        }
-        if (!handled) {
-          if (editorInfo.ace_isCaret()) {
-            theLine = editorInfo.ace_caretLine();
-            lineEntry = rep.lines.atIndex(theLine);
-            if (editorInfo.ace_caretColumn() <= lineEntry.lineMarker) {
-              action = 'delete_newline';
-              prevLineListType = theLine > 0 ? editorInfo.ace_getLineListType(theLine - 1) : '';
-              thisLineListType = editorInfo.ace_getLineListType(theLine);
-              prevLineEntry = theLine > 0 && rep.lines.atIndex(theLine - 1);
-              prevLineBlank = prevLineEntry && prevLineEntry.text.length === prevLineEntry.lineMarker;
-              if (thisLineListType) {
-                if (prevLineBlank && !prevLineListType) {
-                  editorInfo.ace_performDocumentReplaceRange([theLine - 1, prevLineEntry.text.length], [theLine, 0], '');
-                } else {
-                  editorInfo.ace_performDocumentReplaceRange([theLine, 0], [theLine, lineEntry.lineMarker], '');
-                }
+          theLine = editorInfo.ace_caretLine();
+          lineEntry = rep.lines.atIndex(theLine);
+          if (editorInfo.ace_caretColumn() <= lineEntry.lineMarker) {
+            action = 'delete_newline';
+            prevLineListType = theLine > 0 ? editorInfo.ace_getLineListType(theLine - 1) : '';
+            thisLineListType = editorInfo.ace_getLineListType(theLine);
+            prevLineEntry = theLine > 0 && rep.lines.atIndex(theLine - 1);
+            prevLineBlank = prevLineEntry && prevLineEntry.text.length === prevLineEntry.lineMarker;
+            if (thisLineListType) {
+              if (prevLineBlank && !prevLineListType) {
+                editorInfo.ace_performDocumentReplaceRange([theLine - 1, prevLineEntry.text.length], [theLine, 0], '');
               } else {
-                if (theLine > 0) {
-                  editorInfo.ace_performDocumentReplaceRange([theLine - 1, prevLineEntry.text.length], [theLine, 0], '');
-                }
+                editorInfo.ace_performDocumentReplaceRange([theLine, 0], [theLine, lineEntry.lineMarker], '');
               }
             } else {
-              docChar = editorInfo.ace_caretDocChar();
-              if (docChar > 0) {
-                if (evt.metaKey || evt.ctrlKey || evt.altKey) {
-                  deleteBackTo = docChar - 1;
-                  while (deleteBackTo > lineEntry.lineMarker && editorInfo.ace_isWordChar(rep.alltext.charAt(deleteBackTo - 1))) {
-                    deleteBackTo--;
-                  }
-                  editorInfo.ace_performDocumentReplaceCharRange(deleteBackTo, docChar, '');
-                } else {
-                  returnKeyWitinTblOffset = 0;
-                  if (lineText.substring(col - 5, col) === '/r/n ') {
-                    returnKeyWitinTblOffset = 4;
-                  }
-                  editorInfo.ace_performDocumentReplaceCharRange(docChar - 1 - returnKeyWitinTblOffset, docChar, '');
-                }
+              if (theLine > 0) {
+                editorInfo.ace_performDocumentReplaceRange([theLine - 1, prevLineEntry.text.length], [theLine, 0], '');
               }
             }
           } else {
-            editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
+            docChar = editorInfo.ace_caretDocChar();
+            if (docChar > 0) {
+              if (evt.metaKey || evt.ctrlKey || evt.altKey) {
+                deleteBackTo = docChar - 1;
+                while (deleteBackTo > lineEntry.lineMarker && editorInfo.ace_isWordChar(rep.alltext.charAt(deleteBackTo - 1))) {
+                  deleteBackTo--;
+                }
+                editorInfo.ace_performDocumentReplaceCharRange(deleteBackTo, docChar, '');
+              } else {
+                returnKeyWitinTblOffset = 0;
+                if (lineText.substring(col - 5, col) === '/r/n ') {
+                  returnKeyWitinTblOffset = 4;
+                }
+                editorInfo.ace_performDocumentReplaceCharRange(docChar - 1 - returnKeyWitinTblOffset, docChar, '');
+              }
+            }
           }
+        } else {
+          editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
         }
       }
-      line = editorInfo.ace_caretLine();
-      if (line !== -1 && editorInfo.ace_renumberList(line + 1) === null) {
-        return editorInfo.ace_renumberList(line);
+    }
+    line = editorInfo.ace_caretLine();
+    if (line !== -1 && editorInfo.ace_renumberList(line + 1) === null) {
+      return editorInfo.ace_renumberList(line);
+    }
+  };
+  Datatables.getLineTableProperty = function(lineNum){
+    var rep, aline, opIter, tblJSString, error;
+    rep = this.context.rep;
+    aline = rep.alines[lineNum];
+    if (aline) {
+      opIter = Changeset.opIterator(aline);
+      if (opIter.hasNext()) {
+        tblJSString = Changeset.opAttributeValue(opIter.next(), 'tblProp', rep.apool);
+        try {
+          return JSON.parse(tblJSString);
+        } catch (e$) {
+          error = e$;
+          return this.defaults.tblProps;
+        }
       }
-    };
-    dt.getLineTableProperty = function(lineNum){
-      var rep, aline, opIter, tblJSString, error;
+    }
+    return this.defaults.tblProps;
+  };
+  Datatables.updateTblPropInAPool = function(row, td, jsoTblProp, start){
+    var rep, tblProps, editorInfo, thisAuthor, authorInfos, jsoStrTblProp, attrStart, attrEnd, e;
+    try {
       rep = this.context.rep;
-      aline = rep.alines[lineNum];
-      if (aline) {
-        opIter = Changeset.opIterator(aline);
-        if (opIter.hasNext()) {
-          tblJSString = Changeset.opAttributeValue(opIter.next(), 'tblProp', rep.apool);
-          try {
-            return JSON.parse(tblJSString);
-          } catch (e$) {
-            error = e$;
-            return this.defaults.tblProps;
-          }
-        }
+      tblProps = void 8;
+      editorInfo = this.context.editorInfo;
+      thisAuthor = editorInfo.ace_getAuthor();
+      authorInfos = editorInfo.ace_getAuthorInfos();
+      if (typeof jsoTblProp === 'undefined' || jsoTblProp == null) {
+        jsoTblProp = this.getLineTableProperty(start[0]);
+      }
+      if (row !== -1 && td !== -1) {
+        jsoTblProp['authors'][thisAuthor] = {
+          row: row,
+          cell: td,
+          colorId: authorInfos[thisAuthor].bgcolor
+        };
       }
-      return this.defaults.tblProps;
+      jsoStrTblProp = JSON.stringify(jsoTblProp);
+      attrStart = [];
+      attrEnd = [];
+      attrStart[0] = start[0];
+      attrStart[1] = 0;
+      attrEnd[0] = start[0];
+      attrEnd[1] = rep.lines.atIndex(start[0]).text.length;
+      return editorInfo.ace_performDocumentApplyAttributesToRange(attrStart, attrEnd, [['tblProp', jsoStrTblProp]]);
+    } catch (e$) {
+      return e = e$;
+    }
+  };
+  Datatables.getCurrTblOddEvenRowBgColor = function(startRowNum, currRowNum){
+    var rowBgColors, jsoTblProp1, jsoTblProp2;
+    rowBgColors = {
+      oddBgColor: null,
+      evenBgColor: null
     };
-    dt.updateTblPropInAPool = function(row, td, jsoTblProp, start){
-      var rep, tblProps, editorInfo, thisAuthor, authorInfos, jsoStrTblProp, attrStart, attrEnd, e;
-      try {
-        rep = this.context.rep;
-        tblProps = void 8;
-        editorInfo = this.context.editorInfo;
-        thisAuthor = editorInfo.ace_getAuthor();
-        authorInfos = editorInfo.ace_getAuthorInfos();
-        if (typeof jsoTblProp === 'undefined' || jsoTblProp == null) {
-          jsoTblProp = this.getLineTableProperty(start[0]);
+    if (!(startRowNum === currRowNum)) {
+      jsoTblProp1 = this.getLineTableProperty(startRowNum);
+      jsoTblProp2 = this.getLineTableProperty(startRowNum + 1);
+      rowBgColors.evenBgColor = jsoTblProp1['rowAttrs']['evenBgColor'] || jsoTblProp2['rowAttrs']['evenBgColor'];
+      rowBgColors.oddBgColor = jsoTblProp1['rowAttrs']['oddBgColor'] || jsoTblProp2['rowAttrs']['oddBgColor'];
+    }
+    return rowBgColors;
+  };
+  Datatables.getTblAboveRowsFromCurFocus = function(start){
+    var rep, numOfLinesAbove, line;
+    rep = this.context.rep;
+    numOfLinesAbove = 0;
+    line = start[0] - 1;
+    while (!(rep.lines.atIndex(line).text.indexOf('\uFFF9') === -1)) {
+      numOfLinesAbove++;
+      line--;
+    }
+    return numOfLinesAbove;
+  };
+  Datatables.updateTableIndices = function(tblProperties, currTd, addOrDel){
+    var cellAttrs, rIndex, rLen, cellAttr, colAttrs;
+    cellAttrs = tblProperties.cellAttrs;
+    rIndex = 0;
+    rLen = cellAttrs.length;
+    while (rIndex < rLen) {
+      cellAttr = cellAttrs[rIndex];
+      if (addOrDel === 'add') {
+        if (cellAttr) {
+          cellAttr.splice(currTd, 0, null);
         }
-        if (row !== -1 && td !== -1) {
-          jsoTblProp['authors'][thisAuthor] = {
-            row: row,
-            cell: td,
-            colorId: authorInfos[thisAuthor].bgcolor
-          };
+      } else {
+        if (cellAttr) {
+          cellAttr.splice(currTd, 1);
         }
-        jsoStrTblProp = JSON.stringify(jsoTblProp);
-        attrStart = [];
-        attrEnd = [];
-        attrStart[0] = start[0];
-        attrStart[1] = 0;
-        attrEnd[0] = start[0];
-        attrEnd[1] = rep.lines.atIndex(start[0]).text.length;
-        return editorInfo.ace_performDocumentApplyAttributesToRange(attrStart, attrEnd, [['tblProp', jsoStrTblProp]]);
-      } catch (e$) {
-        return e = e$;
       }
-    };
-    dt.getCurrTblOddEvenRowBgColor = function(startRowNum, currRowNum){
-      var rowBgColors, jsoTblProp1, jsoTblProp2;
-      rowBgColors = {
-        oddBgColor: null,
-        evenBgColor: null
-      };
-      if (!(startRowNum === currRowNum)) {
-        jsoTblProp1 = this.getLineTableProperty(startRowNum);
-        jsoTblProp2 = this.getLineTableProperty(startRowNum + 1);
-        rowBgColors.evenBgColor = jsoTblProp1['rowAttrs']['evenBgColor'] || jsoTblProp2['rowAttrs']['evenBgColor'];
-        rowBgColors.oddBgColor = jsoTblProp1['rowAttrs']['oddBgColor'] || jsoTblProp2['rowAttrs']['oddBgColor'];
+      rIndex++;
+    }
+    colAttrs = tblProperties.colAttrs;
+    if (addOrDel === 'add') {
+      if (colAttrs) {
+        colAttrs.splice(currTd, 0, null);
       }
-      return rowBgColors;
-    };
-    dt.getTblAboveRowsFromCurFocus = function(start){
-      var rep, numOfLinesAbove, line;
-      rep = this.context.rep;
-      numOfLinesAbove = 0;
-      line = start[0] - 1;
-      while (!(rep.lines.atIndex(line).text.indexOf('\uFFF9') === -1)) {
-        numOfLinesAbove++;
-        line--;
+    } else {
+      if (colAttrs) {
+        colAttrs.splice(currTd, 1);
       }
-      return numOfLinesAbove;
-    };
-    dt.updateTableIndices = function(tblProperties, currTd, addOrDel){
-      var cellAttrs, rIndex, rLen, cellAttr, colAttrs;
-      cellAttrs = tblProperties.cellAttrs;
-      rIndex = 0;
-      rLen = cellAttrs.length;
-      while (rIndex < rLen) {
-        cellAttr = cellAttrs[rIndex];
-        if (addOrDel === 'add') {
-          if (cellAttr) {
-            cellAttr.splice(currTd, 0, null);
-          }
-        } else {
-          if (cellAttr) {
-            cellAttr.splice(currTd, 1);
-          }
-        }
-        rIndex++;
+    }
+    return tblProperties;
+  };
+  Datatables.sanitizeTblProperties = function(start, updateEvenOddBgColor, updateColAttrs, currTd, addOrDel){
+    var rep, editorInfo, thisAuthor, numOfLinesAbove, tempStart, evenOddRowBgColors, jsoTblProp, update, results$ = [];
+    rep = this.context.rep;
+    editorInfo = this.context.editorInfo;
+    thisAuthor = editorInfo.ace_getAuthor();
+    numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
+    tempStart = [];
+    tempStart[0] = start[0] - numOfLinesAbove;
+    evenOddRowBgColors = {};
+    updateEvenOddBgColor;
+    while (tempStart[0] < rep.lines.length() && rep.lines.atIndex(tempStart[0]).text.indexOf('\uFFF9') !== -1) {
+      jsoTblProp = this.getLineTableProperty(tempStart[0]);
+      update = false;
+      if (tempStart[0] !== start[0] && jsoTblProp['authors'] && jsoTblProp['authors'][thisAuthor]) {
+        delete jsoTblProp['authors'][thisAuthor];
+        update = true;
       }
-      colAttrs = tblProperties.colAttrs;
-      if (addOrDel === 'add') {
-        if (colAttrs) {
-          colAttrs.splice(currTd, 0, null);
-        }
-      } else {
-        if (colAttrs) {
-          colAttrs.splice(currTd, 1);
-        }
+      if (updateColAttrs) {
+        jsoTblProp = this.updateTableIndices(jsoTblProp, currTd, addOrDel);
+        update = true;
       }
-      return tblProperties;
-    };
-    dt.sanitizeTblProperties = function(start, updateEvenOddBgColor, updateColAttrs, currTd, addOrDel){
-      var rep, editorInfo, thisAuthor, numOfLinesAbove, tempStart, evenOddRowBgColors, jsoTblProp, update, results$ = [];
+      if (tempStart[0] !== start[0] && updateEvenOddBgColor) {
+        delete jsoTblProp['rowAttrs']['oddBgColor'];
+        delete jsoTblProp['rowAttrs']['evenBgColor'];
+        update = true;
+      }
+      if (update) {
+        this.updateTblPropInAPool(-1, -1, jsoTblProp, tempStart);
+      }
+      results$.push(tempStart[0] = tempStart[0] + 1);
+    }
+    return results$;
+  };
+  Datatables.updateTblPropInAPool = function(row, td, jsoTblProp, start){
+    var rep, editorInfo, thisAuthor, authorInfos, tblProps, jsoStrTblProp, attrStart, attrEnd, e;
+    try {
       rep = this.context.rep;
       editorInfo = this.context.editorInfo;
       thisAuthor = editorInfo.ace_getAuthor();
-      numOfLinesAbove = this.getTblAboveRowsFromCurFocus(start);
-      tempStart = [];
-      tempStart[0] = start[0] - numOfLinesAbove;
-      evenOddRowBgColors = {};
-      updateEvenOddBgColor;
-      while (tempStart[0] < rep.lines.length() && rep.lines.atIndex(tempStart[0]).text.indexOf('\uFFF9') !== -1) {
-        jsoTblProp = this.getLineTableProperty(tempStart[0]);
-        update = false;
-        if (tempStart[0] !== start[0] && jsoTblProp['authors'] && jsoTblProp['authors'][thisAuthor]) {
-          delete jsoTblProp['authors'][thisAuthor];
-          update = true;
-        }
-        if (updateColAttrs) {
-          jsoTblProp = this.updateTableIndices(jsoTblProp, currTd, addOrDel);
-          update = true;
-        }
-        if (tempStart[0] !== start[0] && updateEvenOddBgColor) {
-          delete jsoTblProp['rowAttrs']['oddBgColor'];
-          delete jsoTblProp['rowAttrs']['evenBgColor'];
-          update = true;
-        }
-        if (update) {
-          this.updateTblPropInAPool(-1, -1, jsoTblProp, tempStart);
-        }
-        results$.push(tempStart[0] = tempStart[0] + 1);
-      }
-      return results$;
-    };
-    dt.updateTblPropInAPool = function(row, td, jsoTblProp, start){
-      var rep, editorInfo, thisAuthor, authorInfos, tblProps, jsoStrTblProp, attrStart, attrEnd, e;
-      try {
-        rep = this.context.rep;
-        editorInfo = this.context.editorInfo;
-        thisAuthor = editorInfo.ace_getAuthor();
-        authorInfos = editorInfo.ace_getAuthorInfos();
-        tblProps = void 8;
-        if (typeof jsoTblProp === 'undefined' || jsoTblProp == null) {
-          jsoTblProp = this.getLineTableProperty(start[0]);
-        }
-        if (row !== -1 && td !== -1) {
-          jsoTblProp['authors'][thisAuthor] = {
-            row: row,
-            cell: td,
-            colorId: authorInfos[thisAuthor].bgcolor
-          };
-        }
-        jsoStrTblProp = JSON.stringify(jsoTblProp);
-        attrStart = [];
-        attrEnd = [];
-        attrStart[0] = start[0];
-        attrStart[1] = 0;
-        attrEnd[0] = start[0];
-        attrEnd[1] = rep.lines.atIndex(start[0]).text.length;
-        return editorInfo.ace_performDocumentApplyAttributesToRange(attrStart, attrEnd, [['tblProp', jsoStrTblProp]]);
-      } catch (e$) {
-        return e = e$;
+      authorInfos = editorInfo.ace_getAuthorInfos();
+      tblProps = void 8;
+      if (typeof jsoTblProp === 'undefined' || jsoTblProp == null) {
+        jsoTblProp = this.getLineTableProperty(start[0]);
       }
-    };
-    dt.updateTblCellAuthor = function(row, td, tblProperties, start, updateEvenOddBgColor){
-      var tempStart, e;
-      try {
-        this.updateTblPropInAPool(row, td, tblProperties, start);
-        tempStart = [];
-        tempStart[0] = start[0];
-        tempStart[1] = start[1];
-        return this.sanitizeTblProperties(tempStart, updateEvenOddBgColor);
-      } catch (e$) {
-        return e = e$;
+      if (row !== -1 && td !== -1) {
+        jsoTblProp['authors'][thisAuthor] = {
+          row: row,
+          cell: td,
+          colorId: authorInfos[thisAuthor].bgcolor
+        };
       }
-    };
-    return dt;
-  }();
-}
-if (typeof exports !== 'undefined') {
+      jsoStrTblProp = JSON.stringify(jsoTblProp);
+      attrStart = [];
+      attrEnd = [];
+      attrStart[0] = start[0];
+      attrStart[1] = 0;
+      attrEnd[0] = start[0];
+      attrEnd[1] = rep.lines.atIndex(start[0]).text.length;
+      return editorInfo.ace_performDocumentApplyAttributesToRange(attrStart, attrEnd, [['tblProp', jsoStrTblProp]]);
+    } catch (e$) {
+      return e = e$;
+    }
+  };
+  Datatables.updateTblCellAuthor = function(row, td, tblProperties, start, updateEvenOddBgColor){
+    var tempStart;
+    try {
+      this.updateTblPropInAPool(row, td, tblProperties, start);
+      tempStart = [];
+      tempStart[0] = start[0];
+      tempStart[1] = start[1];
+      return this.sanitizeTblProperties(tempStart, updateEvenOddBgColor);
+    } catch (e$) {}
+  };
+  function Datatables(){}
+  return Datatables;
+}());
+if (typeof exports != 'undefined' && exports !== null) {
   exports.Datatables = Datatables;
-} else {
-  null;
 }
\ No newline at end of file

From 15beb43cd35f795d97ab512d501fe26013f06661 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Wed, 31 Oct 2012 15:03:30 +0800
Subject: [PATCH 11/36] remove duplicated method: updateTblPropInAPool

---
 src/js/datatables.ls    | 23 -----------------------
 static/js/datatables.js | 30 ------------------------------
 2 files changed, 53 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index 2cb4a8c..517274f 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -890,29 +890,6 @@ class Datatables
           catch error
             return @defaults.tblProps
       @defaults.tblProps
-    @updateTblPropInAPool = (row, td, jsoTblProp, start) ->
-      try
-        rep = @context.rep
-        tblProps = void
-        editorInfo = @context.editorInfo
-        thisAuthor = editorInfo.ace_getAuthor!
-        authorInfos = editorInfo.ace_getAuthorInfos!
-        jsoTblProp = @getLineTableProperty start.0 if typeof jsoTblProp is 'undefined' or not jsoTblProp?
-        if row isnt -1 and td isnt -1
-          jsoTblProp.'authors'[thisAuthor] = {
-            row: row
-            cell: td
-            colorId: authorInfos[thisAuthor].bgcolor
-          }
-        jsoStrTblProp = JSON.stringify jsoTblProp
-        attrStart = []
-        attrEnd = []
-        attrStart.0 = start.0
-        attrStart.1 = 0
-        attrEnd.0 = start.0
-        attrEnd.1 = (rep.lines.atIndex start.0).text.length
-        editorInfo.ace_performDocumentApplyAttributesToRange attrStart, attrEnd, [['tblProp', jsoStrTblProp]]
-      catch
     @getCurrTblOddEvenRowBgColor = (startRowNum, currRowNum) ->
       rowBgColors = {
         oddBgColor: null
diff --git a/static/js/datatables.js b/static/js/datatables.js
index b465bdb..192e027 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -1204,36 +1204,6 @@ Datatables = (function(){
     }
     return this.defaults.tblProps;
   };
-  Datatables.updateTblPropInAPool = function(row, td, jsoTblProp, start){
-    var rep, tblProps, editorInfo, thisAuthor, authorInfos, jsoStrTblProp, attrStart, attrEnd, e;
-    try {
-      rep = this.context.rep;
-      tblProps = void 8;
-      editorInfo = this.context.editorInfo;
-      thisAuthor = editorInfo.ace_getAuthor();
-      authorInfos = editorInfo.ace_getAuthorInfos();
-      if (typeof jsoTblProp === 'undefined' || jsoTblProp == null) {
-        jsoTblProp = this.getLineTableProperty(start[0]);
-      }
-      if (row !== -1 && td !== -1) {
-        jsoTblProp['authors'][thisAuthor] = {
-          row: row,
-          cell: td,
-          colorId: authorInfos[thisAuthor].bgcolor
-        };
-      }
-      jsoStrTblProp = JSON.stringify(jsoTblProp);
-      attrStart = [];
-      attrEnd = [];
-      attrStart[0] = start[0];
-      attrStart[1] = 0;
-      attrEnd[0] = start[0];
-      attrEnd[1] = rep.lines.atIndex(start[0]).text.length;
-      return editorInfo.ace_performDocumentApplyAttributesToRange(attrStart, attrEnd, [['tblProp', jsoStrTblProp]]);
-    } catch (e$) {
-      return e = e$;
-    }
-  };
   Datatables.getCurrTblOddEvenRowBgColor = function(startRowNum, currRowNum){
     var rowBgColors, jsoTblProp1, jsoTblProp2;
     rowBgColors = {

From 26c375e36b65a178f406e6d8f09d69f81adf757b Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Wed, 31 Oct 2012 17:53:35 +0800
Subject: [PATCH 12/36] fix remaining unescaped quotes

---
 src/js/datatables.ls    | 16 ++++++++--------
 static/js/datatables.js | 16 ++++++++--------
 2 files changed, 16 insertions(+), 16 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index 517274f..e664527 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -131,7 +131,7 @@ class Datatables
     }}
     @config= {}
     @vars= {
-        OVERHEAD_LEN_PRE: '{\uF134payload":[[\uF134'.length
+        OVERHEAD_LEN_PRE: '{\uF134payload\uF134:[[\uF134'.length
         OVERHEAD_LEN_MID: '\uF134,\uF134'.length
         OVERHEAD_LEN_ROW_START: '[\uF134'.length
         OVERHEAD_LEN_ROW_END: '\uF134],'.length
@@ -641,10 +641,10 @@ class Datatables
           tblJSONObj = fromEscapedJSON currLineText
           payload = tblJSONObj.payload
           cellPos = (@getTdInfo payload, currTd).cellEndOffset
-          newText = '" ",'
+          newText = '\uF134 \uF134,'
           if currTd is payload.0.length - 1
             rep.selStart.1 = rep.selEnd.1 = cellPos - @vars.OVERHEAD_LEN_ROW_END + 1
-            newText = '," "'
+            newText = ',\uF134 \uF134'
           else
             if currTd is -1 then rep.selStart.1 = rep.selEnd.1 = @vars.OVERHEAD_LEN_PRE - 1 else rep.selStart.1 = rep.selEnd.1 = cellPos - 1
           @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, newText
@@ -685,7 +685,7 @@ class Datatables
           tblJSONObj = fromEscapedJSON currLineText
           payload = tblJSONObj.payload
           cellTdInfo = @getTdInfo payload, currTd
-          newText = '" ",'
+          newText = '\uF134 \uF134,'
           if currTd is payload.0.length - 1
             rep.selStart.1 = cellTdInfo.cellStartOffset - 2
             rep.selEnd.1 = cellTdInfo.cellEndOffset - 2
@@ -743,10 +743,10 @@ class Datatables
         func = 'doTableReturnKey()'
         try
           currCarretPos = rep.selStart.1
-          if (currLineText.substring currCarretPos - 1, currCarretPos + 2) is '","'
+          if (currLineText.substring currCarretPos - 1, currCarretPos + 2) is '\uF134,\uF134'
             return true
           else
-            if (currLineText.substring currCarretPos - 2, currCarretPos + 1) is '","'
+            if (currLineText.substring currCarretPos - 2, currCarretPos + 1) is '\uF134,\uF134'
               return true
             else
               if currCarretPos < @vars.OVERHEAD_LEN_PRE then return true else if currCarretPos > currLineText.length then return true
@@ -779,10 +779,10 @@ class Datatables
         currTdInfo = @getFocusedTdInfo table, rep.selStart.1
         cellEntryLen = table[currTdInfo.row][currTdInfo.td].length
         currCarretPos = rep.selStart.1
-        if (currLineText.substring currCarretPos - 1, currCarretPos + 2) is '","'
+        if (currLineText.substring currCarretPos - 1, currCarretPos + 2) is '\uF134,\uF134'
           return false
         else
-          if (currLineText.substring currCarretPos - 2, currCarretPos + 1) is '","' then return false
+          if (currLineText.substring currCarretPos - 2, currCarretPos + 1) is '\uF134,\uF134' then return false
         switch keyCode
         case @vars.JS_KEY_CODE_BS
           isDeleteAccepted = true if cellEntryLen isnt 0 and cellEntryLen > currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 192e027..ba91778 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -180,7 +180,7 @@ Datatables = (function(){
   };
   Datatables.config = {};
   Datatables.vars = {
-    OVERHEAD_LEN_PRE: '{\uF134payload":[[\uF134'.length,
+    OVERHEAD_LEN_PRE: '{\uF134payload\uF134:[[\uF134'.length,
     OVERHEAD_LEN_MID: '\uF134,\uF134'.length,
     OVERHEAD_LEN_ROW_START: '[\uF134'.length,
     OVERHEAD_LEN_ROW_END: '\uF134],'.length,
@@ -854,10 +854,10 @@ Datatables = (function(){
         tblJSONObj = fromEscapedJSON(currLineText);
         payload = tblJSONObj.payload;
         cellPos = this.getTdInfo(payload, currTd).cellEndOffset;
-        newText = '" ",';
+        newText = '\uF134 \uF134,';
         if (currTd === payload[0].length - 1) {
           rep.selStart[1] = rep.selEnd[1] = cellPos - this.vars.OVERHEAD_LEN_ROW_END + 1;
-          newText = '," "';
+          newText = ',\uF134 \uF134';
         } else {
           if (currTd === -1) {
             rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE - 1;
@@ -911,7 +911,7 @@ Datatables = (function(){
         tblJSONObj = fromEscapedJSON(currLineText);
         payload = tblJSONObj.payload;
         cellTdInfo = this.getTdInfo(payload, currTd);
-        newText = '" ",';
+        newText = '\uF134 \uF134,';
         if (currTd === payload[0].length - 1) {
           rep.selStart[1] = cellTdInfo.cellStartOffset - 2;
           rep.selEnd[1] = cellTdInfo.cellEndOffset - 2;
@@ -983,10 +983,10 @@ Datatables = (function(){
       func = 'doTableReturnKey()';
       try {
         currCarretPos = rep.selStart[1];
-        if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '","') {
+        if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '\uF134,\uF134') {
           return true;
         } else {
-          if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) === '","') {
+          if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) === '\uF134,\uF134') {
             return true;
           } else {
             if (currCarretPos < this.vars.OVERHEAD_LEN_PRE) {
@@ -1036,10 +1036,10 @@ Datatables = (function(){
       currTdInfo = this.getFocusedTdInfo(table, rep.selStart[1]);
       cellEntryLen = table[currTdInfo.row][currTdInfo.td].length;
       currCarretPos = rep.selStart[1];
-      if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '","') {
+      if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '\uF134,\uF134') {
         return false;
       } else {
-        if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) === '","') {
+        if (currLineText.substring(currCarretPos - 2, currCarretPos + 1) === '\uF134,\uF134') {
           return false;
         }
       }

From 33c2e2d5b9bf16ccc56ea005936084acbe8d842b Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Wed, 31 Oct 2012 17:54:46 +0800
Subject: [PATCH 13/36] cleanup render call

---
 src/js/datatables-renderer.ls    |  7 ++-----
 src/js/datatables.ls             | 13 +++++++------
 static/js/datatables-renderer.js | 15 ++++-----------
 static/js/datatables.js          | 22 +++++++++++-----------
 4 files changed, 24 insertions(+), 33 deletions(-)

diff --git a/src/js/datatables-renderer.ls b/src/js/datatables-renderer.ls
index 3379b8c..f8c7700 100644
--- a/src/js/datatables-renderer.ls
+++ b/src/js/datatables-renderer.ls
@@ -1,8 +1,7 @@
 DatatablesRenderer = {}
 class DatatablesRenderer
-  @render = (params, element, attributes) ->
+  @render = (params, element, code, attributes) ->
     renderer = new DatatablesRenderer.Renderer
-    if element.innerText then code = element.innerText else code = element.textContent
     element.innerHTML = renderer.getHtml code, attributes
 
   class @Renderer
@@ -141,11 +140,9 @@ class DatatablesRenderer
         intAttrValue = parseFloat attrValue
         attrValue = if isNaN intAttrValue then parseFloat attrValue else intAttrValue
         96 * attrValue - 1
-      getHtml: (code, attributes) ->
-        JSONCode = ''
+      getHtml: (JSONCode, attributes) ->
         html = ''
         try
-          JSONCode = JSON.parse code.replace(/(\\|")/g, '\\$1').replace(/\uF134/g, '"')
           html = @buildTabularData JSONCode, attributes
         catch
         html
diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index e664527..005d560 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -27,17 +27,18 @@ exports.aceInitialized = (hook, context) ->
   editorInfo = context.editorInfo
   editorInfo.ace_doDatatableOptions = (_ Datatables.doDatatableOptions).bind context
 
-exports.acePostWriteDomLineHTML = (hook_name, args, cb) ->
-  children = args.node.children
+exports.acePostWriteDomLineHTML = (hook_name, {node}, cb) ->
+  children = node.children
   i = 0
   while i < children.length
-    continue if (args.node.children[i].className.indexOf 'list') isnt -1 or (args.node.children[i].className.indexOf 'tag') isnt -1 or (args.node.children[i].className.indexOf 'url') isnt -1
-    lineText = ''
-    if args.node.children[i].innerText then lineText = args.node.children[i].innerText else lineText = args.node.children[i].textContent
+    element = children[i]
+    continue if (element.className.indexOf 'list') isnt -1 or (element.className.indexOf 'tag') isnt -1 or (element.className.indexOf 'url') isnt -1
+    lineText = element.innerText ? element.textContent
     if lineText and (lineText.indexOf '\uFFF9') isnt -1
       dtAttrs = if typeof exports.Datatables isnt 'undefined' then exports.Datatables.attributes else null
       dtAttrs = dtAttrs or ''
-      DatatablesRenderer.render {}, args.node.children[i], dtAttrs
+      code = fromEscapedJSON lineText
+      DatatablesRenderer.render {}, element, code, dtAttrs
       exports.Datatables.attributes = null
     i++
 
diff --git a/static/js/datatables-renderer.js b/static/js/datatables-renderer.js
index 4bd2ad4..a70dba0 100644
--- a/static/js/datatables-renderer.js
+++ b/static/js/datatables-renderer.js
@@ -3,14 +3,9 @@ DatatablesRenderer = {};
 DatatablesRenderer = (function(){
   DatatablesRenderer.displayName = 'DatatablesRenderer';
   var Renderer, prototype = DatatablesRenderer.prototype, constructor = DatatablesRenderer;
-  DatatablesRenderer.render = function(params, element, attributes){
-    var renderer, code;
+  DatatablesRenderer.render = function(params, element, code, attributes){
+    var renderer;
     renderer = new DatatablesRenderer.Renderer;
-    if (element.innerText) {
-      code = element.innerText;
-    } else {
-      code = element.textContent;
-    }
     return element.innerHTML = renderer.getHtml(code, attributes);
   };
   DatatablesRenderer.Renderer = Renderer = (function(){
@@ -228,12 +223,10 @@ DatatablesRenderer = (function(){
       attrValue = isNaN(intAttrValue) ? parseFloat(attrValue) : intAttrValue;
       return 96 * attrValue - 1;
     };
-    prototype.getHtml = function(code, attributes){
-      var JSONCode, html, e;
-      JSONCode = '';
+    prototype.getHtml = function(JSONCode, attributes){
+      var html, e;
       html = '';
       try {
-        JSONCode = JSON.parse(code.replace(/(\\|")/g, '\\$1').replace(/\uF134/g, '"'));
         html = this.buildTabularData(JSONCode, attributes);
       } catch (e$) {
         e = e$;
diff --git a/static/js/datatables.js b/static/js/datatables.js
index ba91778..6bff7b2 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -31,24 +31,24 @@ exports.aceInitialized = function(hook, context){
   editorInfo = context.editorInfo;
   return editorInfo.ace_doDatatableOptions = _(Datatables.doDatatableOptions).bind(context);
 };
-exports.acePostWriteDomLineHTML = function(hook_name, args, cb){
-  var children, i, lineText, dtAttrs, results$ = [];
-  children = args.node.children;
+exports.acePostWriteDomLineHTML = function(hook_name, arg$, cb){
+  var node, children, i, element, lineText, ref$, dtAttrs, code, results$ = [];
+  node = arg$.node;
+  children = node.children;
   i = 0;
   while (i < children.length) {
-    if (args.node.children[i].className.indexOf('list') !== -1 || args.node.children[i].className.indexOf('tag') !== -1 || args.node.children[i].className.indexOf('url') !== -1) {
+    element = children[i];
+    if (element.className.indexOf('list') !== -1 || element.className.indexOf('tag') !== -1 || element.className.indexOf('url') !== -1) {
       continue;
     }
-    lineText = '';
-    if (args.node.children[i].innerText) {
-      lineText = args.node.children[i].innerText;
-    } else {
-      lineText = args.node.children[i].textContent;
-    }
+    lineText = (ref$ = element.innerText) != null
+      ? ref$
+      : element.textContent;
     if (lineText && lineText.indexOf('\uFFF9') !== -1) {
       dtAttrs = typeof exports.Datatables !== 'undefined' ? exports.Datatables.attributes : null;
       dtAttrs = dtAttrs || '';
-      DatatablesRenderer.render({}, args.node.children[i], dtAttrs);
+      code = fromEscapedJSON(lineText);
+      DatatablesRenderer.render({}, element, code, dtAttrs);
       exports.Datatables.attributes = null;
     }
     results$.push(i++);

From 0658433e5227641bb9cb486b19ab554a437d3cb8 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Wed, 31 Oct 2012 23:51:32 +0800
Subject: [PATCH 14/36] fix incorrect js2ls loop translation causing infinite
 loop

---
 src/js/datatables.ls    | 3 +--
 static/js/datatables.js | 5 ++---
 2 files changed, 3 insertions(+), 5 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index 005d560..2c81fe4 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -31,7 +31,7 @@ exports.acePostWriteDomLineHTML = (hook_name, {node}, cb) ->
   children = node.children
   i = 0
   while i < children.length
-    element = children[i]
+    element = children[i++]
     continue if (element.className.indexOf 'list') isnt -1 or (element.className.indexOf 'tag') isnt -1 or (element.className.indexOf 'url') isnt -1
     lineText = element.innerText ? element.textContent
     if lineText and (lineText.indexOf '\uFFF9') isnt -1
@@ -40,7 +40,6 @@ exports.acePostWriteDomLineHTML = (hook_name, {node}, cb) ->
       code = fromEscapedJSON lineText
       DatatablesRenderer.render {}, element, code, dtAttrs
       exports.Datatables.attributes = null
-    i++
 
 exports.eejsBlock_scripts = (hook_name, args, cb) ->
   args.content = args.content + (require 'ep_etherpad-lite/node/eejs/').require 'ep_tables/templates/datatablesScripts.ejs'
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 6bff7b2..6ab1fe3 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -37,7 +37,7 @@ exports.acePostWriteDomLineHTML = function(hook_name, arg$, cb){
   children = node.children;
   i = 0;
   while (i < children.length) {
-    element = children[i];
+    element = children[i++];
     if (element.className.indexOf('list') !== -1 || element.className.indexOf('tag') !== -1 || element.className.indexOf('url') !== -1) {
       continue;
     }
@@ -49,9 +49,8 @@ exports.acePostWriteDomLineHTML = function(hook_name, arg$, cb){
       dtAttrs = dtAttrs || '';
       code = fromEscapedJSON(lineText);
       DatatablesRenderer.render({}, element, code, dtAttrs);
-      exports.Datatables.attributes = null;
+      results$.push(exports.Datatables.attributes = null);
     }
-    results$.push(i++);
   }
   return results$;
 };

From add756110c49b6d1a241dd2358480553357ec859 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Wed, 31 Oct 2012 23:55:42 +0800
Subject: [PATCH 15/36] less tangled logic

---
 src/js/datatables.ls    | 6 +++---
 static/js/datatables.js | 9 +++------
 2 files changed, 6 insertions(+), 9 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index 2c81fe4..d86b692 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -242,11 +242,11 @@ class Datatables
         return 
       if line
         currLineText = line.text
-        if not ((currLineText.indexOf '\uFFF9') is -1)
-          while true
+        if currLineText.indexOf('\uFFF9') isnt -1
+          do
             rep.selStart.0 = rep.selStart.0 + 1
             currLineText = (rep.lines.atIndex rep.selStart.0).text
-            break if not ((currLineText.indexOf '\uFFF9') isnt -1)
+          while currLineText.indexOf('\uFFF9') isnt -1
           rep.selEnd.1 = rep.selStart.1 = currLineText.length
           @context.editorInfo.ace_doReturnKey!
           @context.editorInfo.ace_doReturnKey!
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 6ab1fe3..4644faf 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -311,14 +311,11 @@ Datatables = (function(){
     }
     if (line) {
       currLineText = line.text;
-      if (!(currLineText.indexOf('\uFFF9') === -1)) {
-        for (;;) {
+      if (currLineText.indexOf('\uFFF9') !== -1) {
+        do {
           rep.selStart[0] = rep.selStart[0] + 1;
           currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-          if (!(currLineText.indexOf('\uFFF9') !== -1)) {
-            break;
-          }
-        }
+        } while (currLineText.indexOf('\uFFF9') !== -1);
         rep.selEnd[1] = rep.selStart[1] = currLineText.length;
         this.context.editorInfo.ace_doReturnKey();
         this.context.editorInfo.ace_doReturnKey();

From d2a9b041f40e9c04a8b13d34b37947d646a01cc1 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Thu, 1 Nov 2012 00:45:42 +0800
Subject: [PATCH 16/36] fix cursor jump due to js2ls error

---
 src/js/datatables.ls    | 5 ++++-
 static/js/datatables.js | 2 +-
 2 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index d86b692..faa399c 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -118,7 +118,10 @@ class Datatables
       iLen = els.length
       while i < iLen
         el = els[i]
-        if el.nodeType is 1 and el.tagName.toLowerCase! of excluded then text.push nodeText el else if el.nodeType is 3 then text.push el.data
+        if el.nodeType is 1 and !(el.tagName.toLowerCase! of excluded)
+          text.push nodeText el
+        else if el.nodeType is 3
+          text.push el.data
         i++
       text.join ''
     @defaults= {tblProps: {
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 4644faf..5d22faf 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -158,7 +158,7 @@ Datatables = (function(){
     iLen = els.length;
     while (i < iLen) {
       el = els[i];
-      if (el.nodeType === 1 && el.tagName.toLowerCase() in excluded) {
+      if (el.nodeType === 1 && !(el.tagName.toLowerCase() in excluded)) {
         text.push(nodeText(el));
       } else if (el.nodeType === 3) {
         text.push(el.data);

From 3dfc2ff2f2d46326d3bde96f5b3e5325efa342d4 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Thu, 1 Nov 2012 11:13:51 +0800
Subject: [PATCH 17/36] cleanup nodeText

---
 src/js/datatables.ls    | 22 +++++++---------------
 static/js/datatables.js | 23 ++++++++++-------------
 2 files changed, 17 insertions(+), 28 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index faa399c..cf6c92c 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -106,23 +106,15 @@ exports.aceKeyEvent = (hook, context) ->
   specialHandled
 
 class Datatables
-    nodeText = (n) ->
-      text = []
-      el = void
-      els = n.childNodes
-      excluded = {
+    nodeText = ({childNodes}) ->
+      excluded = do
         noscript: 'noscript'
         script: 'script'
-      }
-      i = 0
-      iLen = els.length
-      while i < iLen
-        el = els[i]
-        if el.nodeType is 1 and !(el.tagName.toLowerCase! of excluded)
-          text.push nodeText el
+      text = for el in childNodes
+        if el.nodeType is 1 and el.tagName.toLowerCase! not of excluded
+          nodeText el
         else if el.nodeType is 3
-          text.push el.data
-        i++
+          el.data
       text.join ''
     @defaults= {tblProps: {
         borderWidth: '1'
@@ -152,7 +144,7 @@ class Datatables
           'delImg'
         ]
     }
-    context: null
+    @context= null
     @isFocused = ->
       return false if not @context.rep.selStart or not @context.rep.selEnd
       line = @context.rep.lines.atIndex @context.rep.selStart.0
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 5d22faf..c644c73 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -145,26 +145,23 @@ exports.aceKeyEvent = function(hook, context){
 Datatables = (function(){
   Datatables.displayName = 'Datatables';
   var nodeText, prototype = Datatables.prototype, constructor = Datatables;
-  nodeText = function(n){
-    var text, el, els, excluded, i, iLen;
-    text = [];
-    el = void 8;
-    els = n.childNodes;
+  nodeText = function(arg$){
+    var childNodes, excluded, text, res$, i$, len$, el;
+    childNodes = arg$.childNodes;
     excluded = {
       noscript: 'noscript',
       script: 'script'
     };
-    i = 0;
-    iLen = els.length;
-    while (i < iLen) {
-      el = els[i];
+    res$ = [];
+    for (i$ = 0, len$ = childNodes.length; i$ < len$; ++i$) {
+      el = childNodes[i$];
       if (el.nodeType === 1 && !(el.tagName.toLowerCase() in excluded)) {
-        text.push(nodeText(el));
+        res$.push(nodeText(el));
       } else if (el.nodeType === 3) {
-        text.push(el.data);
+        res$.push(el.data);
       }
-      i++;
     }
+    text = res$;
     return text.join('');
   };
   Datatables.defaults = {
@@ -187,7 +184,7 @@ Datatables = (function(){
     JS_KEY_CODE_DEL: 46,
     TBL_OPTIONS: ['addTbl', 'addTblRowA', 'addTblRowB', 'addTblColL', 'addTblColR', 'delTbl', 'delTblRow', 'delTblCol', 'delImg']
   };
-  prototype.context = null;
+  Datatables.context = null;
   Datatables.isFocused = function(){
     var line, currLineText;
     if (!this.context.rep.selStart || !this.context.rep.selEnd) {

From 0122e04196d4ec34922eecbdfbcf2120b9462315 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Thu, 1 Nov 2012 11:16:35 +0800
Subject: [PATCH 18/36] fix backspace and prevent table payload leak

---
 src/js/datatables.ls    | 24 ++++++++++--------------
 static/js/datatables.js | 20 ++++++++------------
 2 files changed, 18 insertions(+), 26 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index cf6c92c..3fa24b2 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -760,34 +760,30 @@ class Datatables
         catch
         true
     @isCellDeleteOk = (keyCode) ->
-      context = @context
-      rep = context.rep
-      start = rep.selStart
-      end = rep.selEnd
-      currLine = rep.lines.atIndex rep.selStart.0
-      currLineText = currLine.text
+      {selStart:start}:rep = @context.rep
+      {text:currLineText} = rep.lines.atIndex start.0
       return true if (currLineText.indexOf '\uFFF9') is -1
       isDeleteAccepted = false
-      (try
+      try
         tblJSONObj = fromEscapedJSON currLineText
         table = tblJSONObj.payload
-        currTdInfo = @getFocusedTdInfo table, rep.selStart.1
+        currTdInfo = @getFocusedTdInfo table, start.1
         cellEntryLen = table[currTdInfo.row][currTdInfo.td].length
-        currCarretPos = rep.selStart.1
+        currCarretPos = start.1
         if (currLineText.substring currCarretPos - 1, currCarretPos + 2) is '\uF134,\uF134'
           return false
         else
           if (currLineText.substring currCarretPos - 2, currCarretPos + 1) is '\uF134,\uF134' then return false
         switch keyCode
         case @vars.JS_KEY_CODE_BS
-          isDeleteAccepted = true if cellEntryLen isnt 0 and cellEntryLen > currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID
+          isDeleteAccepted = true if cellEntryLen > 1 and cellEntryLen > currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID
         case @vars.JS_KEY_CODE_DEL
-          return false
-          isDeleteAccepted = true if cellEntryLen isnt 0 and currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID > 0
+          return false # still buggy and can corrupt table structure
+          isDeleteAccepted = true if cellEntryLen > 0 and currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID > 0
         default
-          isDeleteAccepted = true if cellEntryLen isnt 0 and cellEntryLen > currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID
+          isDeleteAccepted = true if cellEntryLen > 1 and cellEntryLen > currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID
       catch error
-        isDeleteAccepted = false)
+        isDeleteAccepted = false
       isDeleteAccepted
     @nodeTextPlain = (n) -> n.innerText or n.textContent or n.nodeValue or ''
     @toString = -> 'ep_tables'
diff --git a/static/js/datatables.js b/static/js/datatables.js
index c644c73..06ba9f0 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -1012,13 +1012,9 @@ Datatables = (function(){
     }
   };
   Datatables.isCellDeleteOk = function(keyCode){
-    var context, rep, start, end, currLine, currLineText, isDeleteAccepted, tblJSONObj, table, currTdInfo, cellEntryLen, currCarretPos, error;
-    context = this.context;
-    rep = context.rep;
-    start = rep.selStart;
-    end = rep.selEnd;
-    currLine = rep.lines.atIndex(rep.selStart[0]);
-    currLineText = currLine.text;
+    var rep, start, currLineText, isDeleteAccepted, tblJSONObj, table, currTdInfo, cellEntryLen, currCarretPos, error;
+    rep = this.context.rep, start = rep.selStart;
+    currLineText = rep.lines.atIndex(start[0]).text;
     if (currLineText.indexOf('\uFFF9') === -1) {
       return true;
     }
@@ -1026,9 +1022,9 @@ Datatables = (function(){
     try {
       tblJSONObj = fromEscapedJSON(currLineText);
       table = tblJSONObj.payload;
-      currTdInfo = this.getFocusedTdInfo(table, rep.selStart[1]);
+      currTdInfo = this.getFocusedTdInfo(table, start[1]);
       cellEntryLen = table[currTdInfo.row][currTdInfo.td].length;
-      currCarretPos = rep.selStart[1];
+      currCarretPos = start[1];
       if (currLineText.substring(currCarretPos - 1, currCarretPos + 2) === '\uF134,\uF134') {
         return false;
       } else {
@@ -1038,18 +1034,18 @@ Datatables = (function(){
       }
       switch (keyCode) {
       case this.vars.JS_KEY_CODE_BS:
-        if (cellEntryLen !== 0 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
+        if (cellEntryLen > 1 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
           isDeleteAccepted = true;
         }
         break;
       case this.vars.JS_KEY_CODE_DEL:
         return false;
-        if (cellEntryLen !== 0 && currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID > 0) {
+        if (cellEntryLen > 0 && currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID > 0) {
           isDeleteAccepted = true;
         }
         break;
       default:
-        if (cellEntryLen !== 0 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
+        if (cellEntryLen > 1 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
           isDeleteAccepted = true;
         }
       }

From bb6b2246d153d0b0ecd3374c0754bc67315d849e Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Thu, 1 Nov 2012 11:21:02 +0800
Subject: [PATCH 19/36] simplify logic

---
 src/js/datatables.ls    | 6 +++---
 static/js/datatables.js | 8 +++-----
 2 files changed, 6 insertions(+), 8 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index 3fa24b2..220367d 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -734,7 +734,7 @@ class Datatables
       lastTblPropertyUsed = 'doTableReturnKey'
       currLine = rep.lines.atIndex rep.selStart.0
       currLineText = currLine.text
-      if not ((currLineText.indexOf '\uFFF9') is -1)
+      if currLineText.indexOf('\uFFF9') isnt -1
         func = 'doTableReturnKey()'
         try
           currCarretPos = rep.selStart.1
@@ -804,10 +804,10 @@ class Datatables
         col = point.index if (nodeText n) or point.index > 0
         parNode = void
         prevSib = void
-        while not ((parNode = n.parentNode) is root)
+        while (parNode = n.parentNode) isnt root
           if prevSib = n.previousSibling
             n = prevSib
-            textLen = if (nodeText n).length is 0 then (@nodeTextPlain n).length else (nodeText n).length
+            textLen = nodeText(n).length or @nodeTextPlain(n).length
             col += textLen
           else
             n = parNode
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 06ba9f0..5c9ddf4 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -972,7 +972,7 @@ Datatables = (function(){
     lastTblPropertyUsed = 'doTableReturnKey';
     currLine = rep.lines.atIndex(rep.selStart[0]);
     currLineText = currLine.text;
-    if (!(currLineText.indexOf('\uFFF9') === -1)) {
+    if (currLineText.indexOf('\uFFF9') !== -1) {
       func = 'doTableReturnKey()';
       try {
         currCarretPos = rep.selStart[1];
@@ -1082,12 +1082,10 @@ Datatables = (function(){
       }
       parNode = void 8;
       prevSib = void 8;
-      while (!((parNode = n.parentNode) === root)) {
+      while ((parNode = n.parentNode) !== root) {
         if (prevSib = n.previousSibling) {
           n = prevSib;
-          textLen = nodeText(n).length === 0
-            ? this.nodeTextPlain(n).length
-            : nodeText(n).length;
+          textLen = nodeText(n).length || this.nodeTextPlain(n).length;
           col += textLen;
         } else {
           n = parNode;

From b05123104c25be78e44c754a80d0f3c376590d1d Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Thu, 1 Nov 2012 11:59:21 +0800
Subject: [PATCH 20/36] disable styling buttons when we are inside table. still
 need css to make the buttons look disabled

---
 src/js/datatables.ls    | 25 ++++++++++++++++++++++++-
 static/js/datatables.js | 30 +++++++++++++++++++++++++++++-
 2 files changed, 53 insertions(+), 2 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index 220367d..6d2482e 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -66,11 +66,34 @@ exports.aceStartLineAndCharForPoint = (hook, context) ->
     top.console.log 'context rep' + Datatables.context.rep
   selStart
 
+_stylesDisabled = false
+
+enableStyles = ->
+  return unless _stylesDisabled
+  $(\#editbar)find('li[data-key]')each ->
+    el = $ @
+    key = el.data \keyOrig
+    el.data(\key, key).attr('data-key', key)
+  _stylesDisabled := false
+
+disableStyles = ->
+  return if _stylesDisabled
+  # note that pad_editbar.js uses attr, so just clearing data('key') doesn't work
+  $(\#editbar)find('li[data-key]')each ->
+    el = $ @
+    key = el.data \key
+    el.data(\keyOrig, key)data(\key, null)attr('data-key', '')
+  _stylesDisabled := true
+
 exports.aceEndLineAndCharForPoint = (hook, context) ->
   selEndLine = null
   try
     Datatables.context = context
-    selEndLine = Datatables.getLineAndCharForPoint! if Datatables.isFocused!
+    if Datatables.isFocused!
+      disableStyles!
+      selEndLine = Datatables.getLineAndCharForPoint!
+    else
+      enableStyles!
   catch error
     top.console.log 'error ' + error
     top.console.log 'context rep' + Datatables.context.rep
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 5c9ddf4..0008f67 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -1,4 +1,4 @@
-var _, Ace2Common, Changeset, escapedJSON, fromEscapedJSON, Datatables;
+var _, Ace2Common, Changeset, escapedJSON, fromEscapedJSON, _stylesDisabled, enableStyles, disableStyles, Datatables;
 _ = require('ep_etherpad-lite/static/js/underscore');
 if (!(typeof require === 'undefined')) {
   if (typeof Ace2Common === 'undefined') {
@@ -85,13 +85,41 @@ exports.aceStartLineAndCharForPoint = function(hook, context){
   }
   return selStart;
 };
+_stylesDisabled = false;
+enableStyles = function(){
+  if (!_stylesDisabled) {
+    return;
+  }
+  $('#editbar').find('li[data-key]').each(function(){
+    var el, key;
+    el = $(this);
+    key = el.data('keyOrig');
+    return el.data('key', key).attr('data-key', key);
+  });
+  return _stylesDisabled = false;
+};
+disableStyles = function(){
+  if (_stylesDisabled) {
+    return;
+  }
+  $('#editbar').find('li[data-key]').each(function(){
+    var el, key;
+    el = $(this);
+    key = el.data('key');
+    return el.data('keyOrig', key).data('key', null).attr('data-key', '');
+  });
+  return _stylesDisabled = true;
+};
 exports.aceEndLineAndCharForPoint = function(hook, context){
   var selEndLine, error;
   selEndLine = null;
   try {
     Datatables.context = context;
     if (Datatables.isFocused()) {
+      disableStyles();
       selEndLine = Datatables.getLineAndCharForPoint();
+    } else {
+      enableStyles();
     }
   } catch (e$) {
     error = e$;

From 831e838dd5bcd76eb5fb0be432004e41be37dbb0 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Thu, 1 Nov 2012 21:40:30 +0800
Subject: [PATCH 21/36] use relative path for css/js

---
 src/js/datatables-ui.ls         | 2 +-
 static/js/datatables-ui.js      | 2 +-
 templates/datatablesScripts.ejs | 2 +-
 templates/styles.ejs            | 2 +-
 4 files changed, 4 insertions(+), 4 deletions(-)

diff --git a/src/js/datatables-ui.ls b/src/js/datatables-ui.ls
index 8c2fd4d..b5b23b1 100644
--- a/src/js/datatables-ui.ls
+++ b/src/js/datatables-ui.ls
@@ -1,5 +1,5 @@
 exports.aceInitInnerdocbodyHead = (hook_name, args, cb) ->
-  args.iframeHTML.push '<link rel="stylesheet" type="text/css" href="/static/plugins/ep_tables/static/css/dataTables.css"/>'
+  args.iframeHTML.push '<link rel="stylesheet" type="text/css" href="../static/plugins/ep_tables/static/css/dataTables.css"/>'
 
 exports.postAceInit = (hook, context) ->
   $.createTableMenu = (init) ->
diff --git a/static/js/datatables-ui.js b/static/js/datatables-ui.js
index acaa899..1e8bbeb 100644
--- a/static/js/datatables-ui.js
+++ b/static/js/datatables-ui.js
@@ -1,5 +1,5 @@
 exports.aceInitInnerdocbodyHead = function(hook_name, args, cb){
-  return args.iframeHTML.push('<link rel="stylesheet" type="text/css" href="/static/plugins/ep_tables/static/css/dataTables.css"/>');
+  return args.iframeHTML.push('<link rel="stylesheet" type="text/css" href="../static/plugins/ep_tables/static/css/dataTables.css"/>');
 };
 exports.postAceInit = function(hook, context){
   $.createTableMenu = function(init){
diff --git a/templates/datatablesScripts.ejs b/templates/datatablesScripts.ejs
index f0bf40c..e1516f6 100644
--- a/templates/datatablesScripts.ejs
+++ b/templates/datatablesScripts.ejs
@@ -1,6 +1,6 @@
 
 
-<script src="/static/plugins/ep_tables/static/js/datatables-renderer.js"></script>
+<script src="../static/plugins/ep_tables/static/js/datatables-renderer.js"></script>
 <script type="text/javascript">
 	require.define("datatables-renderer", function(require, exports, module) { exports.DatatablesRenderer = DatatablesRenderer; });
 </script>
diff --git a/templates/styles.ejs b/templates/styles.ejs
index 1c669e1..eee1ec5 100644
--- a/templates/styles.ejs
+++ b/templates/styles.ejs
@@ -6,4 +6,4 @@
 <link rel='stylesheet' href='http://yui.yahooapis.com/2.9.0/build/container/assets/skins/sam/container.css' type='text/css' />
 <link rel='stylesheet' href='http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/skins/sam/colorpicker.css' type='text/css' />
 
-<link rel="stylesheet" href="/static/plugins/ep_tables/static/css/data-tbl-menu.css" type="text/css" />
+<link rel="stylesheet" href="../static/plugins/ep_tables/static/css/data-tbl-menu.css" type="text/css" />

From 9a3e7fea5973cafe7e7db374344c2aee1d6ebbef Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Mon, 5 Nov 2012 21:14:31 +0800
Subject: [PATCH 22/36] parse the whole line for table json, so intermediate
 elements like span.url do not break the payload.

---
 src/js/datatables.ls    | 19 +++++++------------
 static/js/datatables.js | 27 ++++++++-------------------
 2 files changed, 15 insertions(+), 31 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index 6d2482e..b28b3c0 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -28,18 +28,13 @@ exports.aceInitialized = (hook, context) ->
   editorInfo.ace_doDatatableOptions = (_ Datatables.doDatatableOptions).bind context
 
 exports.acePostWriteDomLineHTML = (hook_name, {node}, cb) ->
-  children = node.children
-  i = 0
-  while i < children.length
-    element = children[i++]
-    continue if (element.className.indexOf 'list') isnt -1 or (element.className.indexOf 'tag') isnt -1 or (element.className.indexOf 'url') isnt -1
-    lineText = element.innerText ? element.textContent
-    if lineText and (lineText.indexOf '\uFFF9') isnt -1
-      dtAttrs = if typeof exports.Datatables isnt 'undefined' then exports.Datatables.attributes else null
-      dtAttrs = dtAttrs or ''
-      code = fromEscapedJSON lineText
-      DatatablesRenderer.render {}, element, code, dtAttrs
-      exports.Datatables.attributes = null
+  lineText = node.textContent
+  if lineText and (lineText.indexOf '\uFFF9') isnt -1
+    dtAttrs = if typeof exports.Datatables isnt 'undefined' then exports.Datatables.attributes else null
+    dtAttrs = dtAttrs or ''
+    code = fromEscapedJSON lineText
+    DatatablesRenderer.render {}, node, code, dtAttrs
+    exports.Datatables.attributes = null
 
 exports.eejsBlock_scripts = (hook_name, args, cb) ->
   args.content = args.content + (require 'ep_etherpad-lite/node/eejs/').require 'ep_tables/templates/datatablesScripts.ejs'
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 0008f67..68c5f50 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -32,27 +32,16 @@ exports.aceInitialized = function(hook, context){
   return editorInfo.ace_doDatatableOptions = _(Datatables.doDatatableOptions).bind(context);
 };
 exports.acePostWriteDomLineHTML = function(hook_name, arg$, cb){
-  var node, children, i, element, lineText, ref$, dtAttrs, code, results$ = [];
+  var node, lineText, dtAttrs, code;
   node = arg$.node;
-  children = node.children;
-  i = 0;
-  while (i < children.length) {
-    element = children[i++];
-    if (element.className.indexOf('list') !== -1 || element.className.indexOf('tag') !== -1 || element.className.indexOf('url') !== -1) {
-      continue;
-    }
-    lineText = (ref$ = element.innerText) != null
-      ? ref$
-      : element.textContent;
-    if (lineText && lineText.indexOf('\uFFF9') !== -1) {
-      dtAttrs = typeof exports.Datatables !== 'undefined' ? exports.Datatables.attributes : null;
-      dtAttrs = dtAttrs || '';
-      code = fromEscapedJSON(lineText);
-      DatatablesRenderer.render({}, element, code, dtAttrs);
-      results$.push(exports.Datatables.attributes = null);
-    }
+  lineText = node.textContent;
+  if (lineText && lineText.indexOf('\uFFF9') !== -1) {
+    dtAttrs = typeof exports.Datatables !== 'undefined' ? exports.Datatables.attributes : null;
+    dtAttrs = dtAttrs || '';
+    code = fromEscapedJSON(lineText);
+    DatatablesRenderer.render({}, node, code, dtAttrs);
+    return exports.Datatables.attributes = null;
   }
-  return results$;
 };
 exports.eejsBlock_scripts = function(hook_name, args, cb){
   return args.content = args.content + require('ep_etherpad-lite/node/eejs/').require('ep_tables/templates/datatablesScripts.ejs');

From 474cd28825dd9bcd7df238ddb703a2df480d89d5 Mon Sep 17 00:00:00 2001
From: Audrey Tang <audreyt@audreyt.org>
Date: Tue, 6 Nov 2012 16:14:04 +0800
Subject: [PATCH 23/36] * Add a reaonsable .gitignore

---
 .gitignore | 5 +++++
 1 file changed, 5 insertions(+)
 create mode 100644 .gitignore

diff --git a/.gitignore b/.gitignore
new file mode 100644
index 0000000..052212a
--- /dev/null
+++ b/.gitignore
@@ -0,0 +1,5 @@
+**/.DS_Store
+node_modules/*
+*.ep_initialized
+*.swp
+*.swo

From 3ca80a4159703df91f05c8b0365b0eb8e15ea8ef Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 6 Nov 2012 14:41:19 +0800
Subject: [PATCH 24/36] remove duplicated method insertTblRowBelow

---
 src/js/datatables.ls    | 25 -------------------------
 static/js/datatables.js | 32 --------------------------------
 2 files changed, 57 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index b28b3c0..bfd7136 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -484,31 +484,6 @@ class Datatables
       @updateTblPropInAPool row, col, null, rep.selStart
       rep.selStart.1 = rep.selEnd.1 = @vars.OVERHEAD_LEN_PRE
       @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, ''
-    @insertTblRowBelow = (numOfRows, table) ->
-      rep = @rep
-      currLineText = (rep.lines.atIndex rep.selStart.0).text
-      payload = [[]]
-      if not numOfRows and numOfRows isnt 0
-        tblPayload = (fromEscapedJSON currLineText).payload
-        numOfRows = tblPayload.0.length
-      tblRows = new Array numOfRows
-      if not (numOfRows is 0)
-        i = 0
-        while i < tblRows.length
-          tblRows[i] = ' '
-          i++
-      payload = [tblRows]
-      if table then payload = table.payload
-      tableObj = {
-        payload: payload
-        tblId: 1
-        tblClass: '\uFFF9'
-        trClass: 'alst'
-        tdClass: 'hide-el'
-      }
-      rep.selEnd.1 = rep.selStart.1 = currLineText.length
-      @context.editorInfo.ace_doReturnKey!
-      @context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, escapedJSON tableObj
     @createDefaultTblProperties = (authors) ->
       rep = @context.rep
       defTblProp = {
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 68c5f50..0ca9560 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -648,38 +648,6 @@ Datatables = (function(){
     rep.selStart[1] = rep.selEnd[1] = this.vars.OVERHEAD_LEN_PRE;
     return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, '');
   };
-  Datatables.insertTblRowBelow = function(numOfRows, table){
-    var rep, currLineText, payload, tblPayload, tblRows, i, tableObj;
-    rep = this.rep;
-    currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-    payload = [[]];
-    if (!numOfRows && numOfRows !== 0) {
-      tblPayload = fromEscapedJSON(currLineText).payload;
-      numOfRows = tblPayload[0].length;
-    }
-    tblRows = new Array(numOfRows);
-    if (!(numOfRows === 0)) {
-      i = 0;
-      while (i < tblRows.length) {
-        tblRows[i] = ' ';
-        i++;
-      }
-    }
-    payload = [tblRows];
-    if (table) {
-      payload = table.payload;
-    }
-    tableObj = {
-      payload: payload,
-      tblId: 1,
-      tblClass: '\uFFF9',
-      trClass: 'alst',
-      tdClass: 'hide-el'
-    };
-    rep.selEnd[1] = rep.selStart[1] = currLineText.length;
-    this.context.editorInfo.ace_doReturnKey();
-    return this.context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, escapedJSON(tableObj));
-  };
   Datatables.createDefaultTblProperties = function(authors){
     var rep, defTblProp, prevLine, jsoTblProp, prevLineText, nextLine, nextLineText, jsoStrTblProp;
     rep = this.context.rep;

From c88ffb292691c96b452de80b0c5eeea6ed3e3b9f Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 6 Nov 2012 14:50:36 +0800
Subject: [PATCH 25/36] use getNewTblId to get tblId

---
 src/js/contentcollector.ls       |  3 ++-
 src/js/datatables-renderer.ls    |  2 +-
 src/js/datatables.ls             |  5 ++++-
 static/js/contentcollector.js    |  5 +++--
 static/js/datatables-renderer.js |  2 +-
 static/js/datatables.js          | 10 ++++++++--
 6 files changed, 19 insertions(+), 8 deletions(-)

diff --git a/src/js/contentcollector.ls b/src/js/contentcollector.ls
index e298171..972281e 100644
--- a/src/js/contentcollector.ls
+++ b/src/js/contentcollector.ls
@@ -7,6 +7,7 @@ exports.collectContentLineBreak = (hook, context) ->
 exports.collectContentLineText = (hook, context) ->
   n = context.node
   txt = context.text
+  tblId = 1
   if txt
     while n
       if n.tagName is 'TD'
@@ -23,7 +24,7 @@ exports.collectContentLineText = (hook, context) ->
               break
             else
               if elementName is 'bracketAndcomma'
-                txt = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}'
+                txt = '\uF134]],\uF134tblId\uF134:\uF134' + tblId +'\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}'
                 break
       n = n.parentNode
   txt
diff --git a/src/js/datatables-renderer.ls b/src/js/datatables-renderer.ls
index f8c7700..313c6a3 100644
--- a/src/js/datatables-renderer.ls
+++ b/src/js/datatables-renderer.ls
@@ -90,7 +90,7 @@ class DatatablesRenderer
             else
               htmlTbl += '<td name=\'tData\' ' + colVAlign + ' style=\'' + printViewTblTDStyles + cellStyles + lastCellBorder + ' border-left:' + tblBorderWidth + 'px solid ' + tblBorderColor + authorBorderColor + borderTop + '\' >' + tds[i] + '' + '<br value=\'tblBreak\'></td>' + delimCell
             i++
-          bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}'
+          bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF134' + tblId + '\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}'
           htmlTbl += '<td name=\'bracketAndcomma\' class=\'  hide-el overhead\'>' + bracketAndcomma + '</td>'
           htmlTbl += '</tr>'
           j++
diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index bfd7136..5f0aa94 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -134,6 +134,7 @@ class Datatables
         else if el.nodeType is 3
           el.data
       text.join ''
+    @lastTblId = 0
     @defaults= {tblProps: {
         borderWidth: '1'
         cellAttrs: []
@@ -711,7 +712,7 @@ class Datatables
       if table then payload = table.payload
       tableObj = {
         payload: payload
-        tblId: 1
+        tblId: table?tblId ? @getNewTblId!
         tblClass: '\uFFF9'
         trClass: 'alst'
         tdClass: 'hide-el'
@@ -719,6 +720,8 @@ class Datatables
       rep.selEnd.1 = rep.selStart.1 = currLineText.length
       @context.editorInfo.ace_inCallStackIfNecessary 'newline', @context.editorInfo.ace_doReturnKey
       context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, escapedJSON tableObj
+    @getNewTblId = ->
+        ++@lastTblId
     @doReturnKey = ->
       context = @context
       rep = context.rep
diff --git a/static/js/contentcollector.js b/static/js/contentcollector.js
index 044216c..ea38861 100644
--- a/static/js/contentcollector.js
+++ b/static/js/contentcollector.js
@@ -8,9 +8,10 @@ exports.collectContentLineBreak = function(hook, context){
   return breakLine;
 };
 exports.collectContentLineText = function(hook, context){
-  var n, txt, elementName;
+  var n, txt, tblId, elementName;
   n = context.node;
   txt = context.text;
+  tblId = 1;
   if (txt) {
     while (n) {
       if (n.tagName === 'TD') {
@@ -27,7 +28,7 @@ exports.collectContentLineText = function(hook, context){
               break;
             } else {
               if (elementName === 'bracketAndcomma') {
-                txt = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}';
+                txt = '\uF134]],\uF134tblId\uF134:\uF134' + tblId(+'\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}');
                 break;
               }
             }
diff --git a/static/js/datatables-renderer.js b/static/js/datatables-renderer.js
index a70dba0..1d42162 100644
--- a/static/js/datatables-renderer.js
+++ b/static/js/datatables-renderer.js
@@ -131,7 +131,7 @@ DatatablesRenderer = (function(){
           }
           i++;
         }
-        bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF1341\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}';
+        bracketAndcomma = '\uF134]],\uF134tblId\uF134:\uF134' + tblId + '\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}';
         htmlTbl += '<td name=\'bracketAndcomma\' class=\'  hide-el overhead\'>' + bracketAndcomma + '</td>';
         htmlTbl += '</tr>';
         j++;
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 0ca9560..97c43ca 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -181,6 +181,7 @@ Datatables = (function(){
     text = res$;
     return text.join('');
   };
+  Datatables.lastTblId = 0;
   Datatables.defaults = {
     tblProps: {
       borderWidth: '1',
@@ -916,7 +917,7 @@ Datatables = (function(){
     }
   };
   Datatables.insertTblRowBelow = function(numOfRows, table){
-    var context, rep, currLineText, payload, tblPayload, tblRows, i, tableObj;
+    var context, rep, currLineText, payload, tblPayload, tblRows, i, tableObj, ref$;
     context = this.context;
     rep = context.rep;
     currLineText = rep.lines.atIndex(rep.selStart[0]).text;
@@ -939,7 +940,9 @@ Datatables = (function(){
     }
     tableObj = {
       payload: payload,
-      tblId: 1,
+      tblId: (ref$ = table != null ? table.tblId : void 8) != null
+        ? ref$
+        : this.getNewTblId(),
       tblClass: '\uFFF9',
       trClass: 'alst',
       tdClass: 'hide-el'
@@ -948,6 +951,9 @@ Datatables = (function(){
     this.context.editorInfo.ace_inCallStackIfNecessary('newline', this.context.editorInfo.ace_doReturnKey);
     return context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, escapedJSON(tableObj));
   };
+  Datatables.getNewTblId = function(){
+    return ++this.lastTblId;
+  };
   Datatables.doReturnKey = function(){
     var context, rep, start, end, lastTblPropertyUsed, currLine, currLineText, func, currCarretPos, newText, jsonObj, payloadStr, error, e;
     context = this.context;

From 3c438a490e153628e7d7f5cdcfe77a65ded656b0 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 6 Nov 2012 15:56:21 +0800
Subject: [PATCH 26/36] maintain tblId across rows and use it to distinguish
 tables

---
 src/js/datatables.ls    | 32 ++++++++++++++---------
 static/js/datatables.js | 58 +++++++++++++++++++++++++++--------------
 2 files changed, 59 insertions(+), 31 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index 5f0aa94..c035862 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -34,6 +34,7 @@ exports.acePostWriteDomLineHTML = (hook_name, {node}, cb) ->
     dtAttrs = dtAttrs or ''
     code = fromEscapedJSON lineText
     DatatablesRenderer.render {}, node, code, dtAttrs
+    exports.Datatables.lastTblId >?= code.tblId
     exports.Datatables.attributes = null
 
 exports.eejsBlock_scripts = (hook_name, args, cb) ->
@@ -285,8 +286,9 @@ class Datatables
         jsoStrTblProp = JSON.stringify @createDefaultTblProperties!
         authors = {}
         i = 0
+        table = {}
         while i < rows
-          @insertTblRowBelow cols
+          @insertTblRowBelow cols, table
           if i is 0 then @performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties! else @performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties authors
           i++
         @updateAuthorAndCaretPos rep.selStart.0 - rows + 1
@@ -298,7 +300,7 @@ class Datatables
       try
         newText = ''
         currLineText = (rep.lines.atIndex rep.selStart.0).text
-        payload = (fromEscapedJSON currLineText).payload
+        {payload,tblId} = (fromEscapedJSON currLineText)
         currTdInfo = @getFocusedTdInfo payload, rep.selStart.1
         currRow = currTdInfo.row
         lastRowOffSet = 0
@@ -310,9 +312,9 @@ class Datatables
         end.1 = rep.selStart.1
         if aboveOrBelow is 'addA'
           rep.selStart.0 = rep.selEnd.0 = rep.selStart.0 - 1
-          @insertTblRowBelow payload.0.length
+          @insertTblRowBelow payload.0.length, {tblId}
         else
-          @insertTblRowBelow payload.0.length
+          @insertTblRowBelow payload.0.length, {tblId}
         @context.editorInfo.ace_performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties!
         @updateAuthorAndCaretPos rep.selStart.0
         updateEvenOddBgColor = true
@@ -540,7 +542,7 @@ class Datatables
           nextLineText = nextLine.text
           updateEvenOddBgColor = false
           if not nextLineText? or nextLineText is '' or (nextLineText.indexOf '\uFFF9') is -1
-            @insertTblRowBelow null, null
+            @insertTblRowBelow null, {tblJSONObj.tblId}
             @performDocApplyTblAttrToRow rep.selStart, @createDefaultTblProperties!
             rep.selEnd.1 = rep.selStart.1 = @vars.OVERHEAD_LEN_PRE
             updateEvenOddBgColor = true
@@ -708,15 +710,16 @@ class Datatables
         while i < tblRows.length
           tblRows[i] = ' '
           i++
-      payload = [tblRows]
-      if table then payload = table.payload
+      payload = table?payload ? [tblRows]
+      tblId = table?tblId ? @getNewTblId!
       tableObj = {
-        payload: payload
-        tblId: table?tblId ? @getNewTblId!
+        payload
+        tblId
         tblClass: '\uFFF9'
         trClass: 'alst'
         tdClass: 'hide-el'
       }
+      table?tblId = tblId
       rep.selEnd.1 = rep.selStart.1 = currLineText.length
       @context.editorInfo.ace_inCallStackIfNecessary 'newline', @context.editorInfo.ace_doReturnKey
       context.editorInfo.ace_performDocumentReplaceRange rep.selStart, rep.selEnd, escapedJSON tableObj
@@ -890,9 +893,14 @@ class Datatables
       rowBgColors
     @getTblAboveRowsFromCurFocus = (start) ->
       rep = @context.rep
-      numOfLinesAbove = 0
-      line = start.0 - 1
-      while not (((rep.lines.atIndex line).text.indexOf '\uFFF9') is -1)
+      numOfLinesAbove = -1
+      line = start.0
+      tblId = null
+      while text = rep.lines.atIndex(line).text
+        break unless text is /\uFFF9/
+        curr = fromEscapedJSON(text).tblId
+        tblId ?= curr
+        break if curr != tblId
         numOfLinesAbove++
         line--
       numOfLinesAbove
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 97c43ca..e723975 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -32,7 +32,7 @@ exports.aceInitialized = function(hook, context){
   return editorInfo.ace_doDatatableOptions = _(Datatables.doDatatableOptions).bind(context);
 };
 exports.acePostWriteDomLineHTML = function(hook_name, arg$, cb){
-  var node, lineText, dtAttrs, code;
+  var node, lineText, dtAttrs, code, ref$, ref1$;
   node = arg$.node;
   lineText = node.textContent;
   if (lineText && lineText.indexOf('\uFFF9') !== -1) {
@@ -40,6 +40,7 @@ exports.acePostWriteDomLineHTML = function(hook_name, arg$, cb){
     dtAttrs = dtAttrs || '';
     code = fromEscapedJSON(lineText);
     DatatablesRenderer.render({}, node, code, dtAttrs);
+    (ref$ = exports.Datatables).lastTblId >= (ref1$ = code.tblId) || (ref$.lastTblId = ref1$);
     return exports.Datatables.attributes = null;
   }
 };
@@ -360,8 +361,9 @@ Datatables = (function(){
       jsoStrTblProp = JSON.stringify(this.createDefaultTblProperties());
       authors = {};
       i = 0;
+      table = {};
       while (i < rows) {
-        this.insertTblRowBelow(cols);
+        this.insertTblRowBelow(cols, table);
         if (i === 0) {
           this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
         } else {
@@ -375,13 +377,13 @@ Datatables = (function(){
     return newText;
   };
   Datatables.insertTblRow = function(aboveOrBelow){
-    var func, rep, newText, currLineText, payload, currTdInfo, currRow, lastRowOffSet, start, end, updateEvenOddBgColor, e;
+    var func, rep, newText, currLineText, ref$, payload, tblId, currTdInfo, currRow, lastRowOffSet, start, end, updateEvenOddBgColor, e;
     func = 'insertTblRow()';
     rep = this.context.rep;
     try {
       newText = '';
       currLineText = rep.lines.atIndex(rep.selStart[0]).text;
-      payload = fromEscapedJSON(currLineText).payload;
+      ref$ = fromEscapedJSON(currLineText), payload = ref$.payload, tblId = ref$.tblId;
       currTdInfo = this.getFocusedTdInfo(payload, rep.selStart[1]);
       currRow = currTdInfo.row;
       lastRowOffSet = 0;
@@ -393,9 +395,13 @@ Datatables = (function(){
       end[1] = rep.selStart[1];
       if (aboveOrBelow === 'addA') {
         rep.selStart[0] = rep.selEnd[0] = rep.selStart[0] - 1;
-        this.insertTblRowBelow(payload[0].length);
+        this.insertTblRowBelow(payload[0].length, {
+          tblId: tblId
+        });
       } else {
-        this.insertTblRowBelow(payload[0].length);
+        this.insertTblRowBelow(payload[0].length, {
+          tblId: tblId
+        });
       }
       this.context.editorInfo.ace_performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
       this.updateAuthorAndCaretPos(rep.selStart[0]);
@@ -719,7 +725,9 @@ Datatables = (function(){
         nextLineText = nextLine.text;
         updateEvenOddBgColor = false;
         if (nextLineText == null || nextLineText === '' || nextLineText.indexOf('\uFFF9') === -1) {
-          this.insertTblRowBelow(null, null);
+          this.insertTblRowBelow(null, {
+            tblId: tblJSONObj.tblId
+          });
           this.performDocApplyTblAttrToRow(rep.selStart, this.createDefaultTblProperties());
           rep.selEnd[1] = rep.selStart[1] = this.vars.OVERHEAD_LEN_PRE;
           updateEvenOddBgColor = true;
@@ -917,7 +925,7 @@ Datatables = (function(){
     }
   };
   Datatables.insertTblRowBelow = function(numOfRows, table){
-    var context, rep, currLineText, payload, tblPayload, tblRows, i, tableObj, ref$;
+    var context, rep, currLineText, payload, tblPayload, tblRows, i, ref$, tblId, tableObj;
     context = this.context;
     rep = context.rep;
     currLineText = rep.lines.atIndex(rep.selStart[0]).text;
@@ -934,19 +942,22 @@ Datatables = (function(){
         i++;
       }
     }
-    payload = [tblRows];
-    if (table) {
-      payload = table.payload;
-    }
+    payload = (ref$ = table != null ? table.payload : void 8) != null
+      ? ref$
+      : [tblRows];
+    tblId = (ref$ = table != null ? table.tblId : void 8) != null
+      ? ref$
+      : this.getNewTblId();
     tableObj = {
       payload: payload,
-      tblId: (ref$ = table != null ? table.tblId : void 8) != null
-        ? ref$
-        : this.getNewTblId(),
+      tblId: tblId,
       tblClass: '\uFFF9',
       trClass: 'alst',
       tdClass: 'hide-el'
     };
+    if (table != null) {
+      table.tblId = tblId;
+    }
     rep.selEnd[1] = rep.selStart[1] = currLineText.length;
     this.context.editorInfo.ace_inCallStackIfNecessary('newline', this.context.editorInfo.ace_doReturnKey);
     return context.editorInfo.ace_performDocumentReplaceRange(rep.selStart, rep.selEnd, escapedJSON(tableObj));
@@ -1197,11 +1208,20 @@ Datatables = (function(){
     return rowBgColors;
   };
   Datatables.getTblAboveRowsFromCurFocus = function(start){
-    var rep, numOfLinesAbove, line;
+    var rep, numOfLinesAbove, line, tblId, text, curr;
     rep = this.context.rep;
-    numOfLinesAbove = 0;
-    line = start[0] - 1;
-    while (!(rep.lines.atIndex(line).text.indexOf('\uFFF9') === -1)) {
+    numOfLinesAbove = -1;
+    line = start[0];
+    tblId = null;
+    while (text = rep.lines.atIndex(line).text) {
+      if (!/\uFFF9/.test(text)) {
+        break;
+      }
+      curr = fromEscapedJSON(text).tblId;
+      tblId == null && (tblId = curr);
+      if (curr !== tblId) {
+        break;
+      }
       numOfLinesAbove++;
       line--;
     }

From 59aaa35966ef19582299b017eb2f020ef1abede8 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 6 Nov 2012 16:26:34 +0800
Subject: [PATCH 27/36] disable table options for now

---
 src/js/datatables-ui.ls    | 5 -----
 static/js/datatables-ui.js | 8 +-------
 2 files changed, 1 insertion(+), 12 deletions(-)

diff --git a/src/js/datatables-ui.ls b/src/js/datatables-ui.ls
index b5b23b1..c481465 100644
--- a/src/js/datatables-ui.ls
+++ b/src/js/datatables-ui.ls
@@ -439,11 +439,6 @@ exports.postAceInit = (hook, context) ->
           'Delete Column'
           'Delete Table'
         ]
-        [{
-          id: 'tbl_prop_menu_item'
-          text: 'Table Properties'
-          onclick: {fn: showTblPropPanel}
-        }]
       ]
       subMenus = $.tblContextMenu.getSubmenus!
       subMenus.0.setFooter matrixTable
diff --git a/static/js/datatables-ui.js b/static/js/datatables-ui.js
index 1e8bbeb..c5ed436 100644
--- a/static/js/datatables-ui.js
+++ b/static/js/datatables-ui.js
@@ -577,13 +577,7 @@ exports.postAceInit = function(hook, context){
             id: 'tbl_insert',
             itemData: ['<div id=\'select_matrix\'>0 X 0</div>']
           }
-        }], ['Insert Row Above', 'Insert Row Below', 'Insert Column Right', 'Insert Column Left'], ['Delete Row', 'Delete Column', 'Delete Table'], [{
-          id: 'tbl_prop_menu_item',
-          text: 'Table Properties',
-          onclick: {
-            fn: showTblPropPanel
-          }
-        }]
+        }], ['Insert Row Above', 'Insert Row Below', 'Insert Column Right', 'Insert Column Left'], ['Delete Row', 'Delete Column', 'Delete Table']
       ]);
       subMenus = $.tblContextMenu.getSubmenus();
       subMenus[0].setFooter(matrixTable);

From 99e5ccd2712f674713f41979eb2be2389c6933cc Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 6 Nov 2012 16:39:09 +0800
Subject: [PATCH 28/36] Fix IE: use jquery to get textContent

---
 src/js/datatables.ls    | 2 +-
 static/js/datatables.js | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index c035862..afd547f 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -28,7 +28,7 @@ exports.aceInitialized = (hook, context) ->
   editorInfo.ace_doDatatableOptions = (_ Datatables.doDatatableOptions).bind context
 
 exports.acePostWriteDomLineHTML = (hook_name, {node}, cb) ->
-  lineText = node.textContent
+  lineText = $(node)text!
   if lineText and (lineText.indexOf '\uFFF9') isnt -1
     dtAttrs = if typeof exports.Datatables isnt 'undefined' then exports.Datatables.attributes else null
     dtAttrs = dtAttrs or ''
diff --git a/static/js/datatables.js b/static/js/datatables.js
index e723975..093d12e 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -34,7 +34,7 @@ exports.aceInitialized = function(hook, context){
 exports.acePostWriteDomLineHTML = function(hook_name, arg$, cb){
   var node, lineText, dtAttrs, code, ref$, ref1$;
   node = arg$.node;
-  lineText = node.textContent;
+  lineText = $(node).text();
   if (lineText && lineText.indexOf('\uFFF9') !== -1) {
     dtAttrs = typeof exports.Datatables !== 'undefined' ? exports.Datatables.attributes : null;
     dtAttrs = dtAttrs || '';

From 978463a14baf993f59c1644544a2a79f2aed6049 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 6 Nov 2012 16:50:14 +0800
Subject: [PATCH 29/36] use interpolation

---
 src/js/contentcollector.ls    | 2 +-
 static/js/contentcollector.js | 2 +-
 2 files changed, 2 insertions(+), 2 deletions(-)

diff --git a/src/js/contentcollector.ls b/src/js/contentcollector.ls
index 972281e..c8d8b14 100644
--- a/src/js/contentcollector.ls
+++ b/src/js/contentcollector.ls
@@ -24,7 +24,7 @@ exports.collectContentLineText = (hook, context) ->
               break
             else
               if elementName is 'bracketAndcomma'
-                txt = '\uF134]],\uF134tblId\uF134:\uF134' + tblId +'\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}'
+                txt = "\uF134]],\uF134tblId\uF134:\uF134#{tblId}\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}"
                 break
       n = n.parentNode
   txt
diff --git a/static/js/contentcollector.js b/static/js/contentcollector.js
index ea38861..6f6d4c3 100644
--- a/static/js/contentcollector.js
+++ b/static/js/contentcollector.js
@@ -28,7 +28,7 @@ exports.collectContentLineText = function(hook, context){
               break;
             } else {
               if (elementName === 'bracketAndcomma') {
-                txt = '\uF134]],\uF134tblId\uF134:\uF134' + tblId(+'\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}');
+                txt = "\uF134]],\uF134tblId\uF134:\uF134" + tblId + "\uF134,\uF134tblClass\uF134:\uF134\uFFF9\uF134}";
                 break;
               }
             }

From 041ad7d0961efe23d6b3003ad67cdf5a34eb67a0 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 6 Nov 2012 16:51:08 +0800
Subject: [PATCH 30/36] wrap atIndex with try as it sometimes calls
 console.warn and breaks IE8

---
 src/js/datatables.ls    | 2 +-
 static/js/datatables.js | 6 +++++-
 2 files changed, 6 insertions(+), 2 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index afd547f..c70883c 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -167,7 +167,7 @@ class Datatables
     @context= null
     @isFocused = ->
       return false if not @context.rep.selStart or not @context.rep.selEnd
-      line = @context.rep.lines.atIndex @context.rep.selStart.0
+      line = try @context.rep.lines.atIndex @context.rep.selStart.0
       if not line then return false
       currLineText = line.text or ''
       if (currLineText.indexOf '\uFFF9') is -1 then return false
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 093d12e..496da73 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -209,7 +209,11 @@ Datatables = (function(){
     if (!this.context.rep.selStart || !this.context.rep.selEnd) {
       return false;
     }
-    line = this.context.rep.lines.atIndex(this.context.rep.selStart[0]);
+    line = (function(){
+      try {
+        return this.context.rep.lines.atIndex(this.context.rep.selStart[0]);
+      } catch (e$) {}
+    }.call(this));
     if (!line) {
       return false;
     }

From 0bd731cbe8fe5f5294a229b59190192135ad5a95 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 6 Nov 2012 16:56:17 +0800
Subject: [PATCH 31/36] IE7 compatibility

---
 src/js/datatables-renderer.ls    | 2 +-
 static/css/dataTables.css        | 3 +++
 static/js/datatables-renderer.js | 2 +-
 3 files changed, 5 insertions(+), 2 deletions(-)

diff --git a/src/js/datatables-renderer.ls b/src/js/datatables-renderer.ls
index 313c6a3..10b3b29 100644
--- a/src/js/datatables-renderer.ls
+++ b/src/js/datatables-renderer.ls
@@ -82,7 +82,7 @@ class DatatablesRenderer
               k = 0
               while k < tdText.length
                 if k < tdText.length - 1
-                  cellsWithBr += tdText[k] + '<label value=\'tblBreak\' class=\'hide-el\'>/r/n</label><label class=\'tblBreak\'></label>'
+                  cellsWithBr += tdText[k] + '<span value=\'tblBreak\' contenteditable="false" class=\'hide-el\'>/r/n</span><label class=\'tblBreak\'></label>'
                 else
                   cellsWithBr += tdText[k]
                 k++
diff --git a/static/css/dataTables.css b/static/css/dataTables.css
index 65b2e6f..0f9a41e 100644
--- a/static/css/dataTables.css
+++ b/static/css/dataTables.css
@@ -1,5 +1,8 @@
 .hide-el{
 	display:none;
+        *position: absolute;
+        *top: -10000px;
+        *display: block;
 }
 .tblBreak{
 	display:block;
diff --git a/static/js/datatables-renderer.js b/static/js/datatables-renderer.js
index 1d42162..96589a4 100644
--- a/static/js/datatables-renderer.js
+++ b/static/js/datatables-renderer.js
@@ -119,7 +119,7 @@ DatatablesRenderer = (function(){
             k = 0;
             while (k < tdText.length) {
               if (k < tdText.length - 1) {
-                cellsWithBr += tdText[k] + '<label value=\'tblBreak\' class=\'hide-el\'>/r/n</label><label class=\'tblBreak\'></label>';
+                cellsWithBr += tdText[k] + '<span value=\'tblBreak\' contenteditable="false" class=\'hide-el\'>/r/n</span><label class=\'tblBreak\'></label>';
               } else {
                 cellsWithBr += tdText[k];
               }

From 33b28bde787c4823e6aad22b7dbeb89e1f9192f7 Mon Sep 17 00:00:00 2001
From: Audrey Tang <audreyt@audreyt.org>
Date: Tue, 6 Nov 2012 17:18:53 +0800
Subject: [PATCH 32/36] * Only emit contenteditable=false for IE7

---
 src/js/datatables-renderer.ls    | 4 +++-
 static/js/datatables-renderer.js | 2 +-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/js/datatables-renderer.ls b/src/js/datatables-renderer.ls
index 10b3b29..e4684c7 100644
--- a/src/js/datatables-renderer.ls
+++ b/src/js/datatables-renderer.ls
@@ -82,7 +82,9 @@ class DatatablesRenderer
               k = 0
               while k < tdText.length
                 if k < tdText.length - 1
-                  cellsWithBr += tdText[k] + '<span value=\'tblBreak\' contenteditable="false" class=\'hide-el\'>/r/n</span><label class=\'tblBreak\'></label>'
+                  cellsWithBr += tdText[k] + "<span value='tblBreak'#{
+                    if $.browser.msie and $.browser.version <= 7 then " contenteditable='false'" else ""
+                  } class='hide-el'>/r/n</span><label class='tblBreak'></label>"
                 else
                   cellsWithBr += tdText[k]
                 k++
diff --git a/static/js/datatables-renderer.js b/static/js/datatables-renderer.js
index 96589a4..224556e 100644
--- a/static/js/datatables-renderer.js
+++ b/static/js/datatables-renderer.js
@@ -119,7 +119,7 @@ DatatablesRenderer = (function(){
             k = 0;
             while (k < tdText.length) {
               if (k < tdText.length - 1) {
-                cellsWithBr += tdText[k] + '<span value=\'tblBreak\' contenteditable="false" class=\'hide-el\'>/r/n</span><label class=\'tblBreak\'></label>';
+                cellsWithBr += tdText[k] + ("<span value='tblBreak'" + ($.browser.msie && $.browser.version <= 7 ? " contenteditable='false'" : "") + " class='hide-el'>/r/n</span><label class='tblBreak'></label>");
               } else {
                 cellsWithBr += tdText[k];
               }

From d5a5eb6f7a4bd011121bcb2be9bb9773eb6165ed Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Tue, 6 Nov 2012 17:21:16 +0800
Subject: [PATCH 33/36] make the table menu more usable

---
 src/js/datatables-ui.ls    | 3 ++-
 static/js/datatables-ui.js | 3 ++-
 2 files changed, 4 insertions(+), 2 deletions(-)

diff --git a/src/js/datatables-ui.ls b/src/js/datatables-ui.ls
index c481465..1bf3b93 100644
--- a/src/js/datatables-ui.ls
+++ b/src/js/datatables-ui.ls
@@ -417,7 +417,6 @@ exports.postAceInit = (hook, context) ->
         zindex: 500
         shadow: false
         position: 'dynamic'
-        keepopen: true
         clicktohide: true
       }
       $.tblContextMenu.addItems [
@@ -463,6 +462,7 @@ exports.postAceInit = (hook, context) ->
         ($ '#select_matrix').html xVal + ' X ' + yVal)
       ($ 'td', '#matrix_table').click ((e) ->
         context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions 'addTbl', 'addTblX' + ($ '#select_matrix').text!), 'tblOptions', true
+        $.tblContextMenu.hide!
         false)
       $.tblContextMenu.subscribe 'click', (p_sType, p_aArgs) ->
         oEvent = p_aArgs.0
@@ -492,6 +492,7 @@ exports.postAceInit = (hook, context) ->
           case 'Delete Column'
             id = 'delTblCol'
           context.ace.callWithAce ((ace) -> ace.ace_doDatatableOptions id), 'tblOptions', true
+          $.tblContextMenu.hide!
           false
     if not init
       $.alignMenu $.tblContextMenu, 'tbl-menu'
diff --git a/static/js/datatables-ui.js b/static/js/datatables-ui.js
index c5ed436..0d13380 100644
--- a/static/js/datatables-ui.js
+++ b/static/js/datatables-ui.js
@@ -567,7 +567,6 @@ exports.postAceInit = function(hook, context){
         zindex: 500,
         shadow: false,
         position: 'dynamic',
-        keepopen: true,
         clicktohide: true
       });
       $.tblContextMenu.addItems([
@@ -622,6 +621,7 @@ exports.postAceInit = function(hook, context){
         context.ace.callWithAce(function(ace){
           return ace.ace_doDatatableOptions('addTbl', 'addTblX' + $('#select_matrix').text());
         }, 'tblOptions', true);
+        $.tblContextMenu.hide();
         return false;
       });
       $.tblContextMenu.subscribe('click', function(p_sType, p_aArgs){
@@ -666,6 +666,7 @@ exports.postAceInit = function(hook, context){
           context.ace.callWithAce(function(ace){
             return ace.ace_doDatatableOptions(id);
           }, 'tblOptions', true);
+          $.tblContextMenu.hide();
           return false;
         }
       });

From 9ab35b798a32cd7a025f45c7914a40e23efb416c Mon Sep 17 00:00:00 2001
From: Audrey Tang <audreyt@audreyt.org>
Date: Thu, 15 Nov 2012 21:56:14 +0800
Subject: [PATCH 34/36] * Point .js to https-hosted github

---
 src/js/datatables-ui.ls         |  4 ++--
 static/js/datatables-ui.js      |  4 ++--
 templates/datatablesScripts.ejs | 18 +++++++++---------
 3 files changed, 13 insertions(+), 13 deletions(-)

diff --git a/src/js/datatables-ui.ls b/src/js/datatables-ui.ls
index 1bf3b93..dbb64c2 100644
--- a/src/js/datatables-ui.ls
+++ b/src/js/datatables-ui.ls
@@ -27,8 +27,8 @@ exports.postAceInit = (hook, context) ->
           showhexsummary: false
           showhexcontrols: true
           images: {
-            PICKER_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/picker_thumb.png'
-            HUE_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/hue_thumb.png'
+            PICKER_THUMB: 'https://raw.github.com/yui/yui2/master/build/colorpicker/assets/picker_thumb.png'
+            HUE_THUMB: 'https://raw.github.com/yui/yui2/master/build/colorpicker/assets/hue_thumb.png'
           }
         }
         $.oColorPicker.on 'rgbChange', colorPickerButtonClick
diff --git a/static/js/datatables-ui.js b/static/js/datatables-ui.js
index 0d13380..ede09eb 100644
--- a/static/js/datatables-ui.js
+++ b/static/js/datatables-ui.js
@@ -31,8 +31,8 @@ exports.postAceInit = function(hook, context){
           showhexsummary: false,
           showhexcontrols: true,
           images: {
-            PICKER_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/picker_thumb.png',
-            HUE_THUMB: 'http://yui.yahooapis.com/2.9.0/build/colorpicker/assets/hue_thumb.png'
+            PICKER_THUMB: 'https://raw.github.com/yui/yui2/master/build/colorpicker/assets/picker_thumb.png',
+            HUE_THUMB: 'https://raw.github.com/yui/yui2/master/build/colorpicker/assets/hue_thumb.png'
           }
         });
         $.oColorPicker.on('rgbChange', colorPickerButtonClick);
diff --git a/templates/datatablesScripts.ejs b/templates/datatablesScripts.ejs
index e1516f6..b11e0fc 100644
--- a/templates/datatablesScripts.ejs
+++ b/templates/datatablesScripts.ejs
@@ -6,12 +6,12 @@
 </script>
 
 
-<script  src="http://yui.yahooapis.com/2.9.0/build/yahoo-dom-event/yahoo-dom-event.js"></script>
-<script  src="http://yui.yahooapis.com/2.9.0/build/dragdrop/dragdrop-min.js"></script>
-<script  src="http://yui.yahooapis.com/2.9.0/build/slider/slider-min.js"></script>
-<script  src="http://yui.yahooapis.com/2.9.0/build/element/element-min.js"></script>
-<script  src="http://yui.yahooapis.com/2.9.0/build/colorpicker/colorpicker-min.js"></script>
-<script  src="http://yui.yahooapis.com/2.9.0/build/container/container_core-min.js"></script>
-<script  src="http://yui.yahooapis.com/2.9.0/build/menu/menu-min.js"></script>
-<script  src="http://yui.yahooapis.com/2.9.0/build/button/button-min.js"></script>
-<script  src="http://yui.yahooapis.com/2.9.0/build/container/container-min.js"></script> 
+<script  src="https://raw.github.com/yui/yui2/master/build/yahoo-dom-event/yahoo-dom-event.js"></script>
+<script  src="https://raw.github.com/yui/yui2/master/build/dragdrop/dragdrop-min.js"></script>
+<script  src="https://raw.github.com/yui/yui2/master/build/slider/slider-min.js"></script>
+<script  src="https://raw.github.com/yui/yui2/master/build/element/element-min.js"></script>
+<script  src="https://raw.github.com/yui/yui2/master/build/colorpicker/colorpicker-min.js"></script>
+<script  src="https://raw.github.com/yui/yui2/master/build/container/container_core-min.js"></script>
+<script  src="https://raw.github.com/yui/yui2/master/build/menu/menu-min.js"></script>
+<script  src="https://raw.github.com/yui/yui2/master/build/button/button-min.js"></script>
+<script  src="https://raw.github.com/yui/yui2/master/build/container/container-min.js"></script> 

From 282f7d41815a3b8d887cf46c3d2620689ebb4180 Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Fri, 16 Nov 2012 15:11:56 +0800
Subject: [PATCH 35/36] fix deleting the sole character in a column

---
 src/js/datatables.ls | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index c70883c..fefea27 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -772,10 +772,11 @@ class Datatables
         if (currLineText.substring currCarretPos - 1, currCarretPos + 2) is '\uF134,\uF134'
           return false
         else
-          if (currLineText.substring currCarretPos - 2, currCarretPos + 1) is '\uF134,\uF134' then return false
+          if (currLineText.substring currCarretPos - 2, currCarretPos + 1) is '\uF134,\uF134'
+            return false
         switch keyCode
         case @vars.JS_KEY_CODE_BS
-          isDeleteAccepted = true if cellEntryLen > 1 and cellEntryLen > currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID
+          isDeleteAccepted = true if cellEntryLen > 0 and cellEntryLen > currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID
         case @vars.JS_KEY_CODE_DEL
           return false # still buggy and can corrupt table structure
           isDeleteAccepted = true if cellEntryLen > 0 and currTdInfo.leftOverTdTxtLen - @vars.OVERHEAD_LEN_MID > 0

From f8a65a3365259b2e4ca1a34826c6cc94bf4bfb6a Mon Sep 17 00:00:00 2001
From: Chia-liang Kao <clkao@clkao.org>
Date: Fri, 16 Nov 2012 16:30:14 +0800
Subject: [PATCH 36/36] fix escapedJSON

---
 src/js/datatables.ls    | 2 +-
 static/js/datatables.js | 4 ++--
 2 files changed, 3 insertions(+), 3 deletions(-)

diff --git a/src/js/datatables.ls b/src/js/datatables.ls
index fefea27..6d44e4b 100644
--- a/src/js/datatables.ls
+++ b/src/js/datatables.ls
@@ -10,7 +10,7 @@ escapedJSON = ->
         if _1
           String.fromCharCode parseInt _1, 16
         else
-          "\\"+_1.charCodeAt(0)+\;
+          "\\"+_2.charCodeAt(0)+\;
     .replace /"/g        '\uF134'
     .replace /\\(\d+);/g (_, _1) -> "\\"+String.fromCharCode(_1)
   #console.log ret
diff --git a/static/js/datatables.js b/static/js/datatables.js
index 496da73..767c9f7 100644
--- a/static/js/datatables.js
+++ b/static/js/datatables.js
@@ -14,7 +14,7 @@ escapedJSON = function(it){
     if (_1) {
       return String.fromCharCode(parseInt(_1, 16));
     } else {
-      return "\\" + _1.charCodeAt(0) + ';';
+      return "\\" + _2.charCodeAt(0) + ';';
     }
   }).replace(/"/g, '\uF134').replace(/\\(\d+);/g, function(_, _1){
     return "\\" + String.fromCharCode(_1);
@@ -1040,7 +1040,7 @@ Datatables = (function(){
       }
       switch (keyCode) {
       case this.vars.JS_KEY_CODE_BS:
-        if (cellEntryLen > 1 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
+        if (cellEntryLen > 0 && cellEntryLen > currTdInfo.leftOverTdTxtLen - this.vars.OVERHEAD_LEN_MID) {
           isDeleteAccepted = true;
         }
         break;