Skip to content

Commit 8e646b4

Browse files
committed
Steps toward a better responsiveness for mobile version. Release 3.0.1
is nearly complete.
1 parent b58806e commit 8e646b4

18 files changed

Lines changed: 530 additions & 217 deletions

README.md

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -81,6 +81,10 @@ This software is available on the net [here](https://visualmatheditor.equatheque
8181
1. The user interface is somewhat different, but functionality is the same
8282
1. The Latex input area and the Formula output area are reversed for a better experience with mobile screen keyboards
8383
1. Navigation panels are used and dialogs, the side panels and the menus are moved out from the main screen to such panels
84+
1. Implemented swipe gestures to simplify navigation between panels: they are always processed on the title bars only
85+
1. Use swipe left and swipe right on the main panel to navigate to the appropriate side panels
86+
1. Use swipe left or swipe right to navigate back to the main panel
87+
1. Use swipe down to dismiss the side menu or the dialog wrapper panels
8488

8589
## Some Screenshots
8690

@@ -106,11 +110,19 @@ The symbol bar with button for the Katex Input Helper (Square Root symbol)
106110
- The persistence of custom equations can be damaged when a filter is active.
107111
- The *web* version of this app does work bad on *Firefox* and on mobile devices in that many dialogs are sized wrong.
108112
This does not appear on the *Chrome* browser on desktop.
109-
- The sub menu items of the mobile version do show icons with the default theme only.
110113
- The mobile version does regularly pop-up the screen keyboard. No mechanism is known to avoid this.
111114

112115
## Release Notes
113116

117+
### 3.0.1
118+
119+
- Bug fixing on the mobile version:
120+
- The icons of sub menu items are now fully visible
121+
- Improved the handling of themes and the start behavior, no more flickering of colors on the progress dialog
122+
- Implemented the menu item separators like those in the desktop version
123+
- Implemented swipe gestures to simplify navigation between panels
124+
- Improved *responsiveness* in the mobile version, especially the handling of orientation changes and the dimensions of dialogs
125+
114126
### 3.0.0
115127

116128
- Introduced a mobile version of the plug-in (experimental)

package-lock.json

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,6 @@
11
{
22
"name": "joplin-plugin-katex-input-helper",
3-
"version": "3.0.0",
3+
"version": "3.0.1",
44
"scripts": {
55
"dist": "webpack --env joplin-plugin-config=buildMain && webpack --env joplin-plugin-config=buildExtraScripts && npm run build-assets-prod && webpack --env joplin-plugin-config=createArchive",
66
"dist-with-doc": "webpack --env joplin-plugin-config=buildMain && webpack --env joplin-plugin-config=buildExtraScripts && npm run build-assets-prod && npm run build-docs && webpack --env joplin-plugin-config=createArchive",
@@ -32,6 +32,7 @@
3232
"@codemirror/view": "^6.40.0",
3333
"@joplin/lib": "^2.6.3",
3434
"@rollup/plugin-inject": "^5.0.5",
35+
"@types/hammerjs": "^2.0.46",
3536
"@types/jquery": "^3.5.32",
3637
"@types/jsdom": "^21.1.7",
3738
"@types/katex": "^0.16.7",
@@ -51,6 +52,7 @@
5152
"generate-file-webpack-plugin": "^1.0.1",
5253
"gh-pages": "6.1.0",
5354
"glob": "^8.0.3",
55+
"hammerjs": "^2.0.8",
5456
"handlebars": "^4.7.8",
5557
"html-loader": "^5.1.0",
5658
"html-webpack-plugin": "^5.6.3",

src/assets/js/dialog.ts

Lines changed: 66 additions & 60 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
import Hammer from 'hammerjs';
12
import './easyui';
23
import './sass/dialog.scss' assert { type: 'css' };
34

45
import { VKI_init } from './keyboard/keyboard';
56
import { FileHandler } from "./fileHandling";
7+
import { Versions } from "./versions";
68

79
import { inject } from 'inversify';
810
import {
@@ -15,8 +17,7 @@ import {
1517
IParser, parserId,
1618
IMath, mathId, ICodeMirror,
1719
IPanels, panelsId, matrixWindowId, unicodeWindowId, informationWindowId, moreDialogId, windowId, dialogId, dynamicPanelId,
18-
IMenus,
19-
menusId} from './interfaces';
20+
IMenus, menusId} from './interfaces';
2021

2122
let console: any;
2223
if (globalThis.console) console = globalThis.console; else console = { log: function(_: string) { }, error: function(_: string) { } };
@@ -300,6 +301,7 @@ export class KatexInputHelper implements IKatexInputHelper {
300301
*
301302
* @param from - body element of the new document
302303
* @param to - body selector of the old, original document
304+
*
303305
*/
304306
function transfer(from: HTMLElement, to: string) {
305307
$(to).html(from.innerHTML);
@@ -353,7 +355,7 @@ export class KatexInputHelper implements IKatexInputHelper {
353355
async initialise() {
354356

355357
let vme = this;
356-
this.versions = await import( /* webpackInclude: /\.json$/ */ './versions.json');
358+
this.versions = new Versions();
357359

358360
// Initialize is done lazily
359361
//this.parser.initialise();
@@ -366,7 +368,7 @@ export class KatexInputHelper implements IKatexInputHelper {
366368
await this.initialiseMobile(this.parameters.isMobile);
367369

368370
// IN QUESTION
369-
vme.initialiseCodeMirror();
371+
await vme.initialiseCodeMirror();
370372
this.localizer.subscribe(this.onLocaleChanged.bind(this));
371373
await this.localizer.initialiseLanguageChoice(this.localType); // Progress dialog uses localized text
372374
// NO ACTION on language choice dialog
@@ -423,40 +425,19 @@ export class KatexInputHelper implements IKatexInputHelper {
423425
panel.panel('resize', { height: `${part}%` });
424426
$(selector).layout('resize');
425427
}
426-
427-
/**
428-
* Queries the height of the south region.
429-
*/
430-
function getHeightFooter() {
431-
const heightFooter = $('.katex-mobile .southRegion').first().outerHeight();
432-
return heightFooter;
433-
}
434-
435-
/**
436-
* Determines the height of the center.
437-
*/
438-
function getHeightCenterVh(mobile: boolean = true) : string {
439-
const headerSelector = mobile ? '#introduction' : '#northRegion';
440-
const footerSelector = mobile ? '.katex-mobile .southRegion' : '.katex-desktop .southRegion';
441-
const padding = 5;
442-
const heightBody = $('body').outerHeight();
443-
const heightHeader = $(headerSelector).outerHeight() + 2 * padding;
444-
const heightFooter = $(footerSelector).outerHeight();
445-
const heightCenter = heightBody - heightHeader - heightFooter;
446-
const heightCenterVh = Math.floor(heightCenter * 100 / heightBody);
447-
448-
return `${heightCenterVh}vh`;
449-
}
450428

451429
// Intent: to restore original web page structure (required by Joplin plugin).
452430
// Here: the viewport
453-
// TODO: required?
431+
// TODO: required? CHECK FUNCTIONALITY WITHOUT THIS
432+
// It seems the functionality is given without this !!
433+
/*
454434
const content = $("body meta[name='viewport']").attr('content');
455435
if (content) {
456436
const html = `<meta name="viewport" content="${content}" ></meta>`;
457437
$("meta[name='viewport']").remove();
458438
$('html > head').append(html);
459439
}
440+
*/
460441

461442
// Here: the body content
462443
$('body').prepend($('#joplin-plugin-content > div'));
@@ -506,7 +487,7 @@ export class KatexInputHelper implements IKatexInputHelper {
506487
$("header:has(+ #westRegion) a.back, header:has(+ #eastRegion) a.back, header:has(+ #wrapperPanelMenu) a.back").on('click', function(_) {
507488
});
508489

509-
// TEST ... WORKING
490+
// Implements a handler for panel open events for the main panel.
510491
$('#myContainer').panel({
511492
fit: true,
512493
onOpen: function() {
@@ -515,6 +496,43 @@ export class KatexInputHelper implements IKatexInputHelper {
515496
}
516497
});
517498

499+
// Handles orientation changes
500+
screen.orientation.addEventListener('change', async function() {
501+
await inst.panels.refresh();
502+
});
503+
504+
/**
505+
* Installs a swipe handler for certain nav panels.
506+
*
507+
* @param from - selector of the origin window
508+
* @param dir - direction (left, right, down)
509+
* @param [to=''] - target panel, empty for switch back
510+
*/
511+
function navigate(from: string, dir: string, to: string = '') {
512+
const wnd = $(from)[0];
513+
const hammer = new Hammer(wnd);
514+
hammer.get('swipe').set({ direction: Hammer.DIRECTION_ALL });
515+
if (to === '') {
516+
hammer.on('swipedown', function(event: any) {
517+
event.preventDefault();
518+
$.mobile.back();
519+
inst.panels.closeOpen();
520+
});
521+
return;
522+
}
523+
hammer.on('swipe' + dir, function(event: any) {
524+
event.preventDefault();
525+
$.mobile.go(to, 'slide', dir);
526+
});
527+
}
528+
529+
navigate('div:has(#myContainer) header', 'left', '#eastRegion');
530+
navigate('div:has(#myContainer) header', 'right', '#westRegion');
531+
navigate('div:has(#eastRegion) header', 'right', '#myContainer');
532+
navigate('div:has(#westRegion) header', 'left', '#myContainer');
533+
navigate('div:has(#wrapperPanel) header', 'down', '');
534+
navigate('div:has(#wrapperPanelMenu) header', 'down', '');
535+
518536
defineProportions('#innerLayout', 'south', 50);
519537

520538
this.sidemenuData = this.getSidemenuData();
@@ -542,8 +560,12 @@ export class KatexInputHelper implements IKatexInputHelper {
542560
console.log(`Parsing with selector #${id}`);
543561
const data = $(`#${id} > div`).map(function(idx: number, dom) {
544562
console.log(`Found menu item : %O`, dom);
545-
if ($(this).hasClass('menu-line')) {
546-
return null;
563+
if ($(this).hasClass('menu-sep')) {
564+
return {
565+
id: '',
566+
text: '',
567+
iconCls: ''
568+
};
547569
}
548570
const span = $(this).find('span');
549571
let children = undefined;
@@ -580,6 +602,8 @@ export class KatexInputHelper implements IKatexInputHelper {
580602

581603
/**
582604
* Populates a side menu in a wrapper menu panel for reduced space.
605+
*
606+
* @param data - the data structure used to describe the menu
583607
*/
584608
populateSidemenu(data: any) {
585609
$('#sm').sidemenu({
@@ -588,6 +612,13 @@ export class KatexInputHelper implements IKatexInputHelper {
588612
multiple: false,
589613
onSelect: this.onMenuClick.bind(this)
590614
});
615+
616+
$('ul.sidemenu-tree span.tree-title').each(function(idx) { // set the css class for menu separator
617+
if ($(this).text() == '') {
618+
$(this).addClass('menu-sep');
619+
}
620+
})
621+
591622
$('#sm').sidemenu('expand');
592623
}
593624

@@ -635,9 +666,10 @@ export class KatexInputHelper implements IKatexInputHelper {
635666
* - change handler -> auto update of formula
636667
* - context menu binding
637668
*/
638-
initialiseCodeMirror() {
669+
async initialiseCodeMirror() {
639670
let vme = this;
640671
const codeMirrorEditor = this.codeMirrorEditor;
672+
await this.versions.init(codeMirrorEditor.version);
641673
// Reserved.
642674
const option = vme.platformInfo.isMobile ? 'contenteditable' : 'textarea'; // RESERVED
643675
try { codeMirrorEditor.setOption('inputStyle', option); } catch(e) {}
@@ -867,6 +899,7 @@ export class KatexInputHelper implements IKatexInputHelper {
867899
if (id in functions) {
868900
await functions[id]();
869901
} else {
902+
if (id === '' || item.text === '') { return; } // probably menu separator
870903
$.messager.show({ title: "<span class='rtl-title-withicon'>" + vme.getLocalText("INFORMATION") + "</span>", msg: item.text });
871904
}
872905
}
@@ -1314,36 +1347,9 @@ export class KatexInputHelper implements IKatexInputHelper {
13141347
*/
13151348
async updateInfo() {
13161349
let vme = this;
1317-
$('#tINFORMATIONS div[href]')
1318-
.each(function( _idx: number ) {
1319-
let href = $(this).attr('href');
1320-
let id = $(this).attr('id');
1321-
if (href.length <= 1) { // info html !
1322-
console.info(`Info dialog with : id : ${id}, href : ${href}`);
1323-
1324-
// Trial for Android
1325-
let newHref = `../information/${id}.html`; // lazily load html info
1326-
$(this).attr('href', newHref);
1327-
import(`../information/${id}.html`)
1328-
.then((mod) => { $(this).html(mod.default); });
1329-
}
1330-
});
1331-
13321350
await vme.parser.parseAsync('div[href]', 0, 100);
13331351
console.info(`Parse completed for : div[href]`);
13341352

1335-
$("#VMEversion").html(`
1336-
<table class="inline-table">
1337-
<tr><td><b> ${vme.versions.version} </b></td><td><b>Katex Input Helper / Visual Math Editor</b>, (This software)</td></tr>
1338-
<tr><td> ${vme.versions.katexVersion} </td><td>Katex</td></tr>
1339-
<tr><td> ${vme.codeMirrorEditor.version} </td><td>Code Mirror</td></tr>
1340-
<tr><td> ${vme.versions.VKI_version} </td><td>Virtual Keyboard</td></tr>
1341-
<tr><td> ${$.fn.jquery} </td><td>Jquery</td></tr>
1342-
<tr><td> ${vme.versions.easyuiVersion} </td><td>Jquery Easyui</td></tr>
1343-
<tr><td> ${vme.versions.colorPickerVersion} </td><td>Jquery Color Picker</td></tr>
1344-
<table>`);
1345-
$("#VMEdate").html((new Date()).getFullYear().toString());
1346-
13471353
// updates exactly 2 dialogs (see selectors)
13481354
// Necessary and additional ones required?
13491355
vme.math.inplaceUpdate('#tEQUATION div a.s[latex], #mSPECIAL_CHARACTER div a.s[latex]', true); // where and when to do that

src/assets/js/helpers.ts

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -110,7 +110,14 @@ export class Utilities implements IUtilities {
110110
* @param secondIcon - the text of the button
111111
*/
112112
regionToggler(btnId: string, layout: string, state: State) : any {
113-
return new RegionToggler(btnId, layout, state, this);
113+
if (this.regionTogglerInst == null) {
114+
this.regionTogglerInst = new RegionToggler(btnId, layout, state, this);
115+
}
116+
return this.regionTogglerInst;
117+
}
118+
119+
refreshRegionToggler() {
120+
this.regionTogglerInst.toggle();
114121
}
115122

116123
/**
@@ -126,6 +133,8 @@ export class Utilities implements IUtilities {
126133
containerToggler(btnId: string, uiId: string, startState: boolean) : any {
127134
return new ContainerToggler(btnId, uiId, startState, this);
128135
}
136+
137+
regionTogglerInst: any = null;
129138
}
130139

131140

0 commit comments

Comments
 (0)