スマホ操作時、トップを通ると選択範囲が動かない
要望に飛ばすべき?bsahd.icon
要望飛ばしサンクスtakker.icon
2024-05-09直ったって!!takker.icon
朗報cFQ2f7LRuLYP.icon
とりまこのページで動作確認しました。直ってそうtakker.icon
Scrapbox mobileでトップページを通るとreloadするまで範囲変更できないバグ
発生条件・原因不明
reloadで解決します
今回はこっち基素.icon
文字列をダブルタップしてセレクトボタンを押したときに動かなくなることに気づくことがある
今度remote debugして挙動を調べてみますtakker.icon
2024-05-05調査
範囲変更できないケースで指を動かすと、次のエラーが大量に現れる
code:error
index.js:2 Uncaught TypeError: Cannot read properties of null (reading 'lines')
at PointerEvent.getCursorPoint (index.js:2:557141)
at PointerEvent.nearestCursorPosition (index.js:2:557268)
at PointerEvent.onTouchMove (index.js:2:560751)
at HTMLDivElement.wrapper (index.js:2:2429884)
at HTMLDivElement.dispatch (index.js:2:2040313)
at be.handle (index.js:2:2038121)
at HTMLDivElement.sentryWrapped (index.js:2:113900)
PointerEventを調べる
code:PointerEvent.js
class PointerEvent extends j.Component {
constructor(i);
getLines() {
return this.mobileLines
}
getCursorPoint(i) {
var v = (0,
W.default)(this.getLines().lines()).offset();
return (0,
pe.calcCursorPoint)(i, {
offset: v
})
}
nearestCursorPosition(i);
focusAndSelectAll(i);
setSelectionRange(i);
componentDidMount();
componentDidUpdate();
componentWillUnmount();
resetSwipeCursor(i);
reset();
onTouchStart(i);
onTouchMove(i);
onTouchMoveLines(i);
onTouchEnd(i);
onMouseDown(i);
onMouseMove(i);
onMouseUp(i);
onClick(i);
onDoubleMouseDown(i);
onTrippleMouseDown(i);
onResize();
render() {
var i = this.props.children;
return j.default.createElement("div", {
onMouseDown: this.onMouseDown,
onMouseMove: this.onMouseMove,
onMouseUp: this.onMouseUp,
onClick: this.onClick
}, j.default.createElement(ie.default, _extends({
ref: i=>{
this.mobileLines = i
}
}, i.props)), j.default.createElement(ae.default, null))
}
}
(一部のmethods定義は略した)
this.mobileLinesがnullになってしまっているということらしい
mobileLinesがコード中に登場するのは、上記コードにある2箇所のみ
とくに代入操作に限ればie.defaultのrefしかない
breakpointを仕掛けて調べると、this.mobileLinesにはLines | nullが代入されている
<div>のonTouchMoveにlistenerが登録されていないように見えるが、stack traceから推測するに、Reactの内部処理で自動でtouchmove時に呼び出されるよう設定されているものと思われる
黒魔術の塊だったのですぐには解読できない
ie.defaultを調べる
コードをたどると、Linesというclass componentがie.defaultだとわかる
code:Lines.js
class Lines extends j.Component {
static get propTypes();
shouldComponentUpdate(i);
lines() {
return this.refs.lines
}
render() {
for (var i = (0,
ee.default)(this.props.lines, {
cursorLine: this.props.cursorVisible && this.props.cursorPosition.line
var Y, le, ce = iW, de = !ce.codeBlock && (0, ie.isEmptyLine)(ce) || !X.default.PageHistory.isEnable ? !X.default.Page.lastAccessed || ce.updated > X.default.Page.lastAccessed : !!X.default.Page.prevSnapshotCreated && ce.updated > X.default.Page.prevSnapshotCreated;
if (null !== (Y = ce.codeBlock) && void 0 !== Y && Y.end && "mermaid", "mmd".includes(null === (le = ce.codeBlock) || void 0 === le ? void 0 : le.lang)) { for (var fe = [], pe = W; pe > 0; pe--) {
if (!be.codeBlock || be.codeBlock.start)
break;
fe.unshift(be.text),
be.codeBlock.hasCursor || (be.unread && (de = be.unread),
be.updated > ce.updated && (ce.updated = be.updated))
}
ce.codeBlock.mermaid = fe.join("\n")
}
var ye = !(!ce.codeBlock && (0,
ie.isEmptyLine)(ce) || !X.default.PageHistory.isEnable) && (!!X.default.Page.nextSnapshotLineIds && !X.default.Page.nextSnapshotLineIds.includes(ce.id))
, _e = ce.updated > X.default.Page.loaded
, we = this.props.cursorVisible && v === ce.id
, xe = this.props.permalinkLine === ce.id;
_.push(j.default.createElement(Z.default, {
key: ce.id,
id: ce.id,
userId: ce.userId,
email: ce.email,
updated: ce.updated,
unread: de,
updatedAfterLoad: _e,
willDeleteNext: ye,
isCursorLine: we,
titleLine: 0 === W,
permalinkLine: xe,
cli: ce.cli,
helpfeel: ce.helpfeel,
codeBlock: ce.codeBlock,
tableBlock: ce.tableBlock,
numberList: ce.numberList,
formulaLine: ce.formulaLine,
quoteLine: ce.quoteLine,
section: ce.section,
numberOfImages: ce.numberOfImages,
isSnapshot: this.props.isSnapshot,
displayStyle: this.props.displayStyle,
rtl: !ce.codeBlock && !ce.tableBlock && (0,
ae.isRTLText)(ce.text),
enableTranslation: this.props.enableTranslation
}, ce.text))
}
return j.default.createElement("div", {
className: "lines",
ref: "lines"
}, _)
}
}
(一部のmethods定義は略した)
refに文字列"lines"を入れる記法が不明takker.icon
こう書くと、例えばLinesではthis.refs.linesでdiv.linesを取得できるようになる
ごめんなさい、当方で調べられるのはここまでですtakker.icon
Linesが代入されない条件が不明
選択範囲操作が有効な状態でも、Linesとnullが交互に高速に代入されている状況を観測した
re-renderしまくってる?
PCではトップページを経由しても選択範囲変更が正常に働くのに、mobileだと働かなくなる理由が不明
cf. PointerEventはPC/mobile双方で使われる共通プログラム
ここまでの情報をまとめてshokai.iconさんに報告すれば、なにか進展があるかも……!
以降はtwitter民に報告任せた
helpのコミュニティでいいんじゃないかなぁ基素.icon
一応流しておくかー基素.icon
ありがたやtakker.icon
forum-jpに書いてくれたbsahd.iconさんもありがとう
なんかすごい。
お疲れ様です基素.iconyuyuko.icon