summaryrefslogtreecommitdiff
path: root/static-files/journal/wymeditor/plugins
diff options
context:
space:
mode:
Diffstat (limited to 'static-files/journal/wymeditor/plugins')
-rw-r--r--static-files/journal/wymeditor/plugins/fullscreen/icon_fullscreen.gifbin0 -> 509 bytes
-rw-r--r--static-files/journal/wymeditor/plugins/fullscreen/jquery.wymeditor.fullscreen.js126
-rw-r--r--static-files/journal/wymeditor/plugins/list/jquery.wymeditor.list.js44
-rw-r--r--static-files/journal/wymeditor/plugins/rdfa/jquery.wymeditor.rdfa.js192
-rw-r--r--static-files/journal/wymeditor/plugins/table/jquery.wymeditor.table.js761
-rw-r--r--static-files/journal/wymeditor/plugins/table/table_delete_column.pngbin0 -> 744 bytes
-rw-r--r--static-files/journal/wymeditor/plugins/table/table_delete_row.pngbin0 -> 683 bytes
-rw-r--r--static-files/journal/wymeditor/plugins/table/table_insert_column.pngbin0 -> 720 bytes
-rw-r--r--static-files/journal/wymeditor/plugins/table/table_insert_row.pngbin0 -> 667 bytes
-rw-r--r--static-files/journal/wymeditor/plugins/table/table_join_row.pngbin0 -> 685 bytes
10 files changed, 1123 insertions, 0 deletions
diff --git a/static-files/journal/wymeditor/plugins/fullscreen/icon_fullscreen.gif b/static-files/journal/wymeditor/plugins/fullscreen/icon_fullscreen.gif
new file mode 100644
index 0000000..d2a8b0a
--- /dev/null
+++ b/static-files/journal/wymeditor/plugins/fullscreen/icon_fullscreen.gif
Binary files differ
diff --git a/static-files/journal/wymeditor/plugins/fullscreen/jquery.wymeditor.fullscreen.js b/static-files/journal/wymeditor/plugins/fullscreen/jquery.wymeditor.fullscreen.js
new file mode 100644
index 0000000..faaa693
--- /dev/null
+++ b/static-files/journal/wymeditor/plugins/fullscreen/jquery.wymeditor.fullscreen.js
@@ -0,0 +1,126 @@
+/*
+ * WYMeditor : what you see is What You Mean web-based editor
+ * Copyright (c) 2005 - 2009 Jean-Francois Hovinne, http://www.wymeditor.org/
+ * Dual licensed under the MIT (MIT-license.txt)
+ * and GPL (GPL-license.txt) licenses.
+ *
+ * For further information visit:
+ * http://www.wymeditor.org/
+ *
+ * File Name:
+ * jquery.wymeditor.fullscreen.js
+ * Fullscreen plugin for WYMeditor
+ *
+ * File Authors:
+ * Luis Santos (luis.santos a-t openquest dotpt)
+ * Jonatan Lundin (jonatan.lundin a-t gmail dotcom)
+ * Gerd Riesselmann (gerd a-t gyro-php dot org) : Fixed issue with new skin layout
+ * Philipp Cordes (pc a-t irgendware dotnet)
+ */
+
+//Extend WYMeditor
+WYMeditor.editor.prototype.fullscreen = function() {
+ var wym = this,
+ $box = jQuery(wym._box),
+ $iframe = jQuery(wym._iframe),
+ $overlay = null,
+ $window = jQuery(window),
+
+ editorMargin = 15; // Margin from window (without padding)
+
+
+ //construct the button's html
+ var html = '' +
+ "<li class='wym_tools_fullscreen'>" +
+ "<a name='Fullscreen' href='#' " +
+ "title='Fullscreen' " +
+ "style='background-image: url(" +
+ wym._options.basePath +
+ "plugins/fullscreen/icon_fullscreen.gif)'>" +
+ "Fullscreen" +
+ "</a>" +
+ "</li>";
+ //add the button to the tools box
+ $box.find(wym._options.toolsSelector + wym._options.toolsListSelector)
+ .append(html);
+
+ function resize () {
+ // Calculate margins
+ var uiHeight = $box.outerHeight(true) - $iframe.outerHeight(true);
+ var editorPadding = $box.outerWidth() - $box.width();
+
+ // Calculate heights
+ var screenHeight = $window.height();
+ var iframeHeight = (screenHeight - uiHeight - (editorMargin * 2)) + 'px';
+
+ // Calculate witdths
+ var screenWidth = $window.width();
+ var boxWidth = (screenWidth - editorPadding - (editorMargin * 2)) + 'px';
+
+ $box.css('width', boxWidth);
+ $iframe.css('height', iframeHeight);
+ $overlay.css({
+ 'height': screenHeight + 'px',
+ 'width': screenWidth + 'px'
+ });
+ }
+
+ //handle click event
+ $box.find('li.wym_tools_fullscreen a').click(function() {
+ if ($box.css('position') != 'fixed') {
+ // Store previous inline styles
+ $box.data('wym-inline-css', $box.attr('style'));
+ $iframe.data('wym-inline-css', $iframe.attr('style'));
+
+ // Create overlay
+ $overlay = jQuery('<div id="wym-fullscreen-overlay"></div>')
+ .appendTo('body').css({
+ 'position': 'fixed',
+ 'background-color': 'rgb(0, 0, 0)',
+ 'opacity': '0.75',
+ 'z-index': '98',
+ 'top': '0px',
+ 'left': '0px'
+ });
+
+ // Possition the editor
+ $box.css({
+ 'position': 'fixed',
+ 'z-index': '99',
+ 'top': editorMargin + 'px',
+ 'left': editorMargin + 'px'
+ });
+
+ // Bind event listeners
+ $window.bind('resize', resize);
+ $box.find('li.wym_tools_html a').bind('click', resize);
+
+ // Force resize
+ resize();
+ } else {
+ // Unbind event listeners
+ $window.unbind('resize', resize);
+ $box.find('li.wym_tools_html a').unbind('click', resize);
+
+ // Remove inline styles
+ $box.css({
+ 'position': 'static',
+ 'z-index': '',
+ 'width': '',
+ 'top': '',
+ 'left': ''
+ });
+ $iframe.css('height', '');
+
+ // Remove overlay
+ $overlay.remove();
+ $overlay = null;
+
+ // Retore previous inline styles
+ $box.attr('style', $box.data('wym-inline-css'));
+ $iframe.attr('style', $iframe.data('wym-inline-css'));
+ }
+
+ return false;
+ });
+};
diff --git a/static-files/journal/wymeditor/plugins/list/jquery.wymeditor.list.js b/static-files/journal/wymeditor/plugins/list/jquery.wymeditor.list.js
new file mode 100644
index 0000000..b009e25
--- /dev/null
+++ b/static-files/journal/wymeditor/plugins/list/jquery.wymeditor.list.js
@@ -0,0 +1,44 @@
+/**
+ * Copyright (c) 2011 PolicyStat LLC.
+ * MIT licensed (MIT-license.txt)
+ *
+ * This plugin adds the ability to use tab and shift+tab to indent/outdent
+ * lists, mimicking a user's expected behavior when inside an editor.
+ *
+ * @author Wes Winham (winhamwr@gmail.com)
+ */
+
+function ListPlugin(options, wym) {
+ var listPlugin = this;
+ ListPlugin._options = jQuery.extend({}, options);
+ listPlugin._wym = wym;
+
+ listPlugin.init();
+}
+
+ListPlugin.prototype.init = function() {
+ var listPlugin = this;
+ listPlugin._wym.listPlugin = listPlugin;
+
+ listPlugin.bindEvents();
+};
+
+ListPlugin.prototype.bindEvents = function() {
+ var listPlugin = this,
+ wym = listPlugin._wym;
+
+ wym.keyboard.combokeys.bind(
+ "tab",
+ function () {
+ wym.indent();
+ return false;
+ }
+ );
+ wym.keyboard.combokeys.bind(
+ "shift+tab",
+ function () {
+ wym.outdent();
+ return false;
+ }
+ );
+};
diff --git a/static-files/journal/wymeditor/plugins/rdfa/jquery.wymeditor.rdfa.js b/static-files/journal/wymeditor/plugins/rdfa/jquery.wymeditor.rdfa.js
new file mode 100644
index 0000000..2323440
--- /dev/null
+++ b/static-files/journal/wymeditor/plugins/rdfa/jquery.wymeditor.rdfa.js
@@ -0,0 +1,192 @@
+/*
+ * WYMeditor : what you see is What You Mean web-based editor
+ * Copyright (c) 2005 - 2011 Jean-Francois Hovinne, http://www.wymeditor.org/
+ * Dual licensed under the MIT (MIT-license.txt)
+ * and GPL (GPL-license.txt) licenses.
+ *
+ * For further information visit:
+ * http://www.wymeditor.org/
+ *
+ * File Name:
+ * jquery.wymeditor.rdfa.js
+ * RDFa plugin for WYMeditor
+ *
+ * File Authors:
+ * Jean-Francois Hovinne (@jfhovinne)
+ */
+
+//Extend WYMeditor
+WYMeditor.editor.prototype.rdfa = function (options) {
+ var wym = this,
+ rdfa = new WYMeditor.RDFa(options, wym);
+ return rdfa;
+};
+
+//RDFa constructor
+WYMeditor.RDFa = function (options, wym) {
+ var rdfa = this;
+ options = jQuery.extend({
+ setStdNameSpaces: true,
+ extendXHTMLParser: true,
+ buttons: {}
+ }, options);
+
+ rdfa._options = options;
+ rdfa._wym = wym;
+ rdfa.init();
+};
+
+//RDFa plugin init
+WYMeditor.RDFa.prototype.init = function () {
+ var rdfa = this;
+ if (rdfa._options.setStdNameSpaces) {
+ rdfa.setStdNameSpaces();
+ }
+ if (rdfa._options.extendXHTMLParser) {
+ rdfa.extendXHTMLParser();
+ }
+ rdfa.setButtons();
+};
+
+//Adding the namespaces to the document
+WYMeditor.RDFa.prototype.setStdNameSpaces = function () {
+ var rdfa = this;
+ rdfa.addNameSpace('xmlns', 'http://www.w3.org/1999/xhtml');
+ rdfa.addNameSpace('version', 'XHTML+RDFa 1.0');
+};
+
+WYMeditor.RDFa.prototype.addNameSpace = function (attr, value) {
+ var rdfa = this;
+ jQuery('html', rdfa._wym._doc)
+ .attr(attr, value);
+};
+
+WYMeditor.RDFa.prototype.extendXHTMLParser = function () {
+ var rdfa = this;
+ rdfa.extendAttributes();
+ rdfa.setStdVocabularies();
+ rdfa.extendLinkAttributes();
+};
+
+WYMeditor.RDFa.prototype.extendAttributes = function () {
+ //Add the RDFa attributes
+ WYMeditor.XhtmlValidator._attributes.core.attributes.push(
+ 'rel',
+ 'rev',
+ 'content',
+ 'href',
+ 'src',
+ 'about',
+ 'property',
+ 'resource',
+ 'datatype',
+ 'typeof'
+ );
+};
+
+WYMeditor.RDFa.prototype.setStdVocabularies = function () {
+ var rdfa = this;
+ //Add the 'standard' vocabularies
+ vocabularies = [
+ 'xmlns:biblio',
+ 'xmlns:cc',
+ 'xmlns:dbp',
+ 'xmlns:dbr',
+ 'xmlns:dc',
+ 'xmlns:ex',
+ 'xmlns:foaf',
+ 'xmlns:rdf',
+ 'xmlns:rdfs',
+ 'xmlns:taxo',
+ 'xmlns:xhv',
+ 'xmlns:xsd'
+ ];
+ jQuery.each(vocabularies, function (index, vocabulary) {
+ rdfa.addVocabulary(vocabulary);
+ });
+};
+
+WYMeditor.RDFa.prototype.addVocabulary = function (vocabulary) {
+ WYMeditor.XhtmlValidator._attributes.core.attributes.push(vocabulary);
+};
+
+WYMeditor.RDFa.prototype.extendLinkAttributes = function () {
+ //Overwrite the <a> attributes 'rel' and 'rev'
+ WYMeditor.XhtmlValidator._tags.a = {
+ "attributes": {
+ "0": "charset",
+ "1": "coords",
+ "2": "href",
+ "3": "hreflang",
+ "4": "name",
+ "5": "rel",
+ "6": "rev",
+ "shape": /^(rect|rectangle|circ|circle|poly|polygon)$/,
+ "7": "type"
+ }
+ };
+};
+
+WYMeditor.RDFa.prototype.setButtons = function () {
+ var rdfa = this,
+ list = jQuery(rdfa._wym._box).find('div.wym_classes ul');
+ jQuery.each(rdfa._options.buttons, function (index, button) {
+ list
+ .append('<li></li>')
+ .children(':last')
+ .append('<a></a>')
+ .children(':last')
+ .attr('href', '#')
+ .text(button.title)
+ .bind('click',
+ {
+ instance: rdfa._wym,
+ button: button,
+ ns: button.ns,
+ attr: button.attr,
+ value: button.value
+ },
+ rdfa.clickButtonHandler);
+ });
+};
+
+WYMeditor.RDFa.prototype.clickButtonHandler = function (evt) {
+ var wym = evt.data.instance,
+ selected = wym.selectedContainer();
+
+ //the attribute already exists, remove it
+ if (typeof jQuery(selected).attr(evt.data.attr) !== 'undefined' &&
+ jQuery(selected).attr(evt.data.attr) !== '') {
+ WYMeditor.console.log(
+ 'attribute already exists, remove it:',
+ evt.data.attr,
+ jQuery(selected).attr(evt.data.attr)
+ );
+ jQuery(selected)
+ .removeAttr(evt.data.attr)
+ .removeClass(evt.data.ns)
+ .removeClass(evt.data.attr)
+ .removeClass(evt.data.value);
+
+ //else, add it
+ } else {
+ WYMeditor.console.log('attribute does not exist, add it:', evt.data.attr, evt.data.value);
+ if (evt.data.value) { //value available
+ jQuery(selected)
+ .attr(evt.data.attr, evt.data.ns + ':' + evt.data.value)
+ .addClass(evt.data.ns)
+ .addClass(evt.data.attr)
+ .addClass(evt.data.value);
+ } else { //value not available
+ evt.data.value = prompt('Value', '');
+ if (evt.data.value !== null) {
+ jQuery(selected)
+ .attr(evt.data.attr, evt.data.value)
+ .addClass(evt.data.ns)
+ .addClass(evt.data.attr)
+ .addClass(evt.data.value);
+ }
+ }
+ }
+ return false;
+};
diff --git a/static-files/journal/wymeditor/plugins/table/jquery.wymeditor.table.js b/static-files/journal/wymeditor/plugins/table/jquery.wymeditor.table.js
new file mode 100644
index 0000000..d258cb5
--- /dev/null
+++ b/static-files/journal/wymeditor/plugins/table/jquery.wymeditor.table.js
@@ -0,0 +1,761 @@
+/* global rangy */
+"use strict";
+
+// Fugue icons by Yusuke Kamiyamane http://p.yusukekamiyamane.com/
+// and licensed under Creative Commons Attribution
+
+/**
+ * A Table editing plugin that gives the user ability to add and remove
+ * rows and columns as well as merge rows and columns.
+ *
+ * @param options A configuration object.
+ * @param wym The WYMeditor instance to which the TableEditor should attach.
+ * @class
+ */
+function TableEditor(options, wym) {
+ var tableEditor = this;
+ options = jQuery.extend({
+ sMergeRowButtonHtml: String() +
+ '<li class="wym_tools_merge_row">' +
+ '<a name="merge_row" href="#" title="Merge Cells" ' +
+ 'style="background-image: ' +
+ "url('" + wym._options.basePath +
+ "plugins/table/table_join_row.png')" + '">' +
+ 'Merge Table Row' +
+ '</a>' +
+ '</li>',
+
+ sMergeRowButtonSelector: "li.wym_tools_merge_row a",
+
+ sAddRowButtonHtml: String() +
+ "<li class='wym_tools_add_row'>" +
+ "<a name='add_row' href='#' " +
+ "title='Add Row' " +
+ "style='background-image:" +
+ " url(" + wym._options.basePath +
+ "plugins/table/table_insert_row.png)'>" +
+ "Add Table Row" +
+ "</a>" +
+ "</li>",
+ sAddRowButtonSelector: "li.wym_tools_add_row a",
+
+ sRemoveRowButtonHtml: String() +
+ "<li class='wym_tools_remove_row'>" +
+ "<a name='remove_row' href='#' " +
+ "title='Remove Row' " +
+ "style='background-image: " +
+ "url(" + wym._options.basePath +
+ "plugins/table/table_delete_row.png)'>" +
+ "Remove Table Row" +
+ "</a>" +
+ "</li>",
+ sRemoveRowButtonSelector: "li.wym_tools_remove_row a",
+
+ sAddColumnButtonHtml: String() +
+ "<li class='wym_tools_add_column'>" +
+ "<a name='add_column' href='#' " +
+ "title='Add Column' " +
+ "style='background-image: " +
+ "url(" + wym._options.basePath +
+ "plugins/table/table_insert_column.png)'>" +
+ "Add Table Column" +
+ "</a>" +
+ "</li>",
+ sAddColumnButtonSelector: "li.wym_tools_add_column a",
+
+ sRemoveColumnButtonHtml: String() +
+ "<li class='wym_tools_remove_column'>" +
+ "<a name='remove_column' href='#' " +
+ "title='Remove Column' " +
+ "style='background-image: " +
+ "url(" + wym._options.basePath +
+ "plugins/table/table_delete_column.png)'>" +
+ "Remove Table Column" +
+ "</a>" +
+ "</li>",
+ sRemoveColumnButtonSelector: "li.wym_tools_remove_column a",
+
+ enableCellTabbing: true
+
+ }, options);
+
+ tableEditor._options = options;
+ tableEditor._wym = wym;
+
+ tableEditor.init();
+}
+
+/**
+ * Construct and return a table objects using the given options object.
+ *
+ * @param options The configuration object.
+ */
+WYMeditor.editor.prototype.table = function (options) {
+ var wym = this,
+ tableEditor = new TableEditor(options, wym);
+ wym.tableEditor = tableEditor;
+
+ return tableEditor;
+};
+
+/**
+ * Initialize the TableEditor object by adding appropriate toolbar buttons and
+ * binding any required event listeners.
+ */
+TableEditor.prototype.init = function () {
+ var tableEditor = this,
+ wym = tableEditor._wym,
+ // Add the tool panel buttons
+ tools = jQuery(wym._box).find(
+ wym._options.toolsSelector + wym._options.toolsListSelector
+ );
+
+ tools.append(tableEditor._options.sMergeRowButtonHtml);
+ tools.append(tableEditor._options.sAddRowButtonHtml);
+ tools.append(tableEditor._options.sRemoveRowButtonHtml);
+ tools.append(tableEditor._options.sAddColumnButtonHtml);
+ tools.append(tableEditor._options.sRemoveColumnButtonHtml);
+
+ tableEditor.bindEvents();
+ rangy.init();
+};
+
+/**
+ * Bind all required event listeners, including button listeners and support
+ * for tabbing through table cells if enableCellTabbing is true.
+ */
+TableEditor.prototype.bindEvents = function () {
+ var tableEditor = this,
+ wym = tableEditor._wym;
+
+ // Handle tool button click
+ jQuery(wym._box).find(
+ tableEditor._options.sMergeRowButtonSelector
+ ).click(function () {
+ tableEditor.mergeRow();
+ return false;
+ });
+ jQuery(wym._box).find(
+ tableEditor._options.sAddRowButtonSelector
+ ).click(function () {
+ return tableEditor.addRow(wym.selectedContainer());
+ });
+ jQuery(wym._box).find(
+ tableEditor._options.sRemoveRowButtonSelector
+ ).click(function () {
+ return tableEditor.removeRow(wym.selectedContainer());
+ });
+ jQuery(wym._box).find(
+ tableEditor._options.sAddColumnButtonSelector
+ ).click(function () {
+ return tableEditor.addColumn(wym.selectedContainer());
+ });
+ jQuery(wym._box).find(
+ tableEditor._options.sRemoveColumnButtonSelector
+ ).click(function () {
+ return tableEditor.removeColumn(wym.selectedContainer());
+ });
+
+ // Handle tab clicks
+ if (tableEditor._options.enableCellTabbing) {
+ jQuery(wym._doc).bind('keydown', tableEditor.keyDown);
+ }
+};
+
+/**
+ * Get the number of columns in a given tr element, accounting for colspan and
+ * rowspan. This function assumes that the table structure is valid, and will
+ * return incorrect results for uneven tables.
+ *
+ * @param tr The <tr> node whose number of columns we need to count.
+ *
+ * @returns {Number} The number of columns in the given tr, accounting for
+ * colspan and rowspan.
+ */
+TableEditor.prototype.getNumColumns = function (tr) {
+ var tableEditor = this,
+ wym = tableEditor._wym,
+ numColumns = 0,
+ table,
+ firstTr;
+
+ table = wym.findUp(tr, 'table');
+ firstTr = jQuery(table).find('tr:eq(0)');
+
+ // Count the tds and ths in the FIRST ROW of this table, accounting for
+ // colspan. We count the first td because it won't have any rowspan's
+ // before it to complicate things
+ jQuery(firstTr).children('td,th').each(function (index, elmnt) {
+ numColumns += TableEditor.GET_COLSPAN_PROP(elmnt);
+ });
+
+ return numColumns;
+};
+
+/**
+ TableEditor.GET_COLSPAN_PROP
+ ============================
+
+ Get the integer value of the inferred colspan property on the given cell in
+ a cross-browser compatible way that's also compatible across jquery
+ versions.
+
+ jquery 1.6 changed the way .attr works, which affected certain browsers
+ differently with regard to colspan and rowspan for cells that didn't
+ explicitly have that attribute set.
+*/
+TableEditor.GET_COLSPAN_PROP = function (cell) {
+ var colspan = jQuery(cell).attr('colspan');
+ if (typeof colspan === 'undefined') {
+ colspan = 1;
+ }
+ return parseInt(colspan, 10);
+};
+
+/**
+ TableEditor.GET_ROWSPAN_PROP
+ ============================
+
+ Get the integer value of the inferred rowspan property on the given cell in
+ a cross-browser compatible way that's also compatible across jquery
+ versions.
+
+ See GET_COLSPAN_PROP for details
+*/
+TableEditor.GET_ROWSPAN_PROP = function (cell) {
+ var rowspan = jQuery(cell).attr('rowspan');
+ if (typeof rowspan === 'undefined') {
+ rowspan = 1;
+ }
+ return parseInt(rowspan, 10);
+};
+/**
+ * Get the X grid index of the given td or th table cell (0-indexed). This
+ * takes in to account all colspans and rowspans.
+ *
+ * @param cell The td or th node whose X index we're returning.
+ */
+TableEditor.prototype.getCellXIndex = function (cell) {
+ var tableEditor = this,
+ i,
+ parentTr,
+ baseRowColumns,
+ rowColCount,
+ missingCells,
+ rowspanIndexes,
+ checkTr,
+ rowOffset,
+ trChildren,
+ elmnt,
+ colspan,
+ indexCounter,
+ cellIndex;
+ parentTr = jQuery(cell).parent('tr')[0];
+
+ baseRowColumns = tableEditor.getNumColumns(parentTr);
+
+ // Figure out how many explicit cells are missing which is how many
+ // rowspans we're affected by
+ rowColCount = 0;
+ jQuery(parentTr).children('td,th').each(function (index, elmnt) {
+ rowColCount += TableEditor.GET_COLSPAN_PROP(elmnt);
+ });
+
+ missingCells = baseRowColumns - rowColCount;
+ rowspanIndexes = [];
+ checkTr = parentTr;
+ rowOffset = 1;
+
+ // If this cell is affected by a rowspan from farther up the table,
+ // we need to take in to account any possible colspan attributes on that
+ // cell. Store the real X index of the cells to the left of our cell to use
+ // in the colspan calculation.
+ while (missingCells > 0) {
+ checkTr = jQuery(checkTr).prev('tr');
+ rowOffset += 1;
+ trChildren = jQuery(checkTr).children('td,th');
+ for (i = 0; i < trChildren.length; i++) {
+ elmnt = trChildren[i];
+ if (TableEditor.GET_ROWSPAN_PROP(elmnt) >= rowOffset) {
+ // Actually affects our source row
+ missingCells -= 1;
+ colspan = TableEditor.GET_COLSPAN_PROP(elmnt);
+ rowspanIndexes[tableEditor.getCellXIndex(elmnt)] = colspan;
+ }
+ }
+ }
+
+ indexCounter = 0;
+ cellIndex = null;
+ // Taking in to account the real X indexes of all of the columns to the
+ // left of this cell, determine the real X index.
+ jQuery(parentTr).children('td,th').each(function (index, elmnt) {
+ if (cellIndex !== null) {
+ // We've already iterated to the cell we're checking
+ return;
+ }
+ // Account for an inferred colspan created by a rowspan from above
+ while (typeof rowspanIndexes[indexCounter] !== 'undefined') {
+ indexCounter += parseInt(rowspanIndexes[indexCounter], 10);
+ }
+ if (elmnt === cell) {
+ // We're at our cell, no need to keep moving to the right.
+ // Signal this by setting the cellIndex
+ cellIndex = indexCounter;
+ return;
+ }
+ // Account for an explicit colspan on this cell
+ indexCounter += TableEditor.GET_COLSPAN_PROP(elmnt);
+ });
+
+ if (cellIndex === null) {
+ // Somehow, we never found the cell when iterating over its row.
+ throw "Cell index not found";
+ }
+ return cellIndex;
+};
+
+/**
+ * Get the number of columns represented by the given array of contiguous cell
+ * (td/th) nodes.
+ * Accounts for colspan and rowspan attributes.
+ *
+ * @param cells An array of td/th nodes whose total column span we're checking.
+ *
+ * @return {Number} The number of columns represented by the "cells"
+ */
+TableEditor.prototype.getTotalColumns = function (cells) {
+ var tableEditor = this,
+ rootTr = tableEditor.getCommonParentTr(cells),
+ baseRowColumns,
+ colspanCount,
+ rowColCount,
+ lastCell,
+ firstCell;
+
+ if (rootTr === null) {
+ // Non-contiguous columns
+ throw "getTotalColumns only allowed for contiguous cells";
+ }
+
+ baseRowColumns = tableEditor.getNumColumns(rootTr);
+
+ // Count the number of simple columns, not accounting for rowspans
+ colspanCount = 0;
+ jQuery(cells).each(function (index, elmnt) {
+ colspanCount += TableEditor.GET_COLSPAN_PROP(elmnt);
+ });
+
+ // Determine if we're affected by rowspans. If the number of simple columns
+ // in the row equals the number of columns in the first row, we don't have
+ // any rowspans
+ rowColCount = 0;
+ jQuery(rootTr).children('td,th').each(function (index, elmnt) {
+ rowColCount += TableEditor.GET_COLSPAN_PROP(elmnt);
+ });
+
+ if (rowColCount === baseRowColumns) {
+ // Easy case. No rowspans to deal with
+ return colspanCount;
+ } else {
+ if (cells.length === 1) {
+ // Easy. Just the colspan
+ return TableEditor.GET_COLSPAN_PROP(cells[0]);
+ } else {
+ lastCell = jQuery(cells).eq(cells.length - 1)[0];
+ firstCell = jQuery(cells).eq(0)[0];
+ // On jQuery 1.4 upgrade, jQuery(cells).eq(-1)
+ return 1 + tableEditor.getCellXIndex(lastCell) -
+ tableEditor.getCellXIndex(firstCell);
+ }
+ }
+};
+
+/**
+ * Merge the table cells in the given selection using a colspan.
+ *
+ * @return {Boolean} true if changes are made, false otherwise
+ */
+TableEditor.prototype.mergeRow = function () {
+ var tableEditor = this,
+ wym = tableEditor._wym,
+ // Get all of the affected nodes in the range
+ nodes = wym._getSelectedNodes(),
+ cells,
+ rootTr,
+ mergeCell,
+ $elmnt,
+ rowspanProp,
+ newContent,
+ combinedColspan;
+
+ wym.deselect();
+
+ // Just use the td and th nodes
+ cells = jQuery(nodes).filter('td,th');
+ if (cells.length === 0) {
+ return false;
+ }
+
+ // If the selection is across multiple tables, don't merge
+ rootTr = tableEditor.getCommonParentTr(cells);
+ if (rootTr === null) {
+ return false;
+ }
+
+ mergeCell = cells[0];
+ // If any of the cells have a rowspan, create the inferred cells
+ jQuery(cells).each(function (i, elmnt) {
+ $elmnt = jQuery(elmnt);
+ rowspanProp = TableEditor.GET_ROWSPAN_PROP(elmnt);
+ if (rowspanProp <= 1) {
+ // We don't care about cells without a rowspan
+ return;
+ }
+
+ // This cell has an actual rowspan, we need to account for it
+ // Figure out the x index for this cell in the table grid
+ var index = tableEditor.getCellXIndex(elmnt),
+ // Create the previously-inferred cell in the appropriate index
+ // with one less rowspan
+ newRowspan = rowspanProp - 1,
+ newTd,
+ insertionIndex,
+ insertionCells,
+ cellInserted,
+ xIndex;
+ if (newRowspan === 1) {
+ newTd = '<td>' + $elmnt.html() + '</td>';
+ } else {
+ newTd = String() +
+ '<td rowspan="' + newRowspan + '">' +
+ $elmnt.html() +
+ '</td>';
+ }
+ if (index === 0) {
+ $elmnt.parent('tr')
+ .next('tr')
+ .prepend(newTd);
+ } else {
+ // TODO: account for colspan/rowspan with insertion
+ // Account for colspan/rowspan by walking from right to left
+ // looking for the cell closest to the desired index to APPEND to
+ insertionIndex = index - 1;
+ insertionCells = $elmnt.parent('tr').next('tr').find('td,th');
+ cellInserted = false;
+ for (i = insertionCells.length - 1; i >= 0; i--) {
+ xIndex = tableEditor.getCellXIndex(insertionCells[i]);
+ if (xIndex <= insertionIndex) {
+ jQuery(insertionCells[i]).after(newTd);
+ cellInserted = true;
+ break;
+ }
+ }
+ if (!cellInserted) {
+ // Bail out now before we clear HTML and break things
+ throw "Cell rowspan invalid";
+ }
+ }
+
+ // Clear the cell's html, since we just moved it down
+ $elmnt.html('');
+ });
+
+ // Remove any rowspan from the mergecell now that we've shifted rowspans
+ // down
+ // ie fails when we try to remove a rowspan for some reason
+ try {
+ jQuery(mergeCell).removeAttr('rowspan');
+ } catch (err) {
+ jQuery(mergeCell).attr('rowspan', 1);
+ }
+
+ // Build the content of the new combined cell from all of the included
+ // cells
+ newContent = '';
+ jQuery(cells).each(function (index, elmnt) {
+ newContent += jQuery(elmnt).html();
+ });
+
+ // Add a colspan to the farthest-left cell
+ combinedColspan = tableEditor.getTotalColumns(cells);
+ if (jQuery.browser.msie) {
+ // jQuery.attr doesn't work for colspan in ie
+ mergeCell.colSpan = combinedColspan;
+ } else {
+ jQuery(mergeCell).attr('colspan', combinedColspan);
+ }
+
+ // Delete the rest of the cells
+ jQuery(cells).each(function (index, elmnt) {
+ if (index !== 0) {
+ jQuery(elmnt).remove();
+ }
+ });
+
+ // Change the content in our newly-merged cell
+ jQuery(mergeCell).html(newContent);
+
+ tableEditor.selectElement(mergeCell);
+
+ wym.registerModification();
+ return true;
+};
+
+/**
+ * Add a row to the given elmnt (representing a <tr> or a child of a <tr>).
+ *
+ * @param The node which will have a row appended after its parent row.
+ */
+TableEditor.prototype.addRow = function (elmnt) {
+ var tableEditor = this,
+ wym = tableEditor._wym,
+ tr = tableEditor._wym.findUp(elmnt, 'tr'),
+ numColumns,
+ tdHtml,
+ i;
+
+ if (tr === null) {
+ return false;
+ }
+
+ numColumns = tableEditor.getNumColumns(tr);
+
+ tdHtml = '';
+ for (i = 0; i < numColumns; i++) {
+ tdHtml += '<td>&nbsp;</td>';
+ }
+ jQuery(tr).after('<tr>' + tdHtml + '</tr>');
+
+ wym.registerModification();
+ return false;
+};
+
+/**
+ * Remove the given table if it doesn't have any rows/columns.
+ *
+ * @param table The table to delete if it is empty.
+ */
+TableEditor.prototype.removeEmptyTable = function (table) {
+ var tableEditor = this,
+ wym = tableEditor._wym,
+ cells = jQuery(table).find('td,th'),
+ $table;
+ if (cells.length === 0) {
+ $table = jQuery(table);
+ $table.prev('br.' + WYMeditor.BLOCKING_ELEMENT_SPACER_CLASS).remove();
+ $table.next('br.' + WYMeditor.BLOCKING_ELEMENT_SPACER_CLASS).remove();
+ $table.remove();
+ wym.prepareDocForEditing();
+ }
+};
+
+/**
+ * Remove the row for the given element (representing a <tr> or a child
+ * of a <tr>).
+ *
+ * @param elmnt The node whose parent tr will be removed.
+ */
+TableEditor.prototype.removeRow = function (elmnt) {
+ var tableEditor = this,
+ wym = tableEditor._wym,
+ tr = wym.findUp(elmnt, 'tr'),
+ table;
+
+ if (tr === null) {
+ return false;
+ }
+ table = wym.findUp(elmnt, 'table');
+ if (
+ wym.hasSelection() === true &&
+ wym.doesElementContainSelection(elmnt) === true
+ ) {
+ wym.deselect();
+ }
+ jQuery(tr).remove();
+ tableEditor.removeEmptyTable(table);
+
+ wym.registerModification();
+ return false;
+};
+
+/**
+ * Add a column to the given elmnt (representing a <td> or a child of a <td>).
+ *
+ * @param elmnt The node which will have a column appended afterward.
+ */
+TableEditor.prototype.addColumn = function (elmnt) {
+ var tableEditor = this,
+ wym = tableEditor._wym,
+ td = wym.findUp(elmnt, ['td', 'th']),
+ prevTds,
+ tdIndex,
+ tr,
+ newTd = '<td>&nbsp;</td>',
+ newTh = '<th>&nbsp;</th>',
+ insertionElement;
+
+ if (td === null) {
+ return false;
+ }
+ prevTds = jQuery(td).prevAll();
+ tdIndex = prevTds.length;
+
+ tr = wym.findUp(td, 'tr');
+ jQuery(tr).siblings('tr').andSelf().each(function (index, element) {
+ insertionElement = newTd;
+ if (jQuery(element).find('th').length > 0) {
+ // The row has a TH, so insert a th
+ insertionElement = newTh;
+ }
+
+ jQuery(element).find('td,th').eq(tdIndex).after(insertionElement);
+ });
+
+ wym.registerModification();
+ return false;
+};
+
+/**
+ * Remove the column to the right of the given elmnt (representing a <td> or a
+ * child of a <td>).
+ */
+TableEditor.prototype.removeColumn = function (elmnt) {
+ var tableEditor = this,
+ wym = tableEditor._wym,
+ td = wym.findUp(elmnt, ['td', 'th']),
+ table,
+ prevTds,
+ tdIndex,
+ tr;
+ if (td === null) {
+ return false;
+ }
+ table = wym.findUp(elmnt, 'table');
+ prevTds = jQuery(td).prevAll();
+ tdIndex = prevTds.length;
+
+ tr = wym.findUp(td, 'tr');
+ jQuery(tr).siblings('tr').addBack().each(function (index, element) {
+ var $cell = jQuery(element).find("td, th").eq(tdIndex);
+ if (
+ wym.hasSelection() === true &&
+ wym.doesElementContainSelection($cell[0]) === true
+ ) {
+ wym.deselect();
+ }
+ $cell.remove();
+ });
+ tableEditor.removeEmptyTable(table);
+
+ wym.registerModification();
+ return false;
+};
+
+/**
+ * keyDown event handler used for consistent tab key cell movement.
+ */
+TableEditor.prototype.keyDown = function (evt) {
+ var doc = this,
+ wym = WYMeditor.INSTANCES[doc.title],
+ tableEditor = wym.tableEditor;
+
+ if (evt.which === WYMeditor.KEY_CODE.TAB) {
+ return tableEditor.selectNextCell(wym.selectedContainer());
+ }
+
+ return null;
+};
+
+/**
+ * Move the focus to the next cell.
+ */
+TableEditor.prototype.selectNextCell = function (elmnt) {
+ var tableEditor = this,
+ wym = tableEditor._wym,
+ cell = wym.findUp(elmnt, ['td', 'th']),
+ nextCells,
+ tr,
+ nextRows;
+
+ if (cell === null) {
+ return null;
+ }
+
+ // Try moving to the next cell to the right
+ nextCells = jQuery(cell).next('td,th');
+ if (nextCells.length > 0) {
+ tableEditor.selectElement(nextCells[0]);
+ return false;
+ }
+
+ // There was no cell to the right, use the first cell in the next row
+ tr = wym.findUp(cell, 'tr');
+ nextRows = jQuery(tr).next('tr');
+ if (nextRows.length !== 0) {
+ nextCells = jQuery(nextRows).children('td,th');
+ if (nextCells.length > 0) {
+ tableEditor.selectElement(nextCells[0]);
+ return false;
+ }
+ }
+
+ // There is no next row. Do a normal tab
+ return null;
+};
+
+/**
+ * Select the given element using rangy selectors.
+ */
+TableEditor.prototype.selectElement = function (elmnt) {
+ var tableEditor = this,
+ wym = tableEditor._wym,
+ sel = wym.selection(),
+ range = rangy.createRange(wym._doc);
+
+ range.setStart(elmnt, 0);
+ range.setEnd(elmnt, 0);
+ range.collapse(false);
+
+ try {
+ sel.setSingleRange(range);
+ } catch (err) {
+ // ie8 can raise an "unkown runtime error" trying to empty the range
+ }
+ // Old IE selection hack
+ if (WYMeditor.isInternetExplorerPre11()) {
+ wym._saveCaret();
+ }
+};
+
+/**
+ * Get the common parent tr for the given table cell nodes. If the closest
+ * parent tr for each cell isn't the same, returns null.
+ */
+TableEditor.prototype.getCommonParentTr = function (cells) {
+ var firstCell,
+ parentTrList,
+ rootTr;
+
+ cells = jQuery(cells).filter('td,th');
+ if (cells.length === 0) {
+ return null;
+ }
+ firstCell = cells[0];
+ parentTrList = jQuery(firstCell).parent('tr');
+
+ if (parentTrList.length === 0) {
+ return null;
+ }
+ rootTr = parentTrList[0];
+
+ // Ensure that all of the cells have the same parent tr
+ jQuery(cells).each(function (index, elmnt) {
+ parentTrList = jQuery(elmnt).parent('tr');
+ if (parentTrList.length === 0 || parentTrList[0] !== rootTr) {
+ return null;
+ }
+ });
+
+ return rootTr;
+};
diff --git a/static-files/journal/wymeditor/plugins/table/table_delete_column.png b/static-files/journal/wymeditor/plugins/table/table_delete_column.png
new file mode 100644
index 0000000..9022d68
--- /dev/null
+++ b/static-files/journal/wymeditor/plugins/table/table_delete_column.png
Binary files differ
diff --git a/static-files/journal/wymeditor/plugins/table/table_delete_row.png b/static-files/journal/wymeditor/plugins/table/table_delete_row.png
new file mode 100644
index 0000000..f9d956f
--- /dev/null
+++ b/static-files/journal/wymeditor/plugins/table/table_delete_row.png
Binary files differ
diff --git a/static-files/journal/wymeditor/plugins/table/table_insert_column.png b/static-files/journal/wymeditor/plugins/table/table_insert_column.png
new file mode 100644
index 0000000..49226ec
--- /dev/null
+++ b/static-files/journal/wymeditor/plugins/table/table_insert_column.png
Binary files differ
diff --git a/static-files/journal/wymeditor/plugins/table/table_insert_row.png b/static-files/journal/wymeditor/plugins/table/table_insert_row.png
new file mode 100644
index 0000000..da435c3
--- /dev/null
+++ b/static-files/journal/wymeditor/plugins/table/table_insert_row.png
Binary files differ
diff --git a/static-files/journal/wymeditor/plugins/table/table_join_row.png b/static-files/journal/wymeditor/plugins/table/table_join_row.png
new file mode 100644
index 0000000..70e5983
--- /dev/null
+++ b/static-files/journal/wymeditor/plugins/table/table_join_row.png
Binary files differ