Skip to content

Commit 4ed3044

Browse files
committed
Initial event implementations for maction
1 parent a5b231c commit 4ed3044

File tree

1 file changed

+163
-1
lines changed

1 file changed

+163
-1
lines changed

mathjax3-ts/output/chtml/Wrappers/maction.ts

Lines changed: 163 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -38,6 +38,8 @@ export type ActionHandler<N, T, D> = (node: CHTMLmaction<N, T, D>) => void;
3838
export type ActionMap = Map<string, ActionHandler<any, any, any>>;
3939
export type ActionPair = [string, ActionHandler<any, any, any>];
4040

41+
export type EventHandler = (event: Event) => void;
42+
export type EventList = [any, string, EventHandler];
4143

4244
/*****************************************************************/
4345
/*
@@ -80,6 +82,7 @@ export class CHTMLmaction<N, T, D> extends CHTMLWrapper<N, T, D> {
8082
public static Actions = new Map([
8183
['toggle', node => {
8284
node.adaptor.setAttribute(node.chtml, 'toggle', node.node.attributes.get('selection') as string);
85+
node.setEventHandler('click', node.toggleClick);
8386
}],
8487

8588
['tooltip', node => {
@@ -92,6 +95,8 @@ export class CHTMLmaction<N, T, D> extends CHTMLWrapper<N, T, D> {
9295
const box = node.html('mjx-tip');
9396
tip.toCHTML(box);
9497
node.adaptor.append(node.chtml, node.html('mjx-tool', {}, [box]));
98+
node.setEventHandler('mouseover', node.tooltipOver);
99+
node.setEventHandler('mouseout', node.tooltipOut);
95100
}
96101
}],
97102

@@ -101,13 +106,25 @@ export class CHTMLmaction<N, T, D> extends CHTMLWrapper<N, T, D> {
101106
if (tip.node.isKind('mtext')) {
102107
const text = (tip.node as TextNode).getText();
103108
node.adaptor.setAttribute(node.chtml, 'statusline', text);
109+
node.setEventHandler('mouseover', node.statusOver);
110+
node.setEventHandler('mouseout', node.statusOut);
104111
}
105112
}]
106113

107114
] as ActionPair[]);
108115

116+
/*************************************************************/
117+
118+
/*
119+
* Delays before posting or clearing a math tooltip
120+
*/
121+
public static postDelay = 600;
122+
public static clearDelay = 100;
123+
124+
/*************************************************************/
125+
109126
/*
110-
* The handler for the specified actiontype
127+
* The handler for the specified actiontype
111128
*/
112129
protected action: ActionHandler<N, T, D> = null;
113130

@@ -120,6 +137,8 @@ export class CHTMLmaction<N, T, D> extends CHTMLWrapper<N, T, D> {
120137
return this.childNodes[i] || this.wrap((this.node as MmlMaction).selected);
121138
}
122139

140+
/*************************************************************/
141+
123142
/*
124143
* @override
125144
*/
@@ -147,4 +166,147 @@ export class CHTMLmaction<N, T, D> extends CHTMLWrapper<N, T, D> {
147166
bbox.updateFrom(this.selected.getBBox());
148167
}
149168

169+
/*************************************************************/
170+
/*************************************************************/
171+
/*
172+
* Handle events for the actions
173+
*/
174+
175+
/*
176+
* Add an event handler to the output for this maction
177+
*/
178+
public setEventHandler(type: string, handler: EventHandler) {
179+
(this.chtml as any).addEventListener(type, handler.bind(this));
180+
}
181+
182+
/*************************************************************/
183+
/*
184+
* Handle statuline changes
185+
*/
186+
187+
/*
188+
* Change the selection and rerender the expression
189+
*/
190+
public toggleClick() {
191+
let selection = Math.max(1, (this.node.attributes.get('selection') as number) + 1);
192+
if (selection > this.childNodes.length) {
193+
selection = 1;
194+
}
195+
this.node.attributes.set('selection', selection);
196+
this.toggleRerender();
197+
}
198+
199+
/*
200+
* Rerender the complete expression and replace it in the document
201+
*/
202+
protected toggleRerender() {
203+
const html = this.getMathHTML();
204+
if (!html) return;
205+
const CHTML = this.factory.chtml;
206+
const node = CHTML.typeset(CHTML.math, CHTML.document);
207+
this.adaptor.replace(node, html);
208+
}
209+
210+
/*
211+
* @return{N} The html for the top-level mjx-chtml node for the expression
212+
*/
213+
protected getMathHTML() {
214+
let parent = this as CHTMLWrapper<N, T, D>;
215+
while (!parent.node.isKind('math')) {
216+
parent = parent.parent;
217+
if (!parent) return null;
218+
}
219+
return this.adaptor.parent(parent.chtml);
220+
}
221+
222+
/*************************************************************/
223+
/*
224+
* Handle tool tips containing math
225+
*/
226+
227+
/*
228+
* Timers for posting/clearing a math tooltip
229+
*/
230+
protected hoverTimer: number = null;
231+
protected clearTimer: number = null;
232+
233+
/*
234+
* clear the timers if any are active
235+
*/
236+
public clearTimers() {
237+
if (this.clearTimer) {
238+
clearTimeout(this.clearTimer);
239+
this.clearTimer = null;
240+
}
241+
if (this.hoverTimer) {
242+
clearTimeout(this.hoverTimer);
243+
this.hoverTimer = null;
244+
}
245+
}
246+
247+
/*
248+
* Handle a tooltip mousover event (start a timer to post the tooltip)
249+
*
250+
* @param{Event} event The mouseover event
251+
*/
252+
public tooltipOver(event: Event) {
253+
const delay = (this.constructor as typeof CHTMLmaction).postDelay;
254+
this.clearTimers();
255+
this.hoverTimer = setTimeout(((event:Event) => {
256+
const adaptor = this.adaptor;
257+
adaptor.setStyle(adaptor.lastChild(this.chtml) as N, 'display', 'block');
258+
}).bind(this), delay);
259+
event.stopPropagation();
260+
}
261+
262+
/*
263+
* Handle a tooltip mousout event (start a timer to remove the tooltip)
264+
*
265+
* @param{Event} event The mouseout event
266+
*/
267+
public tooltipOut(event: Event) {
268+
const delay = (this.constructor as typeof CHTMLmaction).clearDelay;
269+
this.clearTimers();
270+
this.clearTimer = setTimeout(((event: Event) => {
271+
const adaptor = this.adaptor;
272+
adaptor.setStyle(adaptor.lastChild(this.chtml) as N, 'display', '');
273+
}).bind(this), delay);
274+
event.stopPropagation();
275+
}
276+
277+
/*************************************************************/
278+
/*
279+
* Handle statuline changes
280+
*/
281+
282+
/*
283+
* Cached document title (where the status is shown)
284+
*/
285+
protected status: string = null;
286+
287+
/*
288+
* Set the document title to the status value
289+
*
290+
* @param{Event} event The mouseover event
291+
*/
292+
public statusOver(event: Event) {
293+
if (this.status === null) {
294+
this.status = document.title;
295+
document.title = this.adaptor.getAttribute(this.chtml, 'statusline');
296+
}
297+
event.stopPropagation();
298+
}
299+
300+
/*
301+
* Restore the document title to its original value
302+
*
303+
* @param{Event} event The mouseout event
304+
*/
305+
public statusOut(event: Event) {
306+
if (this.status) {
307+
document.title = this.status;
308+
this.status = null;
309+
}
310+
event.stopPropagation();
311+
}
150312
}

0 commit comments

Comments
 (0)