1 /**
  2  * Copyright (C) 2013 KO GmbH <copyright@kogmbh.com>
  3  *
  4  * @licstart
  5  * This file is part of WebODF.
  6  *
  7  * WebODF is free software: you can redistribute it and/or modify it
  8  * under the terms of the GNU Affero General Public License (GNU AGPL)
  9  * as published by the Free Software Foundation, either version 3 of
 10  * the License, or (at your option) any later version.
 11  *
 12  * WebODF is distributed in the hope that it will be useful, but
 13  * WITHOUT ANY WARRANTY; without even the implied warranty of
 14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 15  * GNU Affero General Public License for more details.
 16  *
 17  * You should have received a copy of the GNU Affero General Public License
 18  * along with WebODF.  If not, see <http://www.gnu.org/licenses/>.
 19  * @licend
 20  *
 21  * @source: http://www.webodf.org/
 22  * @source: https://github.com/kogmbh/WebODF/
 23  */
 24 
 25 /*global ops, runtime*/
 26 
 27 /**
 28  * @constructor
 29  * @implements ops.Operation
 30  */
 31 ops.OpInsertTable = function OpInsertTable() {
 32     "use strict";
 33 
 34     var memberid, timestamp, initialRows, initialColumns, position, tableName, tableStyleName,
 35         tableColumnStyleName,
 36         /**@type{!Array.<!Array.<string>>}*/
 37         tableCellStyleMatrix,
 38         /**@const*/
 39         tablens = "urn:oasis:names:tc:opendocument:xmlns:table:1.0",
 40         /**@const*/
 41         textns = "urn:oasis:names:tc:opendocument:xmlns:text:1.0";
 42 
 43     /**
 44      * @param {!ops.OpInsertTable.InitSpec} data
 45      */
 46     this.init = function (data) {
 47         memberid = data.memberid;
 48         timestamp = data.timestamp;
 49         position = data.position;
 50         initialRows = data.initialRows;
 51         initialColumns = data.initialColumns;
 52         tableName = data.tableName;
 53         tableStyleName = data.tableStyleName;
 54         tableColumnStyleName = data.tableColumnStyleName;
 55         tableCellStyleMatrix = data.tableCellStyleMatrix;
 56     };
 57 
 58     this.isEdit = true;
 59     this.group = undefined;
 60 
 61     /**
 62      * @param {!number} row
 63      * @param {!number} column
 64      * @return {!string|undefined}
 65      */
 66     function getCellStyleName(row, column) {
 67         var rowStyles;
 68         if (tableCellStyleMatrix.length === 1) {
 69             rowStyles = tableCellStyleMatrix[0];
 70         } else if (tableCellStyleMatrix.length === 3) {
 71             switch (row) {
 72             case 0:
 73                 rowStyles = tableCellStyleMatrix[0];
 74                 break;
 75             case initialRows - 1:
 76                 rowStyles = tableCellStyleMatrix[2];
 77                 break;
 78             default:
 79                 rowStyles = tableCellStyleMatrix[1];
 80                 break;
 81             }
 82         } else {
 83             rowStyles = tableCellStyleMatrix[row];
 84         }
 85 
 86         if (rowStyles.length === 1) {
 87             return rowStyles[0];
 88         }
 89         if (rowStyles.length === 3) {
 90             switch (column) {
 91             case 0:
 92                 return rowStyles[0];
 93             case initialColumns - 1:
 94                 return rowStyles[2];
 95             default:
 96                 return rowStyles[1];
 97             }
 98         }
 99         return rowStyles[column];
100     }
101 
102     /**
103      * @param {!Document} document
104      * @return {!Element}
105      */
106     function createTableNode(document) {
107         var tableNode = document.createElementNS(tablens, "table:table"),
108             columns = document.createElementNS(tablens, "table:table-column"),
109             row, cell, paragraph,
110             rowCounter, columnCounter, cellStyleName;
111 
112         if (tableStyleName) {
113             tableNode.setAttributeNS(tablens, "table:style-name", tableStyleName);
114         }
115         if (tableName) {
116             tableNode.setAttributeNS(tablens, "table:name", tableName);
117         }
118 
119         columns.setAttributeNS(tablens, "table:number-columns-repeated", initialColumns);
120         if (tableColumnStyleName) {
121             columns.setAttributeNS(tablens, "table:style-name", tableColumnStyleName);
122         }
123 
124         tableNode.appendChild(columns);
125         for (rowCounter = 0; rowCounter < initialRows; rowCounter += 1) {
126             row = document.createElementNS(tablens, "table:table-row");
127             for (columnCounter = 0; columnCounter < initialColumns; columnCounter += 1) {
128                 cell = document.createElementNS(tablens, "table:table-cell");
129                 cellStyleName = getCellStyleName(rowCounter, columnCounter);
130                 if (cellStyleName) {
131                     cell.setAttributeNS(tablens, "table:style-name", cellStyleName);
132                 }
133                 paragraph = document.createElementNS(textns, "text:p");
134                 cell.appendChild(paragraph);
135                 row.appendChild(cell);
136             }
137             tableNode.appendChild(row);
138         }
139         return tableNode;
140     }
141 
142     /**
143      * @param {!ops.Document} document
144      */
145     this.execute = function (document) {
146         var odtDocument = /**@type{ops.OdtDocument}*/(document),
147             domPosition = odtDocument.getTextNodeAtStep(position),
148             rootNode = odtDocument.getRootNode(),
149             previousSibling,
150             tableNode;
151 
152         if (domPosition) {
153             tableNode = createTableNode(odtDocument.getDOMDocument());
154             // For now assume the table should be inserted after the current paragraph
155             // or failing that, as the first element in the root node
156             previousSibling = odtDocument.getParagraphElement(domPosition.textNode);
157             rootNode.insertBefore(tableNode, previousSibling.nextSibling);
158             // The parent table counts for 1 position, and 1 paragraph is added per cell
159             odtDocument.emit(ops.OdtDocument.signalStepsInserted, {position: position});
160 
161             odtDocument.getOdfCanvas().refreshSize();
162             odtDocument.emit(ops.OdtDocument.signalTableAdded, {
163                 tableElement: tableNode,
164                 memberId: memberid,
165                 timeStamp: timestamp
166             });
167 
168             odtDocument.getOdfCanvas().rerenderAnnotations();
169             return true;
170         }
171         return false;
172     };
173 
174     /**
175      * @return {!ops.OpInsertTable.Spec}
176      */
177     this.spec = function () {
178         return {
179             optype: "InsertTable",
180             memberid: memberid,
181             timestamp: timestamp,
182             position: position,
183             initialRows: initialRows,
184             initialColumns: initialColumns,
185             tableName: tableName,
186             tableStyleName: tableStyleName,
187             tableColumnStyleName: tableColumnStyleName,
188             tableCellStyleMatrix: tableCellStyleMatrix
189         };
190     };
191 };
192 /**@typedef{{
193     optype:string,
194     memberid:string,
195     timestamp:number,
196     position:number,
197     initialRows:number,
198     initialColumns:number,
199     tableName:string,
200     tableStyleName:string,
201     tableColumnStyleName:string,
202     tableCellStyleMatrix:!Array.<!Array.<string>>
203 }}*/
204 ops.OpInsertTable.Spec;
205 /**@typedef{{
206     memberid:string,
207     timestamp:(number|undefined),
208     position:number,
209     initialRows:number,
210     initialColumns:number,
211     tableName:string,
212     tableStyleName:string,
213     tableColumnStyleName:string,
214     tableCellStyleMatrix:!Array.<!Array.<string>>
215 }}*/
216 ops.OpInsertTable.InitSpec;
217