This app provides monitoring and information features for the common freifunk user and the technical stuff of a freifunk community.
Code base is taken from a TUM Practical Course project and added here to see if Freifunk Altdorf can use it.
https://www.freifunk-altdorf.de
You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
203 lines
5.0 KiB
203 lines
5.0 KiB
var Class = require('../../core/class'); |
|
var Path = require('../../core/path'); |
|
var SVGParser = require('./core'); |
|
var Font = require('../../shapes/font'); |
|
|
|
var parse = SVGParser.prototype.parse; |
|
|
|
var matchFontURL = /url\(['"\s]*([^\)]*?)['"\s]*\)\s+format\(['"]?svg['"]?\)/i; |
|
|
|
var trimFontFamily = /^['"\s]+|['"\s]+$|,.*$/g; |
|
|
|
var fillFaceAttributes = function(element, face){ |
|
var attributes = element.attributes; |
|
for (var i = 0, l = attributes.length; i < l; i++){ |
|
var attribute = attributes[i]; |
|
if (!(attribute.nodeName in face)){ |
|
face[attribute.nodeName] = attribute.nodeValue; |
|
} |
|
} |
|
}; |
|
|
|
SVGParser.implement({ |
|
|
|
parse: function(element, styles){ |
|
if (element.documentElement && element != this.fontDocument){ |
|
this.fontDocument = element; |
|
this.findFonts(element); |
|
} |
|
return parse.apply(this, arguments); |
|
}, |
|
|
|
findFonts: function(document){ |
|
var fonts = this.fonts || (this.fonts = {}); |
|
var root = document.documentElement, node = root; |
|
treewalker: while (node){ |
|
if (node.nodeType == 1 && node.nodeName == 'font-face'){ |
|
this.fontFace(node); |
|
} |
|
if (node.firstChild){ |
|
node = node.firstChild; |
|
} else { |
|
while (!node.nextSibling){ |
|
node = node.parentNode; |
|
if (!node || node == root) break treewalker; |
|
} |
|
node = node.nextSibling; |
|
} |
|
} |
|
|
|
if (this.findCSS){ |
|
var rules = this.findCSS(document).cssRules; |
|
for (var i = 0, l = rules.length; i < l; i++){ |
|
var rule = rules[i]; |
|
if (rule.fontFace){ |
|
var url = matchFontURL.exec(rule.style.src); |
|
if (url) this.fontURL(document, url[1], rule.style); |
|
} |
|
} |
|
} |
|
}, |
|
|
|
fontFace: function(element){ |
|
var face = {}; |
|
fillFaceAttributes(element, face); |
|
if (element.parentNode.nodeName == 'font') this.font(element.parentNode, face); |
|
var node = element.firstChild; |
|
while (node){ |
|
if (node.nodeName == 'font-face-src'){ |
|
node = node.firstChild; |
|
continue; |
|
} |
|
if (node.nodeName == 'font-face-uri'){ |
|
var url = node.getAttribute('xlink:href'); |
|
this.fontURL(element.ownerDocument, url, face); |
|
} |
|
node = node.nextSibling; |
|
} |
|
}, |
|
|
|
fontURL: function(document, url, face){ |
|
if (!face['font-family']) return; |
|
var pendingFonts = this.pendingFonts || (this.pendingFonts = {}); |
|
var family = face['font-family'].replace(trimFontFamily, ''); |
|
var callbacks = pendingFonts[family] = []; |
|
this.findByURL(document, url, function(font){ |
|
delete pendingFonts[family]; |
|
if (font){ |
|
var f = this.font(font, face); |
|
for (var i = 0, l = callbacks.length; i < l; i++) |
|
callbacks[i].call(this, f); |
|
} |
|
}); |
|
}, |
|
|
|
findFont: function(styles, callback){ |
|
var family = styles['font-family'].replace(trimFontFamily, ''); |
|
var callbacks = this.pendingFonts && this.pendingFonts[family]; |
|
if (callbacks){ |
|
callbacks.push(callback); |
|
} else if (this.fonts){ |
|
callback.call(this, this.fonts[family]); |
|
} else { |
|
callback.call(this, null); |
|
} |
|
}, |
|
|
|
font: function(element, face){ |
|
var glyphs = {}, font = { face: face, glyphs: glyphs }; |
|
|
|
var w = element.getAttribute('horiz-adv-x'); |
|
if (w) font.w = parseInt(w, 10); |
|
|
|
var node = element.firstChild; |
|
while (node){ |
|
switch(node.nodeName){ |
|
case 'font-face': |
|
fillFaceAttributes(node, face); |
|
break; |
|
case 'missing-glyph': |
|
case 'glyph': |
|
var glyph = {}, |
|
code = node.nodeName == 'missing-glyph' ? 'missing' : node.getAttribute('unicode'), |
|
w = node.getAttribute('horiz-adv-x'), |
|
d = node.getAttribute('d'); |
|
if (!code) break; |
|
if (w) glyph.w = parseInt(w, 10); |
|
|
|
if (d){ |
|
// Flip path |
|
var path = new FlippedVMLPathAtNormalPrecision(d); |
|
glyph.d = path.toVML().substr(1); |
|
} |
|
glyphs[code] = glyph; |
|
break; |
|
// TODO: Kerning |
|
} |
|
node = node.nextSibling; |
|
} |
|
|
|
var units = face['units-per-em']; |
|
|
|
if (isNaN(units)) face['units-per-em'] = units = 1000; |
|
|
|
if (face.ascent == null) face.ascent = face.descent == null ? 0.8 * units : units - face.descent; |
|
if (face.descent == null) face.descent = face.ascent - units; |
|
|
|
var family = face['font-family']; |
|
if (!family) return; |
|
face['font-family'] = family = family.replace(trimFontFamily, ''); |
|
|
|
var fonts = this.fonts || (this.fonts = {}); |
|
if (face.ascent) face.ascent = +face.ascent; |
|
if (face.descent) face.descent = +face.descent; |
|
fonts[family] = font; |
|
if (this.MODE.Font) |
|
this.MODE.Font.register(font); |
|
else |
|
Font.register(font); |
|
return font; |
|
} |
|
|
|
}); |
|
|
|
var round = Math.round; |
|
|
|
var FlippedVMLPathAtNormalPrecision = Class(Path, { |
|
|
|
initialize: function(path){ |
|
this.reset(); |
|
if (path){ |
|
this.push(path); |
|
} |
|
}, |
|
|
|
onReset: function(){ |
|
this.path = []; |
|
}, |
|
|
|
onMove: function(sx, sy, x, y){ |
|
this.path.push('m', round(x), -round(y)); |
|
}, |
|
|
|
onLine: function(sx, sy, x, y){ |
|
this.path.push('l', round(x), -round(y)); |
|
}, |
|
|
|
onBezierCurve: function(sx, sy, p1x, p1y, p2x, p2y, x, y){ |
|
this.path.push('c', |
|
round(p1x), -round(p1y), |
|
round(p2x), -round(p2y), |
|
round(x), -round(y) |
|
); |
|
}, |
|
|
|
onClose: function(){ |
|
this.path.push('x'); |
|
}, |
|
|
|
toVML: function(){ |
|
return this.path.join(' '); |
|
} |
|
|
|
});
|
|
|