CodeMirrorのlintによるエラーとワーニング表示があります
これを使っていたのですが,マウスオーバーでtooltipが表示されるので,マウスのないスマホではエラーがあるのはわかるけど,何がエラーかわからない という状況になりました.
それでは困るので,マークをタップ(というか行番号付近をタップ)した時に,tooltipを表示するようにしてみました.
適当な部分をタップすると消えます.
##仕組み
CodeMirrorのtouchendイベントで,マークをタップしたらそこに疑似マウスオーバーイベントを発生させることでtooltipを出す ということをしています.
tooltipをきちんと自分で生成して表示するところまでやれば,疑似マウスオーバーイベントは不要なのですが,
どうもこのtooltipの機能はcodemirrorと密接になっているようで,
その部分だけを取り出すことができなかったため,疑似イベントで対応しています.
(もちろんコピペしたらできますが,同じコードが複数箇所にあるのは好きではないので....)
touchendイベント自体がスマホじゃないと発生しないので,スマホのときだけ動作します.
PCの場合は通常通りマウスオーバーで表示されます.
##コード
CodeMirror.on(cm.display.scroller, "touchend", function (e) {
let touch = cm.display.activeTouch;
let date = new Date;
if (touch && touch.left != null &&
!touch.moved && date - touch.start < 300) {
//エディタの何処かをsingle tapした
if (!touch.prev) {
//行に変換するならこれ
var pos = cm.coordsChar(touch, "page");
//gutterの範囲判定
if(touch.left < Math.floor(cm.display.gutters.getBoundingClientRect().right)){
showLintTooltip(pos.line);
return;
}
}
}
//hide tooltip
if(currentTooptipTarget) {
dispatchMouseEvent(currentTooptipTarget, "mouseout", 0, 0);
currentTooptipTarget = null;
}
});
let currentTooptipTarget = null ;
function showLintTooltip(line){
let markers = jsEditor.state.lint.marked;
let info = jsEditor.lineInfo(line);
for (let marker of markers) {
if (marker.lines[0].lineNo() === line) {
//need to tooltip
let element = info.gutterMarkers["CodeMirror-lint-markers"];
if (element) {
let rect = element.getBoundingClientRect();
console.log(rect);
if(currentTooptipTarget == element){
//hide tooltip
dispatchMouseEvent(element, "mouseout", rect.x, rect.y);
currentTooptipTarget = null;
}else {
//hide tooltip
if(currentTooptipTarget) {
dispatchMouseEvent(currentTooptipTarget, "mouseout", rect.x, rect.y);
}
//show tooltip
dispatchMouseEvent(element, "mouseover", rect.left+rect.width/2, rect.top+rect.height/2);
currentTooptipTarget = element;
}
return;
}
}
}
}
function dispatchMouseEvent(elm, type,x,y){
var mouseMoveEvent = document.createEvent("MouseEvents");
mouseMoveEvent.initMouseEvent(
type, //event type : click, mousedown, mouseup, mouseover, mousemove, mouseout.
true, //canBubble
false, //cancelable
window, //event's AbstractView : should be window
1, // detail : Event's mouse click count
x, // screenX
y, // screenY
x, // clientX
y, // clientY
false, // ctrlKey
false, // altKey
false, // shiftKey
false, // metaKey
0, // button : 0 = click, 1 = middle button, 2 = right button
null // relatedTarget : Only used with some event types (e.g. mouseover and mouseout). In other cases, pass null.
);
elm.dispatchEvent(mouseMoveEvent);
}
##注意点
上のコードで表示はできるようになったものの,iOS(safari)のcssにバグ(?)があるようで,position:fixed
での位置指定が上手く行かないようでした.(縦方向にずれる)
その場合はcssでposition:absolute
でゴニョゴニョしてあげるとちょうどよくなると思います.
なお,Androidでは(自分の試した限り)問題なく動いています.
##その他
iosでcodemirrorを使う場合,日本語入力が変になる問題があるので,こっちの対応も必須になると思います(参考にさせていただきました)
https://qiita.com/ttakuru88/items/e363267772cacf4c1fa2
そもそもスマホでコードを書きたいって需要はどのくらいあるんだろう・・・?