/* global OpenDocument */ OpenDocument.StyleManager = function () { this.maps = new Map([ ["cell-named", new Map()], ["row-named", new Map()], ["cell-automatic", new Map()], ["column-named", new Map()], ["column-automatic", new Map()] ]); this.matchingClassMaps = new Map([ ["cell", new Map()], ["row", new Map()], ["column", new Map()] ]); for(let object of OpenDocument.StyleManager.DEFAULT_STYLES ) { this.putStyle(object.type + "-named", _buildDefault(object)); } this.automaticStyleNumber = 1; this.currencyMap = new Map(); OpenDocument.StyleManager.readDocumentStyleSheets(this); function _buildDefault(object) { let style = new OpenDocument.Style(object.type, object.name); if (object.parent) { style.setParent(object.parent); } for(let propertyName in object.properties) { let stylePropertyDef = OpenDocument.Style.getStylePropertyDef(object.type, propertyName); if (stylePropertyDef) { style.putStyleProperty(stylePropertyDef, object.properties[propertyName]); } } return style; } }; OpenDocument.StyleManager.prototype.putStyle = function (mapName, style, styleKey) { if (!styleKey) { styleKey = style.styleName; } var map = this.maps.get(mapName); if (map.has(styleKey)) { let existingStyle = map.get(styleKey); existingStyle.copyProperties(style); } else { map.set(styleKey, style); } }; OpenDocument.StyleManager.prototype.hasStyle = function (mapName, styleKey) { var map = this.maps.get(mapName); if (map) { return map.has(styleKey); } else { return false; } }; OpenDocument.StyleManager.prototype.getStyle = function (mapName, styleKey) { var map = this.maps.get(mapName); if (map) { return map.get(styleKey); } else { return null; } return this.map.get(styleKey); }; OpenDocument.StyleManager.prototype.getAutomaticCellStyleName = function (type, parentStyleName, currencyCode) { var styleKey = type + ":"; if (type === "currency") { styleKey += currencyCode + ":"; } styleKey += parentStyleName; if (this.hasStyle("cell-automatic", styleKey)) { return this.getStyle("cell-automatic", styleKey).styleName; } var name = OpenDocument.CELLSTYLE_PREFIX + this.automaticStyleNumber; this.automaticStyleNumber++; var dataStyleName = null; switch(type) { case "date": dataStyleName = OpenDocument.ISODATE_DATASTYLE_NAME; break; case "currency": let number; if (this.currencyMap.has(currencyCode)) { number = this.currencyMap.get(currencyCode); } else { number = this.automaticStyleNumber; this.automaticStyleNumber++; this.currencyMap.set(currencyCode, number); } dataStyleName = OpenDocument.DATASTYLE_PREFIX + number; break; } var cellStyle = new OpenDocument.Style("cell", name); if (parentStyleName) { cellStyle.setParent(parentStyleName); } else { cellStyle.setParent(OpenDocument.DEFAULT_CELLSTYLE_NAME); } if (dataStyleName) { cellStyle.setDataStyle(dataStyleName); } this.putStyle("cell-automatic", cellStyle, styleKey); return name; }; OpenDocument.StyleManager.prototype.getMatchingStyleName = function (type, element) { var map = this.matchingClassMaps.get(type); if (map) { for(let className of element.classList) { if (map.has(className)) { return map.get(className); } } } return ""; }; /** * * @param {OpenDocument.XmlWriter} xmlWriter * @returns {undefined} */ OpenDocument.StyleManager.prototype.writeStyles = function (mapName, xmlWriter) { var map = this.maps.get(mapName); if (map) { for(let style of map.values()) { style.write(xmlWriter); } } }; OpenDocument.StyleManager.prototype.writeDataStyles = function (xmlWriter) { xmlWriter .addDateStyle(); for(let entry of this.currencyMap) { xmlWriter .addCurrencyStyle(entry[0], entry[1]); } }; OpenDocument.StyleManager.readDocumentStyleSheets = function (styleManager) { var styleSheetList = document.styleSheets; for(let i = 0, len = styleSheetList.length; i < len; i++) { OpenDocument.StyleManager.readStyleSheet(styleManager, styleSheetList[i]); } }; OpenDocument.StyleManager.readStyleSheet = function (styleManager, styleSheet) { var ruleList = styleSheet.cssRules; for(let i = 0, len = ruleList.length; i < len; i++) { let rule = ruleList[i]; if ((rule.selectorText) && (rule.style)) { let selectorArray = _parseSelectorText(rule.selectorText); for(let selector of selectorArray) { _addStyle(selector, rule.style); } } } function _parseSelectorText(selectorText) { let resultArray = new Array(); for(let token of selectorText.split(',')) { let result = __parseToken(token); if (result) { switch(result[0]) { case "cell": case "row": case "column": resultArray.push(result); break; } } } return resultArray; function __parseToken(token) { token = token.trim(); let idx = token.indexOf(' '); let followingPart = ""; if (idx !== -1) { followingPart = token.substring(idx +1).trim(); token = token.substring(0, idx); } let dotIndex = token.indexOf('.'); if (dotIndex === -1) { return null; } let type = token.substring(0, dotIndex); let name = token.substring(dotIndex + 1); return [type, name, followingPart]; } } function _addStyle(selector, cssStyleDeclaration) { let type = selector[0]; let style = new OpenDocument.Style(type, selector[1]); let borderBuffer = false; if (type === "cell") { borderBuffer = new OpenDocument.StyleManager.BorderBuffer(); } for(let i = 0, len = cssStyleDeclaration.length; i < len; i++) { let propertyName = cssStyleDeclaration[i]; let propertyValue = cssStyleDeclaration.getPropertyValue(propertyName); if (borderBuffer) { let borderTest = propertyName.match(/^border-([a-z]+)-([a-z]+)/); if (borderTest) { borderBuffer.putSubproperty(borderTest[1], borderTest[2], propertyValue); continue; } } if (propertyName === "content") { __parseDeclarationText(propertyValue); } else { let stylePropertyDef = OpenDocument.Style.getStylePropertyDef(type, propertyName); if (stylePropertyDef) { style.putStyleProperty(stylePropertyDef, propertyValue); } } } if (borderBuffer) { borderBuffer.fillStyle(style); } _parseFollowingPart(selector[2]); styleManager.putStyle(type + "-named", style); function __parseDeclarationText(declarationText) { let start = declarationText.indexOf('"'); if (start === -1) { return; } let end = declarationText.lastIndexOf('"'); if (end === start) { return; } let tokens = declarationText.substring(start + 1, end).split(';'); for(let token of tokens) { let paire = token.split(':'); if (paire.length === 2) { let name = paire[0].trim(); let value = paire[1].trim(); let stylePropertyDef = OpenDocument.Style.getStylePropertyDef(type, name); if (stylePropertyDef) { style.putStyleProperty(stylePropertyDef, value); } } } } function _parseFollowingPart(followingPart) { if (!followingPart) { return; } let tokens = new Array(); for(let token of followingPart.split(" ")) { token = token.trim(); if (token.length > 0) { tokens.push(token); } } let index = 0; let length = tokens.length - 1; while(index < length) { let operatorToken = tokens[index]; switch(operatorToken) { case '~': __addMatchingClass(_parseClass(tokens[index +1])); index ++; break; case '+': __setParent(_parseClass(tokens[index +1])); index ++; break; } index ++; } } function __addMatchingClass(matchingClass) { if (!matchingClass) { return; } let map = styleManager.matchingClassMaps.get(type); if (map) { map.set(matchingClass, style.styleName); } } function __setParent(parentStyleName) { if (!parentStyleName) { return; } style.setParent(parentStyleName); } } function _parseClass(classToken) { let dotIndex = classToken.indexOf('.'); if (dotIndex === -1) { return false; } return classToken.substring(dotIndex + 1); } }; OpenDocument.StyleManager.BorderBuffer = function () { this.map = new Map([ ["bottom", false], ["left", false], ["right", false], ["top", false] ]); }; OpenDocument.StyleManager.BorderBuffer.prototype.putSubproperty = function (position, subproperty, value) { if (!this.map.has(position)) { return; } let positionObject = this.map.get(position); if (!positionObject) { positionObject = { width: "0.75pt", color: "rgb(0, 0, 0)", style: "solid" }; this.map.set(position, positionObject); } if (positionObject.hasOwnProperty(subproperty)) { if (subproperty === "color") { value = OpenDocument.Style.formatColor(value); } positionObject[subproperty] = value; }; }; OpenDocument.StyleManager.BorderBuffer.prototype.fillStyle = function (style) { for(let entry of this.map) { let position = entry[0]; let object = entry[1]; if (object) { let stylePropertyDef = OpenDocument.Style.getStylePropertyDef("type", "border-" + position); if (stylePropertyDef) { let value = object.width + " " + object.style + " " + object.color; style.putStyleProperty(stylePropertyDef, value); } } } }; OpenDocument.StyleManager.DEFAULT_STYLES = [ { type: "cell", name: "Standard", parent: "", properties: { } }, { type: "cell", name: "Bold", parent: "Standard", properties: { "font-weight": "bold" } }, { type: "cell", name: "Italic", parent: "Standard", properties: { "font-weight": "italic" } }, { type: "cell", name: "BoldItalic", parent: "Standard", properties: { "font-weight": "bold", "font-style": "italic" } }, { type: "cell", name: "Header", properties: { "font-weight": "bold", "text-align": "center", "vertical-align": "middle" } } ];