diff --git a/lib/network/modules/NodesHandler.js b/lib/network/modules/NodesHandler.js index 5ed50e24..7c56f3d2 100644 --- a/lib/network/modules/NodesHandler.js +++ b/lib/network/modules/NodesHandler.js @@ -64,7 +64,7 @@ class NodesHandler { mono: { mod: '', size: 15, // px - face: 'courier new', + face: 'monospace', vadjust: 2 } }, diff --git a/lib/network/modules/components/shared/Label.js b/lib/network/modules/components/shared/Label.js index 80afc804..becbf0d3 100644 --- a/lib/network/modules/components/shared/Label.js +++ b/lib/network/modules/components/shared/Label.js @@ -126,124 +126,136 @@ class Label { } } + + /** + * Collapse the font options for the multi-font to single objects, from + * the chain of option objects passed. + * + * If an option for a specific multi-font is not present, the parent + * option is checked for the given option. + * + * NOTE: naming of 'groupOptions' is a misnomer; the actual value passed + * is the new values to set from setOptions(). + */ propagateFonts(options, groupOptions, defaultOptions) { - if (this.fontOptions.multi) { - let mods = [ 'bold', 'ital', 'boldital', 'mono' ]; - for (const mod of mods) { - let optionsFontMod; - if (options.font) { - optionsFontMod = options.font[mod]; - } - if (typeof optionsFontMod === 'string') { - let modOptionsArray = optionsFontMod.split(" "); - this.fontOptions[mod].size = modOptionsArray[0].replace("px",""); - this.fontOptions[mod].face = modOptionsArray[1]; - this.fontOptions[mod].color = modOptionsArray[2]; - this.fontOptions[mod].vadjust = this.fontOptions.vadjust; - this.fontOptions[mod].mod = defaultOptions.font[mod].mod; - } else { - // We need to be crafty about loading the modded fonts. We want as - // much 'natural' versatility as we can get, so a simple global - // change propagates in an expected way, even if not stictly logical. - - // face: We want to capture any direct settings and overrides, but - // fall back to the base font if there aren't any. We make a - // special exception for mono, since we probably don't want to - // sync to a the base font face. - // - // if the mod face is in the node's options, use it - // else if the mod face is in the global options, use it - // else if the face is in the global options, use it - // else use the base font's face. - if (optionsFontMod && optionsFontMod.hasOwnProperty('face')) { - this.fontOptions[mod].face = optionsFontMod.face; - } else if (groupOptions.font && groupOptions.font[mod] && - groupOptions.font[mod].hasOwnProperty('face')) { - this.fontOptions[mod].face = groupOptions.font[mod].face; - } else if (mod === 'mono') { - this.fontOptions[mod].face = defaultOptions.font[mod].face; - } else if (groupOptions.font && - groupOptions.font.hasOwnProperty('face')) { - this.fontOptions[mod].face = groupOptions.font.face; - } else { - this.fontOptions[mod].face = this.fontOptions.face; - } + if (!this.fontOptions.multi) return; - // color: this is handled just like the face. - if (optionsFontMod && optionsFontMod.hasOwnProperty('color')) { - this.fontOptions[mod].color = optionsFontMod.color; - } else if (groupOptions.font && groupOptions.font[mod] && - groupOptions.font[mod].hasOwnProperty('color')) { - this.fontOptions[mod].color = groupOptions.font[mod].color; - } else if (groupOptions.font && - groupOptions.font.hasOwnProperty('color')) { - this.fontOptions[mod].color = groupOptions.font.color; - } else { - this.fontOptions[mod].color = this.fontOptions.color; - } + /** + * Get property value from options.font[mod][property] if present. + * If mod not passed, use property value from options.font[property]. + * + * @return value if found, null otherwise. + */ + var getP = function(options, mod, property) { + if (!options.font) return null; - // mod: this is handled just like the face, except we never grab the - // base font's mod. We know they're in the defaultOptions, and unless - // we've been steered away from them, we use the default. - if (optionsFontMod && optionsFontMod.hasOwnProperty('mod')) { - this.fontOptions[mod].mod = optionsFontMod.mod; - } else if (groupOptions.font && groupOptions.font[mod] && - groupOptions.font[mod].hasOwnProperty('mod')) { - this.fontOptions[mod].mod = groupOptions.font[mod].mod; - } else if (groupOptions.font && - groupOptions.font.hasOwnProperty('mod')) { - this.fontOptions[mod].mod = groupOptions.font.mod; - } else { - this.fontOptions[mod].mod = defaultOptions.font[mod].mod; - } + var opt = options.font; - // size: It's important that we size up defaults similarly if we're - // using default faces unless overriden. We want to preserve the - // ratios closely - but if faces have changed, all bets are off. - // - // if the mod size is in the node's options, use it - // else if the mod size is in the global options, use it - // else if the mod face is the same as the default and the base face - // is the same as the default, scale the mod size using the same - // ratio - // else if the size is in the global options, use it - // else use the base font's size. - if (optionsFontMod && optionsFontMod.hasOwnProperty('size')) { - this.fontOptions[mod].size = optionsFontMod.size; - } else if (groupOptions.font && groupOptions.font[mod] && - groupOptions.font[mod].hasOwnProperty('size')) { - this.fontOptions[mod].size = groupOptions.font[mod].size; - } else if ((this.fontOptions[mod].face === defaultOptions.font[mod].face) && - (this.fontOptions.face === defaultOptions.font.face)) { - let ratio = this.fontOptions.size / Number(defaultOptions.font.size); - this.fontOptions[mod].size = defaultOptions.font[mod].size * ratio; - } else if (groupOptions.font && - groupOptions.font.hasOwnProperty('size')) { - this.fontOptions[mod].size = groupOptions.font.size; - } else { - this.fontOptions[mod].size = this.fontOptions.size; - } + if (mod) { + if (!opt[mod]) return null; + opt = opt[mod]; + } - // vadjust: this is handled just like the size. - if (optionsFontMod && optionsFontMod.hasOwnProperty('vadjust')) { - this.fontOptions[mod].vadjust = optionsFontMod.vadjust; - } else if (groupOptions.font && - groupOptions.font[mod] && groupOptions.font[mod].hasOwnProperty('vadjust')) { - this.fontOptions[mod].vadjust = groupOptions.font[mod].vadjust; - } else if ((this.fontOptions[mod].face === defaultOptions.font[mod].face) && - (this.fontOptions.face === defaultOptions.font.face)) { - let ratio = this.fontOptions.size / Number(defaultOptions.font.size); - this.fontOptions[mod].vadjust = defaultOptions.font[mod].vadjust * Math.round(ratio); - } else if (groupOptions.font && - groupOptions.font.hasOwnProperty('vadjust')) { - this.fontOptions[mod].vadjust = groupOptions.font.vadjust; - } else { - this.fontOptions[mod].vadjust = this.fontOptions.vadjust; - } + if (opt.hasOwnProperty(property)) { + return opt[property]; + } + + return null; + }; + + + let mods = [ 'bold', 'ital', 'boldital', 'mono' ]; + for (const mod of mods) { + let modOptions = this.fontOptions[mod]; + let modDefaults = defaultOptions.font[mod]; + + let optionsFontMod; + if (options.font) { + optionsFontMod = options.font[mod]; + } + + if (typeof optionsFontMod === 'string') { + let modOptionsArray = optionsFontMod.split(" "); + modOptions.size = modOptionsArray[0].replace("px",""); + modOptions.face = modOptionsArray[1]; + modOptions.color = modOptionsArray[2]; + modOptions.vadjust = this.fontOptions.vadjust; + modOptions.mod = modDefaults.mod; + } else { + + // We need to be crafty about loading the modded fonts. We want as + // much 'natural' versatility as we can get, so a simple global + // change propagates in an expected way, even if not stictly logical. + + // face: We want to capture any direct settings and overrides, but + // fall back to the base font if there aren't any. We make a + // special exception for mono, since we probably don't want to + // sync to a the base font face. + modOptions.face = + getP(options , mod, 'face') || + getP(groupOptions, mod, 'face') || + (mod === 'mono'? modDefaults.face:null ) || + getP(groupOptions, null, 'face') || + this.fontOptions.face + ; + + // color: this is handled just like the face, except for specific default for 'mono' + modOptions.color = + getP(options , mod, 'color') || + getP(groupOptions, mod, 'color') || + getP(groupOptions, null, 'color') || + this.fontOptions.color + ; + + // mod: this is handled just like the face, except we never grab the + // base font's mod. We know they're in the defaultOptions, and unless + // we've been steered away from them, we use the default. + modOptions.mod = + getP(options , mod, 'mod') || + getP(groupOptions, mod, 'mod') || + getP(groupOptions, null, 'mod') || + modDefaults.mod + ; + + + // It's important that we size up defaults similarly if we're + // using default faces unless overriden. We want to preserve the + // ratios closely - but if faces have changed, all bets are off. + let ratio; + + // NOTE: Following condition always fails, because modDefaults + // has no explicit font property. This is deliberate, see + // var's 'NodesHandler.defaultOptions.font[mod]'. + // However, I want to keep the original logic while refactoring; + // it appears to be working fine even if ratio is never set. + // TODO: examine if this is a bug, fix if necessary. + // + if ((modOptions.face === modDefaults.face) && + (this.fontOptions.face === defaultOptions.font.face)) { + + ratio = this.fontOptions.size / Number(defaultOptions.font.size); } - this.fontOptions[mod].size = Number(this.fontOptions[mod].size); - this.fontOptions[mod].vadjust = Number(this.fontOptions[mod].vadjust); + + + modOptions.size = + getP(options , mod, 'size') || + getP(groupOptions, mod, 'size') || + (ratio? modDefaults.size * ratio: null) || // Scale the mod size using the same ratio + getP(groupOptions, null, 'size') || + this.fontOptions.size + ; + + modOptions.vadjust = + getP(options , mod, 'vadjust') || + getP(groupOptions, mod, 'vadjust') || + (ratio? modDefaults.vadjust * Math.round(ratio): null) || // Scale it using the same ratio + this.fontOptions.vadjust + ; + } + + modOptions.size = Number(modOptions.size); + modOptions.vadjust = Number(modOptions.vadjust); } }