Tidy up chunky theme, add theme name autocomplete [#17]

This commit is contained in:
David Evans 2017-11-06 21:46:40 +00:00
parent f6f557bcd7
commit 2cb34c273c
9 changed files with 119 additions and 50 deletions

View File

@ -14,7 +14,7 @@
form-action 'none';
">
<title>Sequence Diagram</title>
<title>Readme Image Generator</title>
<link rel="icon" href="favicon.png">
<link rel="stylesheet" href="styles/readme_images.css">

View File

@ -109,6 +109,9 @@ define([
const code = new CodeMirror(container, {
value,
mode: 'sequence',
globals: {
themes: this.renderer.getThemeNames(),
},
lineNumbers: true,
showTrailingSpace: true,
extraKeys: {

View File

@ -24,7 +24,11 @@ defineDescribe('Interface', ['./Interface'], (Interface) => {
agents: [],
stages: [],
});
renderer = jasmine.createSpyObj('renderer', ['render', 'svg']);
renderer = jasmine.createSpyObj('renderer', [
'render',
'svg',
'getThemeNames',
]);
renderer.svg.and.returnValue(document.createElement('svg'));
container = jasmine.createSpyObj('container', ['appendChild']);
exporter = jasmine.createSpyObj('exporter', ['getSVGURL']);

View File

@ -17,6 +17,8 @@
return o;
}
const PNG_RESOLUTION = 4;
const FAVICON_SRC = (
'theme chunky\n' +
'define ABC as A, DEF as B\n' +
@ -47,7 +49,7 @@
results.push({
file: 'favicon.png',
code: FAVICON_SRC,
height: 64,
size: {width: 16, height: 16},
});
return results;
}
@ -61,8 +63,6 @@
}
}
const PNG_RESOLUTION = 4;
/* jshint -W072 */ // Allow several required modules
requirejs([
'sequence/Parser',
@ -91,7 +91,7 @@
status.appendChild(statusText);
document.body.appendChild(status);
function renderSample({file, code, height}) {
function renderSample({file, code, size}) {
const renderer = new Renderer({themes});
const exporter = new Exporter();
@ -124,11 +124,11 @@
const parsed = parser.parse(code);
const sequence = generator.generate(parsed);
renderer.render(sequence);
let resolution = PNG_RESOLUTION;
if(height) {
resolution = height / renderer.height;
if(size) {
renderer.width = size.width;
renderer.height = size.height;
}
exporter.getPNGURL(renderer, resolution, (url) => {
exporter.getPNGURL(renderer, PNG_RESOLUTION, (url) => {
raster.setAttribute('src', url);
downloadPNG.setAttribute('href', url);
});

View File

@ -1,4 +1,4 @@
define(() => {
define(['core/ArrayUtilities'], (array) => {
'use strict';
const TRIMMER = /^([ \t]*)(.*)$/;
@ -32,6 +32,26 @@ define(() => {
};
}
function getGlobals({global, prefix = '', suffix = ''}, globals) {
const identified = globals[global];
if(!identified) {
return [];
}
return identified.map((item) => (prefix + item + suffix));
}
function populateGlobals(suggestions, globals = {}) {
for(let i = 0; i < suggestions.length;) {
if(typeof suggestions[i] === 'object') {
const identified = getGlobals(suggestions[i], globals);
array.mergeSets(suggestions, identified);
suggestions.splice(i, 1);
} else {
++ i;
}
}
}
function getHints(cm, options) {
const cur = cm.getCursor();
const token = cm.getTokenAt(cur);
@ -52,6 +72,8 @@ define(() => {
comp = comp.concat(token.state.knownAgent);
}
populateGlobals(comp, cm.options.globals);
const ranges = makeRanges(cm, cur.line, from, token.end);
let selfValid = false;
const list = (comp

View File

@ -26,11 +26,21 @@ define(['core/ArrayUtilities'], (array) => {
',': {type: 'operator', suggest: true, then: {'': 1}},
'\n': end,
}};
const agentListToEnd = {type: 'variable', suggest: 'Agent', then: {
const agentListToText = {type: 'variable', suggest: 'Agent', then: {
'': 0,
',': {type: 'operator', suggest: true, then: {'': 1}},
':': {type: 'operator', suggest: true, then: {'': textToEnd}},
}};
const agentList2ToText = {type: 'variable', suggest: 'Agent', then: {
'': 0,
',': {type: 'operator', suggest: true, then: {'': agentListToText}},
':': CM_ERROR,
}};
const singleAgentToText = {type: 'variable', suggest: 'Agent', then: {
'': 0,
',': CM_ERROR,
':': {type: 'operator', suggest: true, then: {'': textToEnd}},
}};
const agentToOptText = {type: 'variable', suggest: 'Agent', then: {
'': 0,
':': {type: 'operator', suggest: true, then: {
@ -46,12 +56,12 @@ define(['core/ArrayUtilities'], (array) => {
suggest: [side + ' of ', side + ': '],
then: {
'of': {type: 'keyword', suggest: true, then: {
'': agentListToEnd,
'': agentListToText,
}},
':': {type: 'operator', suggest: true, then: {
'': textToEnd,
}},
'': agentListToEnd,
'': agentListToText,
},
};
}
@ -122,7 +132,17 @@ define(['core/ArrayUtilities'], (array) => {
'': textToEnd,
}},
'theme': {type: 'keyword', suggest: true, then: {
'': textToEnd,
'': {
type: 'string',
suggest: {
global: 'themes',
suffix: '\n',
},
then: {
'': 0,
'\n': end,
},
},
}},
'terminators': {type: 'keyword', suggest: true, then: {
'none': {type: 'keyword', suggest: true, then: {}},
@ -166,17 +186,17 @@ define(['core/ArrayUtilities'], (array) => {
}},
'note': {type: 'keyword', suggest: true, then: {
'over': {type: 'keyword', suggest: true, then: {
'': agentListToEnd,
'': agentListToText,
}},
'left': makeSideNote('left'),
'right': makeSideNote('right'),
'between': {type: 'keyword', suggest: true, then: {
'': agentListToEnd,
'': agentList2ToText,
}},
}},
'state': {type: 'keyword', suggest: 'state over ', then: {
'over': {type: 'keyword', suggest: true, then: {
'': agentListToEnd,
'': singleAgentToText,
}},
}},
'text': {type: 'keyword', suggest: true, then: {
@ -204,6 +224,9 @@ define(['core/ArrayUtilities'], (array) => {
}
function cmGetVarSuggestions(state, previous, current) {
if(typeof current.suggest === 'object' && current.suggest.global) {
return [current.suggest];
}
if(
typeof current.suggest !== 'string' ||
previous.suggest === current.suggest

View File

@ -589,6 +589,12 @@ define([
this.sizer.detach();
}
getThemeNames() {
return (Array.from(this.themes.keys())
.filter((name) => (name !== ''))
);
}
getAgentX(name) {
return this.agentInfos.get(name).x;
}

View File

@ -24,13 +24,18 @@ define([
function getArrowShort(theme) {
const arrow = theme.connect.arrow;
const h = arrow.height / 2;
const w = arrow.width;
const join = arrow.attrs['stroke-linejoin'] || 'miter';
const t = arrow.attrs['stroke-width'] * 0.5;
const lineStroke = theme.agentLineAttrs['stroke-width'] * 0.5;
if(join === 'round') {
return lineStroke + t;
} else {
const h = arrow.height / 2;
const w = arrow.width;
const arrowDistance = t * Math.sqrt((w * w) / (h * h) + 1);
return lineStroke + arrowDistance;
}
}
class Connect extends BaseComponent {
separation({agentNames, label}, env) {

View File

@ -4,7 +4,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
const LINE_HEIGHT = 1.3;
const SETTINGS = {
titleMargin: 10,
titleMargin: 12,
outerMargin: 5,
agentMargin: 8,
actionMargin: 5,
@ -40,6 +40,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
'fill': 'none',
'stroke': '#000000',
'stroke-width': 3,
'stroke-linecap': 'round',
},
},
bar: {
@ -48,6 +49,8 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
'stroke': '#000000',
'stroke-width': 3,
'height': 4,
'rx': 2,
'ry': 2,
},
},
fade: {
@ -60,7 +63,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
},
connect: {
loopbackRadius: 6,
loopbackRadius: 8,
lineAttrs: {
'solid': {
'fill': 'none',
@ -71,7 +74,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
'fill': 'none',
'stroke': '#000000',
'stroke-width': 3,
'stroke-dasharray': '4, 2',
'stroke-dasharray': '10, 4',
},
},
arrow: {
@ -79,13 +82,14 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
height: 12,
attrs: {
'fill': '#000000',
'stroke-width': 0,
'stroke-linejoin': 'miter',
'stroke': '#000000',
'stroke-width': 3,
'stroke-linejoin': 'round',
},
},
label: {
padding: 6,
margin: {top: 2, bottom: 1},
margin: {top: 2, bottom: 3},
attrs: {
'font-family': 'sans-serif',
'font-size': 8,
@ -100,10 +104,10 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
},
mask: {
padding: {
top: 0,
left: 3,
right: 3,
bottom: 1,
top: 1,
left: 5,
right: 5,
bottom: 3,
},
},
},
@ -116,28 +120,28 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
boxAttrs: {
'fill': 'none',
'stroke': '#000000',
'stroke-width': 1.5,
'rx': 2,
'ry': 2,
'stroke-width': 4,
'rx': 5,
'ry': 5,
},
section: {
padding: {
top: 3,
bottom: 2,
bottom: 4,
},
mode: {
padding: {
top: 1,
left: 3,
right: 3,
bottom: 0,
top: 2,
left: 5,
right: 5,
bottom: 1,
},
boxAttrs: {
'fill': '#FFFFFF',
'stroke': '#000000',
'stroke-width': 3,
'rx': 2,
'ry': 2,
'stroke-width': 2,
'rx': 3,
'ry': 3,
},
labelAttrs: {
'font-family': 'sans-serif',
@ -149,7 +153,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
},
label: {
padding: {
top: 1,
top: 2,
left: 5,
right: 3,
bottom: 0,
@ -165,8 +169,8 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
separator: {
attrs: {
'stroke': '#000000',
'stroke-width': 1.5,
'stroke-dasharray': '4, 2',
'stroke-width': 2,
'stroke-dasharray': '5, 3',
},
},
},
@ -187,12 +191,13 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
},
'note': {
margin: {top: 0, left: 5, right: 5, bottom: 0},
padding: {top: 5, left: 5, right: 10, bottom: 5},
padding: {top: 3, left: 3, right: 10, bottom: 3},
overlap: {left: 10, right: 10},
boxRenderer: SVGShapes.renderNote.bind(null, {
'fill': '#FFFFFF',
'stroke': '#000000',
'stroke-width': 1,
'stroke-width': 2,
'stroke-linejoin': 'round',
}, {
'fill': 'none',
'stroke': '#000000',
@ -206,12 +211,12 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
},
'state': {
margin: {top: 0, left: 5, right: 5, bottom: 0},
padding: {top: 7, left: 7, right: 7, bottom: 7},
padding: {top: 5, left: 7, right: 7, bottom: 5},
overlap: {left: 10, right: 10},
boxRenderer: SVGShapes.renderBox.bind(null, {
'fill': '#FFFFFF',
'stroke': '#000000',
'stroke-width': 1,
'stroke-width': 3,
'rx': 10,
'ry': 10,
}),
@ -225,6 +230,7 @@ define(['core/ArrayUtilities', 'svg/SVGShapes'], (array, SVGShapes) => {
titleAttrs: {
'font-family': 'sans-serif',
'font-weight': 'bolder',
'font-size': 20,
'line-height': LINE_HEIGHT,
'text-anchor': 'middle',