src/script/interpreter/uistate.js
/*
msc {
hscale="1.2";
html [label="index.html", textbgcolor="#ddf"]
, ui [label="mscgenui.js"]
, msc [label="xuparser.js"]
, render [label="mscrender.js"]
, utls [label="mscrenderutensils.js"]
, doc [label="window.document", textbgcolor="#ddf"];
html => ui [label="render"];
ui =>> doc [label="get input from textarea"];
doc >> ui [label="text"];
ui =>> msc [label="parse(text)"];
--- [label="[hunky dory]", linecolor="green"];
ui << msc [label="AST"];
ui => render [label="renderAST(AST, text)"];
render => utls [label="low level helpers"];
utls => doc [label="all kinds of dom manipulation"];
render => doc [label="all kinds of dom manipulation"];
render note render [label="move dom manipulation down?"];
--- [label="[parse error]", linecolor="red"];
ui << msc [label="exception"];
ui =>> ui [label="show error"];
ui =>> html [label="show error"];
|||;
ui note msc [label="There's a parser for mscgen and a separate one for ms genny.\nFor simplicity only showning one.",
textbgcolor="#ffe"];
}
*/
/* eslint max-statements: 0 */
var xuparser = require('mscgenjs/dist/cjs/parse/xuparser')
var msgennyparser = require('mscgenjs/dist/cjs/parse/msgennyparser')
var renderast = require('mscgenjs/dist/cjs/render/graphics/renderast')
var ast2msgenny = require('mscgenjs/dist/cjs/render/text/ast2msgenny')
var ast2xu = require('mscgenjs/dist/cjs/render/text/ast2xu')
var maps = require('../utl/maps')
var $ = require('../utl/domutl')
var exporter = require('../utl/exporter')
var populateLists = require('./populate-lists')
var state = require('./state')
var gCodeMirror = {}
var gErrorCoordinates = {
line: 0,
column: 0
}
function requestRender () {
if (state.getAutoRender()) {
render(getSource(), state.getLanguage())
}
}
function getASTBare (pSource, pLanguage) {
if (pLanguage === 'msgenny') {
return msgennyparser.parse(pSource)
} else if (pLanguage === 'json') {
return JSON.parse(pSource)
} // we use the xu parser for both mscgen and xu:
return xuparser.parse(pSource)
}
function getAST (pLanguage, pSource) {
var lLanguage = pLanguage || state.getLanguage()
var lSource = pSource || getSource()
return getASTBare(lSource, lLanguage)
}
function clear () {
if (['mscgen', 'xu'].indexOf(state.getLanguage()) > -1) {
setSource('msc{\n \n}')
setCursorInSource(1, 3)
} else {
setSource('')
}
}
function renderSource (pAST, pLanguage) {
var lTargetSource = ''
if (pLanguage === 'msgenny') {
lTargetSource = ast2msgenny.render(pAST)
} else if (pLanguage === 'json') {
lTargetSource = JSON.stringify(pAST, null, ' ')
} else { // for rendering mscgen we use the xu renderer
lTargetSource = ast2xu.render(pAST)
}
return lTargetSource
}
function getSource () {
return gCodeMirror.getValue()
}
function setSource (pSource) {
gCodeMirror.setValue(pSource)
}
function setCursorInSource (pLine, pColumn) {
gCodeMirror.setCursor(pLine, pColumn)
gCodeMirror.focus()
}
function setLanguage (pLanguage) {
state.setLanguage(pLanguage)
gCodeMirror.setOption('mode', maps.language2Mode(pLanguage))
window.__language_mscgen.checked = false
window.__language_msgenny.checked = false
window.__language_json.checked = false
if (pLanguage === 'msgenny') {
window.__language_msgenny.checked = true
$.ss(window.__btn_more_color_schemes).hide()
window.__color_panel.style.width = '0'
} else if (pLanguage === 'json') {
window.__language_json.checked = true
$.ss(window.__btn_more_color_schemes).show()
} else /* "mscgen" === pLanguage || "xu" === pLanguage */{
window.__language_mscgen.checked = true
$.ss(window.__btn_more_color_schemes).show()
}
requestRender()
}
function handleRenderException (pException, pSource) {
if (pException.location) {
gErrorCoordinates.line = pException.location.start.line
gErrorCoordinates.column = pException.location.start.column
displayError(
'Line ' + pException.location.start.line + ', column ' +
pException.location.start.column + ': ' + pException.message,
'>>> ' + pSource.split('\n')[pException.location.start.line - 1] + ' <<<'
)
} else {
gErrorCoordinates.line = 0
gErrorCoordinates.column = 0
displayError(pException.message)
}
}
function render (pSource, pLanguage) {
preRenderReset()
try {
var lAST = getASTBare(pSource, pLanguage)
if (state.getDebug()) {
try {
window.history.replaceState(
{},
'',
exporter.toLocationString(
window.location,
pSource,
maps.correctLanguage(
lAST.meta.extendedFeatures,
pLanguage
),
state.getMirrorEntities(),
state.getNamedStyle()
)
)
} catch (e) {
// on chrome window.history.replaceState barfs when
// the interpreter runs from a file:// instead of
// from a server. This try/ catch is a crude way
// to handle that without breaking the rest of the flow
}
}
renderast.render(
lAST,
window,
'__svg',
{
source: state.getIncludeSource() ? pSource : null,
mirrorEntitiesOnBottom: state.getMirrorEntities(),
regularArcTextVerticalAlignment: state.getVerticalLabelAlignment(),
additionalTemplate: state.getNamedStyle()
}
)
if (lAST.entities.length > 0) {
showRenderSuccess(lAST.meta)
}
} catch (e) {
handleRenderException(e, pSource)
}
}
function preRenderReset () {
hideError()
$.ss(window.__output_controls_area).hide()
$.ss(window.__placeholder).show('flex')
$.ss(window.__svg).hide()
renderast.clean('__svg', window)
}
function showRenderSuccess (pMeta) {
$.ss(window.__output_controls_area).show()
$.ss(window.__placeholder).hide()
$.ss(window.__svg).show()
showExtendedArcTypeFeatures(pMeta)
showExtendedFeatures(pMeta)
state.setLanguage(maps.correctLanguage(pMeta.extendedFeatures, state.getLanguage()))
}
function showExtendedArcTypeFeatures (pMeta) {
if (pMeta && pMeta.extendedArcTypes === true) {
$.ss(window.__show_anim).hide()
} else {
$.ss(window.__show_anim).show()
}
}
function showExtendedFeatures (pMeta) {
if (pMeta && pMeta.extendedFeatures === true) {
$.ss(window.__xu_notify).show()
} else {
$.ss(window.__xu_notify).hide()
}
}
function setAutoRender (pAutoRender) {
state.setAutoRender(pAutoRender)
if (pAutoRender) {
window.__autorender.checked = true
$.ss(window.__btn_render).hide()
} else {
window.__autorender.checked = false
$.ss(window.__btn_render).show()
}
}
function hideError () {
$.ss(window.__error).hide()
window.__error_output.textContent = ''
window.__error_context.textContent = ''
}
function displayError (pError, pContext) {
$.ss(window.__error).show()
$.ss(window.__placeholder).hide()
window.__error_output.textContent = pError
window.__error_context.textContent = pContext
}
module.exports = {
init: function (pCodeMirror) {
gCodeMirror = pCodeMirror
setAutoRender(state.getAutoRender())
setLanguage(state.getLanguage())
populateLists.initSamples(state.getDebug())
populateLists.initNamedStyles()
if (window.__loading) {
window.__loading.outerHTML = ''
}
},
switchLanguage: function (pLanguage) {
var lAST = {}
try {
lAST = getAST()
if (lAST !== {}) {
setSource(renderSource(lAST, pLanguage))
}
} catch (e) {
// do nothing
}
setLanguage(pLanguage)
},
manipulateSource: function (pFunction) {
var lAST = {}
try {
lAST = getAST()
if (lAST !== {}) {
setSource(
renderSource(
pFunction(lAST),
state.getLanguage()
)
)
}
} catch (e) {
// do nothing
}
},
setSample: function (pURL) {
if (pURL === 'none' || !pURL) {
clear()
} else {
$.ajax(
pURL,
function onSuccess (pEvent) {
setLanguage(maps.classifyExtension(pURL))
setSource(pEvent.target.response)
},
function onError () {
setSource("# could not find or open '" + pURL + "'")
}
)
}
},
errorOnClick: function () {
setCursorInSource(gErrorCoordinates.line - 1, gErrorCoordinates.column - 1)
},
/**
* parses + renders the given source in the given language
* @type {string} source
* @type {string} language (one of mscgen, xu, msgenny or json)
*/
render,
/**
* parse + renders the current source in the current
* language if 'autorender' is on
*/
requestRender,
getAutoRender: state.getAutoRender,
setAutoRender,
getSource,
setSource,
getLanguage: state.getLanguage,
setLanguage,
getDebug: state.getDebug,
setDebug: function (pBoolean) {
state.setDebug(pBoolean)
if (state.getDebug()) {
$.doForAllOfClass('debug', function (pDomNode) {
$.ss(pDomNode).show()
})
}
},
getAST,
getLinkToInterpeter: state.getLinkToInterpreter,
setLinkToInterpeter: function (pBoolean) {
state.setLinkToInterpreter(pBoolean)
window.__link_to_interpreter.checked = pBoolean
},
setMirrorEntities: function (pBoolean) {
state.setMirrorEntities(pBoolean)
window.__option_mirror_entities.checked = pBoolean
},
getMirrorEntities: state.getMirrorEntities,
setIncludeSource: function (pBoolean) {
state.setIncludeSource(pBoolean)
window.__option_include_source.checked = pBoolean
},
getIncludeSource: state.getIncludeSource,
setNamedStyle: function (pStyle) {
window.__option_style_basic.checked = false
window.__option_style_inverted.checked = false
window.__option_style_grayscaled.checked = false
window.__option_style_fountainpen.checked = false
window.__option_style_lazy.checked = false
window.__option_style_cygne.checked = false
window.__option_style_pegasse.checked = false
window.__option_style_classic.checked = false
window.__option_style_noentityboxes.checked = false
var lOptionToCheck = document.getElementById('__option_style_' + pStyle)
if (lOptionToCheck) {
lOptionToCheck.checked = true
state.setNamedStyle(pStyle)
} else {
window.__option_style_basic.checked = true
state.setNamedStyle('basic')
}
},
getNamedStyle: state.getNamedStyle,
setVerticalLabelAlignment: function (pVerticalLabelAlignment) {
window.__option_vertical_label_alignment.value = pVerticalLabelAlignment
state.setVerticalLabelAlignment(pVerticalLabelAlignment)
},
getVerticalLabelAlignment: state.getVerticalLabelAlignment,
preRenderReset
}
/*
This file is part of mscgen_js.
mscgen_js is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
mscgen_js is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with mscgen_js. If not, see <http://www.gnu.org/licenses/>.
*/