1 /** 2 * Copyright (C) 2012-2014 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, gui*/ 26 27 /** 28 * @constructor 29 * @param {!Array.<!odf.Formatting.AppliedStyle>} styles 30 */ 31 gui.StyleSummary = function StyleSummary(styles) { 32 "use strict"; 33 var propertyValues = {}; 34 35 /** 36 * Get all values for the section + propertyName across all supplied styles. If a 37 * one or more styles do not have a defined value for the specified propertyName, the 38 * returned array will contain an "undefined" value to indicate the property is 39 * missing on some of the styles. 40 * 41 * @param {!string} section Section (e.g., style:text-properties) 42 * @param {!string} propertyName Property (e.g., fo:font-weight) 43 * @return {!Array.<!string|undefined>} 44 */ 45 function getPropertyValues(section, propertyName) { 46 var cacheKey = section + "|" + propertyName, 47 /**@type{Array.<!string>}*/values; 48 if (!propertyValues.hasOwnProperty(cacheKey)) { 49 values = []; 50 styles.forEach(function (style) { 51 var styleSection = /**@type{!Object.<!string, !string>}*/(style.styleProperties[section]), 52 value = styleSection && styleSection[propertyName]; 53 if (values.indexOf(value) === -1) { 54 values.push(value); 55 } 56 }); 57 propertyValues[cacheKey] = values; 58 } 59 return propertyValues[cacheKey]; 60 } 61 this.getPropertyValues = getPropertyValues; 62 63 /** 64 * Create a lazily-loaded, cached lookup function that returns true if all section + propertyName 65 * values are contained in the supplied acceptedPropertyValues array 66 * 67 * @param {!string} section Section (e.g., style:text-properties) 68 * @param {!string} propertyName Property (e.g., fo:font-weight) 69 * @param {!Array.<!string>} acceptedPropertyValues Array of accepted values 70 * @return {!function():!boolean} Returns true if all values are in the accepted property values 71 */ 72 function lazilyLoaded(section, propertyName, acceptedPropertyValues) { 73 return function () { 74 var existingPropertyValues = getPropertyValues(section, propertyName); 75 // As a small optimization, check accepted vs. existing lengths first. 76 // If there are more existing values than accepted, this function should return 77 // false as there are definitely some non-acceptable values. 78 return acceptedPropertyValues.length >= existingPropertyValues.length 79 // Next, ensure each existing property value appears in the accepted properties array 80 && existingPropertyValues.every(function (v) { return acceptedPropertyValues.indexOf(v) !== -1; }); 81 }; 82 } 83 84 /** 85 * Return the common value for a section + propertyName if it has an identical value in all 86 * supplied styles. If there are multiple values, or one or more styles do not have either 87 * the section or propertyName present, this function will return undefined. 88 * 89 * @param {!string} section Section (e.g., style:text-properties) 90 * @param {!string} propertyName Property (e.g., fo:font-weight) 91 * @return {string|undefined} 92 */ 93 function getCommonValue(section, propertyName) { 94 var values = getPropertyValues(section, propertyName); 95 return values.length === 1 ? values[0] : undefined; 96 } 97 this.getCommonValue = getCommonValue; 98 99 /** 100 * Returns true if all styles specify text as bold; otherwise false. 101 * @return {!boolean} 102 */ 103 this.isBold = lazilyLoaded("style:text-properties", "fo:font-weight", ["bold"]); 104 105 /** 106 * Returns true if all styles specify text as italic; otherwise false. 107 * @return {!boolean} 108 */ 109 this.isItalic = lazilyLoaded("style:text-properties", "fo:font-style", ["italic"]); 110 111 /** 112 * Returns true if all styles specify text as underlined; otherwise false. 113 * @return {!boolean} 114 */ 115 this.hasUnderline = lazilyLoaded("style:text-properties", "style:text-underline-style", ["solid"]); 116 117 /** 118 * Returns true if all styles specify text as strike-through; otherwise false. 119 * @return {!boolean} 120 */ 121 this.hasStrikeThrough = lazilyLoaded("style:text-properties", "style:text-line-through-style", ["solid"]); 122 123 /** 124 * Returns the common font size in the supplied styles; otherwise undefined if there is no common font size 125 * @return {number|undefined} 126 */ 127 this.fontSize = function () { 128 var stringFontSize = getCommonValue('style:text-properties', 'fo:font-size'); 129 return /**@type{number|undefined}*/(stringFontSize && parseFloat(stringFontSize)); // TODO: support other units besides pt! 130 }; 131 132 /** 133 * Returns the common font name in the supplied styles; otherwise undefined if there is no common font name 134 * @return {string|undefined} 135 */ 136 this.fontName = function () { 137 return getCommonValue('style:text-properties', 'style:font-name'); 138 }; 139 140 /** 141 * Returns true if all styles are left aligned; otherwise false. 142 * @return {!boolean} 143 */ 144 this.isAlignedLeft = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["left", "start"]); 145 146 /** 147 * Returns true if all styles are center aligned; otherwise false. 148 * @return {!boolean} 149 */ 150 this.isAlignedCenter = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["center"]); 151 152 /** 153 * Returns true if all styles are right aligned; otherwise false. 154 * @return {!boolean} 155 */ 156 this.isAlignedRight = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["right", "end"]); 157 158 /** 159 * Returns true if all styles are justified; otherwise false. 160 * @return {!boolean} 161 */ 162 this.isAlignedJustified = lazilyLoaded("style:paragraph-properties", "fo:text-align", ["justify"]); 163 /** 164 * @type{!Object.<string,function():*>} 165 */ 166 this.text = { 167 isBold: this.isBold, 168 isItalic: this.isItalic, 169 hasUnderline: this.hasUnderline, 170 hasStrikeThrough: this.hasStrikeThrough, 171 fontSize: this.fontSize, 172 fontName: this.fontName 173 }; 174 /** 175 * @type{!Object.<string,function():*>} 176 */ 177 this.paragraph = { 178 isAlignedLeft: this.isAlignedLeft, 179 isAlignedCenter: this.isAlignedCenter, 180 isAlignedRight: this.isAlignedRight, 181 isAlignedJustified: this.isAlignedJustified 182 }; 183 }; 184