LoginSignup
3
2

More than 5 years have passed since last update.

codemirrorのlint error/warningをモバイルでも表示する

Posted at

CodeMirrorのlintによるエラーとワーニング表示があります

スクリーンショット 2018-03-24 19.12.17.png

これを使っていたのですが,マウスオーバーで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

そもそもスマホでコードを書きたいって需要はどのくらいあるんだろう・・・?

3
2
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
3
2