webgme
Version:
Web-based Generic Modeling Environment
261 lines (219 loc) • 9.31 kB
JavaScript
/*globals define, $, WebGMEGlobal, unescape*/
/*jshint browser: true*/
/**
* @author kecso / https://github.com/kecso
*/
define([
'ejs',
'js/Constants',
'text!assets/decoratorSVGList.json'
], function (ejs, CONSTANTS, DecoratorSVGIconList) {
'use strict';
var SVG_CACHE = {},
BASEDIR = CONSTANTS.ASSETS_DECORATOR_SVG_FOLDER;
/**
* The function checks if the input string is a potential svg string or svg template string (and not a simple path)
* @param {string} text - the string to check
* @return {boolean} Returns if the checked text can be used as an svg string or template
*/
function isSvg(text) {
if (DecoratorSVGIconList.indexOf(text) > -1 || WebGMEGlobal.gmeConfig.client.allowUserDefinedSVG !== true) {
return false;
}
text = text || '';
// As this method only helps with distinguishing between a url-path and svg/ejs text we simply check
// if there are any tags in the text (as the char '<' must be URL-encoded it should not be in any paths).
return text.indexOf('<') > -1;
//TODO we try our best to remove the ejs portions without actual rendering, but that might not help...
// Removing ejs brackets doesn't mean the left over part is a valid svg
// and $(text).is('svg') logs errors for empty attributes etc.
// text = text.split('<%');
// for (var i = 0; i < text.length; i += 1) {
// text[i] = text[i].replace(/^(.|\n)*%>/g, '');
// }
// text = text.join('');
//
// try {
// result = $(text).is('svg');
// } catch (e) {
// result = false;
// }
//
// return result;
}
function getSvgFileContent(svgFilePath) {
var content = null;
if (SVG_CACHE[svgFilePath]) {
content = SVG_CACHE[svgFilePath];
} else {
// get the svg from the server in SYNC mode, may take some time
$.ajax(svgFilePath, {async: false})
.done(function (data) {
if (svgFilePath.indexOf('.ejs') === svgFilePath.length - '.ejs'.length) {
SVG_CACHE[svgFilePath] = data;
content = SVG_CACHE[svgFilePath];
} else if (svgFilePath.indexOf('.svg') === svgFilePath.length - '.svg'.length) {
var svgElements = $(data).find('svg');
if (svgElements.length > 0) {
SVG_CACHE[svgFilePath] = $(data).find('svg').first().prop('outerHTML');
content = SVG_CACHE[svgFilePath];
}
}
})
.fail(function (/*resp, status, err*/) {
});
}
return content;
}
/**
* Returns the uri for embedding the svg inside an img element. If the stored registry is an embedded
* svg or ejs, the content will be rendered and a data link generated.
* @param {GMENode} clientNodeObj - The target node where we will gather the asset
* @param {string} registryId - The name of the registry entry that holds the svg asset which
* can be either an svg template string or a path of the svg file
* @return {string} The generated string should be used as the src attribute of an img tag without any modification
*/
function getSvgUri(clientNodeObj, registryId) {
var data = clientNodeObj.getRegistry(registryId);
if (typeof data === 'string' && data.length > 0) {
if (isSvg(data) === true) {
try {
data = ejs.render(data, clientNodeObj);
if ($(data)[0].tagName !== 'svg') {
data = $(data).find('svg').first().prop('outerHTML');
}
return 'data:image/svg+xml;base64,' + window.btoa(unescape(encodeURIComponent(data)));
} catch (e) {
return null;
}
} else if (DecoratorSVGIconList.indexOf(data) > -1) {
return BASEDIR + data;
} else {
return null;
}
}
return null;
}
/**
* The function retrieves a sting that represents the svg asset pointed by the parameters
* @param {GMENode} clientNodeObj - The target node where we will look for the asset.
* @param {string} registryId - The name of the registry that contains the asset.
* @return {string|null} The rendered or downloaded svg string which can be used to create elements
*/
function getSvgContent(clientNodeObj, registryId) {
var data = clientNodeObj.getRegistry(registryId);
if (typeof data === 'string' && data.length > 0) {
if (isSvg(data)) {
try {
data = ejs.render(data, clientNodeObj);
if ($(data)[0].tagName !== 'svg') {
data = $(data).find('svg').first().prop('outerHTML');
}
return data;
} catch (e) {
return null;
}
} else if (data.indexOf('.svg') === data.length - '.svg'.length) {
return getSvgFileContent(BASEDIR + data);
} else {
return null;
}
}
return null;
}
/**
* The function creates an svg element pointed by the parameters
* @param {GMENode} clientNodeObj - The target client node object.
* @param {string} registryId - The name of the registry that holds the asset
* @return {object|null} The generated DOM element or null if no svg was found
*/
function getSvgElement(clientNodeObj, registryId) {
var html = getSvgContent(clientNodeObj, registryId);
if (html === null) {
return null;
}
return $(html);
}
/**
* The function is able to retrieve the unrendered or rendered svg asset
* @param {string} data - The svg string or svg template string
* @param {GMENode} clientNodeObj - The target client node to use for rendering
* @param {boolean} doRender - If true the data will be rendered as an ejs template
* @param {boolean} doUri - If true, the rendered result will be translated into base64 string to use as
* src in img tags
* @return {string|object|null} If null returned, than either the rendering was faulty or the input
* data is not an svg.
*/
function getRawSvgContent(data, clientNodeObj, doRender, doUri) {
if (typeof data === 'string' && data.length > 0) {
if (isSvg(data)) {
} else {
data = getSvgFileContent(BASEDIR + data);
}
if (doRender === true) {
try {
data = ejs.render(data, clientNodeObj);
} catch (e) {
return null;
}
if ($(data)[0].tagName !== 'svg') {
data = $(data).find('svg').first().prop('outerHTML');
}
if (doUri === true) {
data = $(data).data = 'data:image/svg+xml;base64,' +
window.btoa(unescape(encodeURIComponent(data)));
} else {
data = $(data);
}
}
return data;
}
return null;
}
/**
* The function can check if the ejs template do generate an svg.
* @param {string} templateString - The string to test.
* @param {GMENode} clientNodeObj - The target node object
* @return {error|null} Returns the ejs error if something goes wrong or null otherwise.
*/
function testSvgTemplate(templateString, clientNodeObj) {
var svgContent;
if (WebGMEGlobal.gmeConfig.client.allowUserDefinedSVG !== true) {
return new Error('Not allowed to run or test unsafe script templates.');
}
try {
svgContent = ejs.render(templateString, clientNodeObj);
if ($(svgContent).is('svg') === false) {
throw new Error('Rendered template is not a proper svg.');
}
} catch (e) {
return e;
}
return null;
}
function sanitizeSvgForEdge($el) {
// FIX: For edge browser - which completely crashes if the xmlns:xlink doesn't exit
// FIX: when xlink:href is defined.
var tmpEl = $('<div>'),
sanitizedEl;
tmpEl.append($el);
sanitizedEl = $(tmpEl.html());
sanitizedEl.find('use').each(function () {
var useEl = $(this);
if (useEl.attr('xlink:href') && !useEl.attr('xmlns:xlink')) {
useEl.attr('xmlns:xlink', 'http://www.w3.org/1999/xlink');
}
});
return sanitizedEl;
}
return {
getSvgUri: getSvgUri,
getSvgContent: getSvgContent,
getSvgElement: getSvgElement,
//
getRawSvgContent: getRawSvgContent,
isSvg: isSvg,
testSvgTemplate: testSvgTemplate,
sanitizeSvgForEdge: sanitizeSvgForEdge,
};
});