Skip to content

Commit 00bf372

Browse files
committed
Upgrade JSXGraph to the latest version and fix the graphtool for that.
The latest version of JXSGraph is 1.12.2. However, that version (and all versions after 1.11.1) have an issue with tab order when keyboard events are enabled. Basically, it is impossible to use shift-tab to progress in reverse in the tab order. See jsxgraph/jsxgraph#773. So to work around that I had to override the board's `keyDownListener` method with one that does not call `preventDefault` on a keydown event that comes from a tab key being used. Another thing that is a bit annoying with versions 1.11.1 and later is that you now have to set the tabindex on elements that are not fixed yourself. By default they set the tabindex to -1, which means they are not in the tab order. So `gt.definingPointAttributes` is now a function, and if it is called with `gt.isStatic` true, a tabindex of -1 is used, but if `gt.isStatic` is false, then a tabindex of 0 is used (and so those points will be keyboard focusable).
1 parent bcebe4a commit 00bf372

File tree

13 files changed

+132
-22
lines changed

13 files changed

+132
-22
lines changed

htdocs/js/GraphTool/circletool.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@
188188
const center = this.center;
189189
delete this.center;
190190

191-
center.setAttribute(gt.definingPointAttributes);
191+
center.setAttribute(gt.definingPointAttributes());
192192
center.on('down', () => gt.onPointDown(center));
193193
center.on('up', () => gt.onPointUp(center));
194194

