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