jsHtml2Ods/src/js/opendocument/OpenDocument.StyleManager.js

415 lines
12 KiB
JavaScript

/* 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 '~':
for(let i = index +1; i <= length; i++) {
__addMatchingClasses(tokens[i]);
}
index = length;
break;
case '+':
__setParent(tokens[index +1]);
index ++;
break;
}
index ++;
}
}
function __addMatchingClasses(token) {
if (!token) {
return;
}
let map = styleManager.matchingClassMaps.get(type);
if (!map) {
return;
}
if (token.startsWith('.')) {
map.set(token.substring(1), style.styleName);
}
}
function __setParent(token) {
if (!token) {
return;
}
let dotIndex = token.indexOf('.');
if (dotIndex !== -1) {
style.setParent(token.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"
}
},
{
type: "row",
name: "Standard",
parent: "",
properties: {
}
},
{
type: "row",
name: "Header",
parent: "",
properties: {
}
}
];