1 /**
  2  * Copyright (C) 2012-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 runtime, odf, ops*/
 26 
 27 /**
 28  * @constructor
 29  * @implements ops.Operation
 30  */
 31 ops.OpUpdateParagraphStyle = function OpUpdateParagraphStyle() {
 32     "use strict";
 33 
 34     var memberid, timestamp, styleName,
 35         /**@type{!odf.Formatting.StyleData}*/
 36         setProperties,
 37         /**@type{{attributes:string}}*/
 38         removedProperties,
 39         /**@const*/
 40         paragraphPropertiesName = 'style:paragraph-properties',
 41         /**@const*/
 42         textPropertiesName = 'style:text-properties',
 43         /**@const*/
 44         stylens = odf.Namespaces.stylens;
 45 
 46     /**
 47      * Removes attributes of a node by the names listed in removedAttributeNames.
 48      * @param {!Element} node
 49      * @param {!string} removedAttributeNames
 50      */
 51     function removedAttributesFromStyleNode(node, removedAttributeNames) {
 52         var i, attributeNameParts,
 53             /**@type{!Array.<string>}*/
 54             attributeNameList = removedAttributeNames ? removedAttributeNames.split(',') : [];
 55 
 56         for (i = 0; i < attributeNameList.length; i += 1) {
 57             attributeNameParts = attributeNameList[i].split(":");
 58             // TODO: ensure all used prefixes have a namespaces listed
 59             node.removeAttributeNS(/**@type{string}*/(odf.Namespaces.lookupNamespaceURI(attributeNameParts[0])), attributeNameParts[1]);
 60         }
 61     }
 62 
 63     /**
 64      * @param {!ops.OpUpdateParagraphStyle.InitSpec} data
 65      */
 66     this.init = function (data) {
 67         memberid = data.memberid;
 68         timestamp = data.timestamp;
 69         styleName = data.styleName;
 70         setProperties = data.setProperties;
 71         removedProperties = data.removedProperties;
 72     };
 73 
 74     this.isEdit = true;
 75     this.group = undefined;
 76 
 77     /**
 78      * @param {!ops.Document} document
 79      */
 80     this.execute = function (document) {
 81         var odtDocument = /**@type{ops.OdtDocument}*/(document),
 82             formatting = odtDocument.getFormatting(),
 83             styleNode, object,
 84             paragraphPropertiesNode, textPropertiesNode;
 85 
 86         if (styleName !== "") {
 87             // Common Style
 88             styleNode = formatting.getStyleElement(styleName, 'paragraph');
 89         } else {
 90             // Default Style
 91             styleNode = formatting.getDefaultStyleElement('paragraph');
 92         }
 93 
 94         if (styleNode) {
 95             paragraphPropertiesNode = /**@type{Element}*/(styleNode.getElementsByTagNameNS(stylens, 'paragraph-properties').item(0));
 96             textPropertiesNode = /**@type{Element}*/(styleNode.getElementsByTagNameNS(stylens, 'text-properties').item(0));
 97 
 98             if (setProperties) {
 99                 formatting.updateStyle(styleNode, setProperties);
100             }
101 
102             // remove attributes in the style nodes
103             if (removedProperties) {
104                 object = /**@type{{attributes:string}}*/(removedProperties[paragraphPropertiesName]);
105                 if (paragraphPropertiesNode && object) {
106                     removedAttributesFromStyleNode(paragraphPropertiesNode, object.attributes);
107                     if (paragraphPropertiesNode.attributes.length === 0) {
108                         styleNode.removeChild(paragraphPropertiesNode);
109                     }
110                 }
111 
112                 object = /**@type{{attributes:string}}*/(removedProperties[textPropertiesName]);
113                 if (textPropertiesNode && object) {
114                     // TODO: check if fontname can be removed from font-face-declaration
115                     removedAttributesFromStyleNode(textPropertiesNode, object.attributes);
116                     if (textPropertiesNode.attributes.length === 0) {
117                         styleNode.removeChild(textPropertiesNode);
118                     }
119                 }
120 
121                 removedAttributesFromStyleNode(styleNode, removedProperties.attributes);
122             }
123 
124             odtDocument.getOdfCanvas().refreshCSS();
125             odtDocument.emit(ops.OdtDocument.signalParagraphStyleModified, styleName);
126             odtDocument.getOdfCanvas().rerenderAnnotations();
127             return true;
128         }
129         return false;
130     };
131 
132     /**
133      * @return {!ops.OpUpdateParagraphStyle.Spec}
134      */
135     this.spec = function () {
136         return {
137             optype: "UpdateParagraphStyle",
138             memberid: memberid,
139             timestamp: timestamp,
140             styleName: styleName,
141             setProperties: setProperties,
142             removedProperties: removedProperties
143         };
144     };
145 };
146 /**@typedef{{
147     optype:string,
148     memberid:string,
149     timestamp:number,
150     styleName:string,
151     setProperties:!odf.Formatting.StyleData,
152     removedProperties:{attributes:string}
153 }}*/
154 ops.OpUpdateParagraphStyle.Spec;
155 /**@typedef{{
156     memberid:string,
157     timestamp:(number|undefined),
158     styleName:string,
159     setProperties:!odf.Formatting.StyleData,
160     removedProperties:{attributes:string}
161 }}*/
162 ops.OpUpdateParagraphStyle.InitSpec;
163