htdocs/js/GraphTool/cubictool.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
constructor(point1, point2, point3, point4, solid) {
1414
for (const point of [point1, point2, point3, point4]) {
15-
point.setAttribute(gt.definingPointAttributes);
15+
point.setAttribute(gt.definingPointAttributes());
1616
if (!gt.isStatic) {
1717
point.on('down', () => gt.onPointDown(point));
1818
point.on('up', () => gt.onPointUp(point));

htdocs/js/GraphTool/graphtool.js

Lines changed: 112 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ window.graphTool = (containerId, options) => {
3939
underConstructionFixed: JXG.palette.red // defined to be '#d55e00'
4040
};
4141

42-
gt.definingPointAttributes = {
42+
gt.definingPointAttributes = () => ({
4343
size: 3,
4444
fixed: false,
4545
highlight: true,
@@ -49,8 +49,9 @@ window.graphTool = (containerId, options) => {
4949
fillColor: gt.color.point,
5050
highlightStrokeWidth: 1,
5151
highlightStrokeColor: gt.color.focusCurve,
52-
highlightFillColor: gt.color.pointHighlight
53-
};
52+
highlightFillColor: gt.color.pointHighlight,
53+
tabindex: gt.isStatic ? -1 : 0
54+
});
5455

5556
gt.options = options;
5657
gt.snapSizeX = options.snapSizeX ? options.snapSizeX : 1;
@@ -255,6 +256,113 @@ window.graphTool = (containerId, options) => {
255256
gt.board.highlightInfobox = (_x, _y, el) => gt.board.highlightCustomInfobox('', el);
256257

257258
if (!gt.isStatic) {
259+
// This is a mess to work around an issue with JSXGraph versions 1.11.1 or later. Their keyDownListener
260+
// calls preventDefault on the keydown event when shift-tab is pressed. That prevents keyboard focus from
261+
// moving backward in the tab order. So this removes the JSXGraph keyboard event handlers, then overrides
262+
// the board's keyDownListener with essentially the same code with the exception that when the tab key is
263+
// pressed, preventDefault is not called. Then the keyboard event listeners are added back, using this
264+
// keydownListener.
265+
gt.board.removeKeyboardEventHandlers();
266+
gt.board.keyDownListener = function (evt) {
267+
const id_node = evt.target.id;
268+
let done = true;
269+
270+
if (!this.attr.keyboard.enabled || id_node === '') return false;
271+
272+
const doc = this.containerObj.shadowRoot || document;
273+
if (doc.activeElement) {
274+
if (doc.activeElement.tagName === 'INPUT' || doc.activeElement.tagName === 'textarea') return false;
275+
}
276+
277+
const id = id_node.replace(this.containerObj.id + '_', '');
278+
const el = this.select(id);
279+
280+
if (
281+
(JXG.evaluate(this.attr.keyboard.panshift) && evt.shiftKey) ||
282+
(JXG.evaluate(this.attr.keyboard.panctrl) && evt.ctrlKey)
283+
) {
284+
const doZoom = JXG.evaluate(this.attr.zoom.enabled) === true;
285+
if (evt.keyCode === 38) this.clickUpArrow();
286+
else if (evt.keyCode === 40) this.clickDownArrow();
287+
else if (evt.keyCode === 37) this.clickLeftArrow();
288+
else if (evt.keyCode === 39) this.clickRightArrow();
289+
else if (doZoom && evt.keyCode === 171) this.zoomIn();
290+
else if (doZoom && evt.keyCode === 173) this.zoomOut();
291+
else if (doZoom && evt.keyCode === 79) this.zoom100();
292+
else done = false;
293+
} else if (!evt.shiftKey && !evt.ctrlKey) {
294+
let dx = JXG.evaluate(this.attr.keyboard.dx) / this.unitX;
295+
let dy = JXG.evaluate(this.attr.keyboard.dy) / this.unitY;
296+
if (JXG.exists(el.visProp)) {
297+
if (
298+
JXG.exists(el.visProp.snaptogrid) &&
299+
el.visProp.snaptogrid &&
300+
el.evalVisProp('snapsizex') &&
301+
el.evalVisProp('snapsizey')
302+
) {
303+
const res = el.getSnapSizes();
304+
dx = res[0];
305+
dy = res[1];
306+
} else if (
307+
JXG.exists(el.visProp.attracttogrid) &&
308+
el.visProp.attracttogrid &&
309+
el.evalVisProp('attractordistance') &&
310+
el.evalVisProp('attractorunit')
311+
) {
312+
let sX = 1.1 * el.evalVisProp('attractordistance');
313+
let sY = sX;
314+
if (el.evalVisProp('attractorunit') === 'screen') {
315+
sX /= this.unitX;
316+
sY /= this.unitX;
317+
}
318+
dx = Math.max(sX, dx);
319+
dy = Math.max(sY, dy);
320+
}
321+
}
322+
323+
let dir;
324+
if (evt.keyCode === 38) dir = [0, dy];
325+
else if (evt.keyCode === 40) dir = [0, -dy];
326+
else if (evt.keyCode === 37) dir = [-dx, 0];
327+
else if (evt.keyCode === 39) dir = [dx, 0];
328+
else done = false;
329+
330+
if (
331+
dir &&
332+
el.isDraggable &&
333+
el.visPropCalc.visible &&
334+
((this.geonextCompatibilityMode &&
335+
(JXG.isPoint(el) || el.elementClass === Const.OBJECT_CLASS_TEXT)) ||
336+
!this.geonextCompatibilityMode) &&
337+
!el.evalVisProp('fixed')
338+
) {
339+
this.mode = this.BOARD_MODE_DRAG;
340+
if (JXG.exists(el.coords)) {
341+
const actPos = el.coords.usrCoords.slice(1);
342+
dir[0] += actPos[0];
343+
dir[1] += actPos[1];
344+
el.setPosition(JXG.COORDS_BY_USER, dir);
345+
this.updateInfobox(el);
346+
} else {
347+
this.displayInfobox(false);
348+
el.setPositionDirectly(Const.COORDS_BY_USER, dir, [0, 0]);
349+
}
350+
351+
this.triggerEventHandlers(['keymove', 'move'], [evt, this.mode]);
352+
el.triggerEventHandlers(['keydrag', 'drag'], [evt]);
353+
this.mode = this.BOARD_MODE_NONE;
354+
}
355+
} else if (evt.key === 'Tab') {
356+
done = false;
357+
}
358+
359+
this.update();
360+
361+
if (done && JXG.exists(evt.preventDefault)) evt.preventDefault();
362+
return done;
363+
};
364+
gt.board.addKeyboardEventHandlers();
365+
258366
gt.graphContainer.tabIndex = -1;
259367
gt.board.containerObj.tabIndex = -1;
260368

@@ -798,7 +906,7 @@ window.graphTool = (containerId, options) => {
798906
const point = gt.board.create('point', [gt.snapRound(x, gt.snapSizeX), gt.snapRound(y, gt.snapSizeY)], {
799907
snapSizeX: gt.snapSizeX,
800908
snapSizeY: gt.snapSizeY,
801-
...gt.definingPointAttributes
909+
...gt.definingPointAttributes()
802910
});
803911
point.setAttribute({ snapToGrid: true });
804912
if (!gt.isStatic) {

htdocs/js/GraphTool/intervaltools.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -454,7 +454,8 @@
454454
highlightStrokeWidth: 3,
455455
highlightStrokeColor: gt.color.pointHighlightDarker,
456456
// highlightFillColor is gt.color.pointHighlight if not included.
457-
highlightFillColor: gt.color.pointHighlightDarker
457+
highlightFillColor: gt.color.pointHighlightDarker,
458+
tabindex: gt.isStatic ? -1 : 0
458459
};
459460
}
460461

htdocs/js/GraphTool/linetool.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -188,7 +188,7 @@
188188
const point1 = this.point1;
189189
delete this.point1;
190190

191-
point1.setAttribute(gt.definingPointAttributes);
191+
point1.setAttribute(gt.definingPointAttributes());
192192
point1.on('down', () => gt.onPointDown(point1));
193193
point1.on('up', () => gt.onPointUp(point1));
194194

htdocs/js/GraphTool/parabolatool.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -237,7 +237,7 @@
237237
const vertex = this.vertex;
238238
delete this.vertex;
239239

240-
vertex.setAttribute(gt.definingPointAttributes);
240+
vertex.setAttribute(gt.definingPointAttributes());
241241
vertex.on('down', () => gt.onPointDown(vertex));
242242
vertex.on('up', () => gt.onPointUp(vertex));
243243

htdocs/js/GraphTool/pointtool.js

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,8 @@
2222
strokeColor: gt.color.curve,
2323
fixed: gt.isStatic,
2424
highlightStrokeColor: gt.color.underConstruction,
25-
highlightFillColor: gt.color.pointHighlight
25+
highlightFillColor: gt.color.pointHighlight,
26+
tabindex: gt.isStatic ? -1 : 0
2627
})
2728
);
2829

htdocs/js/GraphTool/quadratictool.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
constructor(point1, point2, point3, solid) {
1414
for (const point of [point1, point2, point3]) {
15-
point.setAttribute(gt.definingPointAttributes);
15+
point.setAttribute(gt.definingPointAttributes());
1616
if (!gt.isStatic) {
1717
point.on('down', () => gt.onPointDown(point));
1818
point.on('up', () => gt.onPointUp(point));

htdocs/js/GraphTool/quadrilateral.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
constructor(point1, point2, point3, point4, solid) {
1414
for (const point of [point1, point2, point3, point4]) {
15-
point.setAttribute(gt.definingPointAttributes);
15+
point.setAttribute(gt.definingPointAttributes());
1616
if (!gt.isStatic) {
1717
point.on('down', () => gt.onPointDown(point));
1818
point.on('up', () => gt.onPointUp(point));

htdocs/js/GraphTool/sinewavetool.js

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@
1212

1313
constructor(shiftPoint, periodPoint, amplitudePoint, solid) {
1414
for (const point of [shiftPoint, periodPoint, amplitudePoint]) {
15-
point.setAttribute(gt.definingPointAttributes);
15+
point.setAttribute(gt.definingPointAttributes());
1616
if (!gt.isStatic) {
1717
point.on('down', () => gt.onPointDown(point));
1818
point.on('up', () => gt.onPointUp(point));

0 commit comments

Comments
 (0)