1. 背景0
◎非規範的[ `IE9^ua / `Firefox 6.0a2^ua ]は、 選択~内の任意な範囲oを許容し,この仕様が元々~~述べていたものに従う。 しかしながら,これは、 ~~無意味で不快な際どい事例を導くことに加え,[ 作者, 実装者, 仕様の書き手 ]三者とも それに~~対処する必要がある。 [ `Chrome 14 dev^ua / `Opera 11.11^ua ]は、 選択を積極的に正規化し,それを[ 空~要素やそれに類するもの ]の内側には居させなくするが、 これも作者から柔軟性を奪うので,不良な案に見える。 ◎ IE9 and Firefox 6.0a2 allow arbitrary ranges in the selection, which follows what this spec originally said. However, this leads to unpleasant corner cases that authors, implementers, and spec writers all have to deal with, and they don't make any real sense. Chrome 14 dev and Opera 11.11 aggressively normalize selections, like not letting them lie inside empty elements and things like that, but this is also viewed as a bad idea, because it takes flexibility away from authors.
よって,編集者は、 いくぶんの単純~化を許容しつつ作者をさほど拘束しない妥協を成すよう,仕様を変更した。 `論点@https://lists.w3.org/Archives/Public/public-whatwg-archive/2011Jun/0193.html$ を見よ。 基本的には、[ `選択$の`範囲o$sLの`境界点$の`~node$bpが、 `Document^I の子孫であって, `Element^I または `Text^I であり続ける ]よう,そうならなくなる何箇所かで例外を投出する。 【言い換えれば、`~live範囲o$ `DOM$r に課される拘束に従う。】 ◎ So I changed the spec to a made-up compromise that allows some simplification but doesn't constrain authors much. See discussion. Basically it would throw exceptions in some places to try to stop the selection from containing a range that had a boundary point other than an Element or Text node, or a boundary point that didn't descend from a Document.
(`以下略$) ◎ But this meant getRangeAt() had to start returning a copy, not a reference. Also, it would be prone to things failing weirdly in corner cases. Perhaps most significantly, all sorts of problems might arise when DOM mutations transpire, like if a boundary point's node is removed from its parent and the mutation rules would place the new boundary point inside a non-Text/Element node. And finally, the previously-specified behavior had the advantage of matching two major implementations, while the new behavior matched no one. So I changed it back. ◎ See bug 15470. IE9, Firefox 12.0a1, Chrome 17 dev, and Opera Next 12.00 alpha all make the range initially null.
【この訳に特有な表記規約】
◎表記記号原文に多数見られる過去~UA実装の互換性に関する情報は、 現況と乖離していると見受けられるので,この訳では大部分を省略する ( “(以下略)” と記された箇所)。 訳者が確認した限り、 現在の `Firefox^ua ( `Gecko^ua ), `Chrome^ua に関しては,ほぼ仕様に従っていると見受けられる。 (今や~supportされなくなった `IE^ua に関する注記も数多く含まれている。)
2. 定義
どの`文書$にも,それが`属する閲覧~文脈$ ~NEQ ~NULL ならば `選択@ と呼ばれる,一意な `Selection$I ~objが結付けられる。 `DOM$r `HTML$r ◎ Every document with a browsing context has a unique selection associated with it.
注記: これは、 ~HTML仕様による要件である。 (`以下略$) ◎ Note This is a requirement of the HTML spec. IE9 and Opera Next 12.00 alpha seem to follow it, while Firefox 12.0a1 and Chrome 17 dev seem not to. See Mozilla bug, WebKit bug.
この`選択$は、 `文書$を成す すべての内容から共有されるモノトスル (入子な`文書$は別として) — 文書~内に`編集中の~host$が在れば,それも含めて。 ◎ This one selection must be shared by all the content of the document (though not by nested documents), including any editing hosts in the document.
各 `選択$には、 `範囲o@sL が結付けられる — それは、[ ある`範囲o$†/ ~NULL ]であり, 初期~時は ~NULL になるモノトスル。 ◎ Each selection can be associated with a single range. When there is no range associated with the selection, the selection is empty. The selection must be initially empty.
【† この`範囲o$( `AbstractRange$I )は、 実質的には`~live範囲o$( `Range$I )になる — この仕様に定義される~APIは、 `範囲o$sLとして `Range^I ~objを返している (唯一の例外は、新たに追加された `getComposedRanges()$m )。 しかしながら, `§ ~DOM変異に対する応答-法@#responding-to-dom-mutations$では、 “`~live範囲o$であったかのように” ふるまうものと指定している。 なぜ,直に`~live範囲o$として定義しないのかは、 よくわからない。 】【 原文では、 `範囲o$sLは `DOM$r 用語の`範囲o$を直に指していて, “範囲oが結付けられ得る” と記されているが、 “結付けられない場合” を表現し易くするため、 この訳では, ~NULL もとり得る新たな用語として定義し直す。 それに伴い,原文における “結付けられない場合” を表す句 “`選択$は `空である@#dfn-empty@ ( `is empty^en )” も,直に “`選択$の`範囲o$sL ~EQ ~NULL” と記すことにする ( “空である” は、 意味論的に, “範囲oが`畳まれて$いる” ことと紛らわしいので)。 】
注記: `文書$の`選択$は、 `文書$ごとに一つだけ結付けられる~objなので、 `Document.open()@~HTMLdynamic#dom-document-open$c が~callされるときには新たな~objに置換される。 `~W3C~bug #15470@~W3Cbug/show_bug.cgi?id=15470$ を見よ。 (`以下略$) ◎ Note A document's selection is a singleton object associated with that document, so it gets replaced with a new object when Document.open() is called. See bug 15470. IE9 and Opera Next 12.00 alpha allow the user to reset the range to null after the fact by clicking somewhere; Firefox 12.0a1 and Chrome 17 dev do not. We follow Gecko/WebKit, because it lessens the chance of getRangeAt(0) throwing.
`選択$の`範囲o$sLは、 非 ~NULL になったなら — この仕様が他を要求するまで — 同じ~objであり続けるモノトスル。 ◎ Once a selection is associated with a given range, it must continue to be associated with that same range until this specification requires otherwise.
注記: 一例として,~DOMが範囲oの境界点を変化させるような仕方で変更されても,~scriptが`範囲o$sLの境界点を改変しても、 選択の`範囲o$sLは同じ~objであり続ける。 しかしながら,[ 利用者が選択を変更したか,~scriptが `addRange()$m を~callした ]場合、 この仕様の他所にて要求されるとおり,選択の`範囲o$sLは新たな`範囲o$になる。 ◎ Note For instance, if the DOM changes in a way that changes the range's boundary points, or a script modifies the boundary points of the range, the same range object must continue to be associated with the selection. However, if the user changes the selection or a script calls addRange(), the selection must be associated with a new range object, as required elsewhere in this specification.
`選択$の`範囲o$sLは[ ~NULL でない, かつ`畳まれて$いる ]場合、 ~caret位置は,`範囲o$sLの`始端$にあるモノトスル。 他の場合における~caret位置は、 この仕様では定義しない。 ~UAは、 ~caretを[ `範囲o$sLの始端, 終端, あるいは他所 ]のどこにするか裁定するときには,~platform規約に従うベキである。 ◎ If the selection's range is not null and is collapsed, then the caret position must be at that range's boundary point. When the selection is not collapsed, this specification does not define the caret position; user agents should follow platform conventions in deciding whether the caret is at the start of the selection, the end of the selection, or somewhere else.
各 `選択$には `方向@sL があり、[ `前方@i, `後方@i, `無方向@i ]いずれかをとる。 利用者が 1 個目の`境界点$ %A を指示してから, 2 個目のそれ %B を指示することにより (ある地点を~clickして別の地点へ~dragするなどにより), `選択$の`範囲o$sLを作成した場合、 初期~時の`方向$sLは,[ %A は %B `より後$i ならば `後方$i / %A は %B `より前$i ならば `前方$i / ~ELSE_ `無方向$i ]になるモノトスル。 `DOM$r ◎ Each selection has a direction: forwards, backwards, or directionless. If the user creates a selection by indicating first one boundary point of the range and then the other (such as by clicking on one point and dragging to another), and the first indicated boundary point is after the second, then the corresponding selection must initially be backwards. If the first indicated boundary point is before the second, then the corresponding selection must initially be forwards. Otherwise, it must be directionless.
`選択$の`範囲o$sLが~scriptにより — 例えば `selectNode()$m を介して — 変異したとしても、 当の`選択$の`方向$sLは,保全するモノトスル。 ◎ When the selection's range is mutated by scripts, e.g. via selectNode(node), direction of the selection must be preserved.
各 `選択$には `~anchor@sL ( `anchor^en ), `~focus@sL ( `focus^en )もある 【順に, “選択し始めた地点”, “選択し終えた地点” を表す】: ◎ Each selections also have an anchor and a focus.\
- `選択$の`範囲o$sL ~EQ ~NULL の場合、[ `~anchor$sL, `~focus$sL ]どちらも ~NULL を返すとする。 ◎ If the selection's range is null, its anchor and focus are both null.\
-
`選択$の`範囲o$sL ~NEQ ~NULL の場合、 `選択$の`方向$sLに応じて
- `前方$i ならば [ `~anchor$sLは`範囲o$sLの`始端$,`~focus$sLは`範囲o$sLの`終端$ ]を返すとする。
- 他の場合は[ `~anchor$sLは`範囲o$sLの`終端$, `~focus$sLは`範囲o$sLの`始端$ ]を返すとする。
注記: `選択$の[ `~anchor$sL, `~focus$sL ]は`文書~tree$内にあるとは限らない — それは、 同じ`文書$の`~shadow~tree$内にもあり得る。 ◎ Note anchor and focus of selection need not to be in the document tree. It could be in a shadow tree of the same document.
各[ `文書$/ `input$e 要素/ `textarea$e 要素 ]は、 `~selectionchange-ev~eventを~scheduleしたか@ を有する — それは、 真偽値であり,初期~時は ~F とする。 ◎ Each document, input element, and textarea element has a boolean has scheduled selectionchange event, which is initially false.
3. `Selection^I ~interface
`Selection$I ~interfaceは 各~文書に結付けられた`選択$とヤリトリする仕方を供する。 ◎ Selection interface provides a way to interact with the selection associated with each document.
[`Exposed$=Window] interface `Selection@I { readonly attribute `Node$I? `anchorNode$m; readonly attribute `unsigned long$ `anchorOffset$m; readonly attribute `Node$I? `focusNode$m; readonly attribute `unsigned long$ `focusOffset$m; readonly attribute `boolean$ `isCollapsed$m; readonly attribute `unsigned long$ `rangeCount$m; readonly attribute `DOMString$ `type$m; readonly attribute `DOMString$ `direction$m; `Range$I `getRangeAt$m(`unsigned long$ %index); `undefined$ `addRange$m(`Range$I %range); `undefined$ `removeRange$m(`Range$I %range); `undefined$ `removeAllRanges$m(); `undefined$ `empty$m(); `sequence$<`StaticRange$I> `getComposedRanges$m(optional `GetComposedRangesOptions$I %options = {}); `undefined$ `collapse$m(`Node$I? %node, optional `unsigned long$ %offset = 0); `undefined$ `setPosition$m(`Node$I? %node, optional `unsigned long$ %offset = 0); `undefined$ `collapseToStart$m(); `undefined$ `collapseToEnd$m(); `undefined$ `extend$m(`Node$I %node, optional `unsigned long$ %offset = 0); `undefined$ `setBaseAndExtent$m(`Node$I %anchorNode, `unsigned long$ %anchorOffset, `Node$I %focusNode, `unsigned long$ %focusOffset); `undefined$ `selectAllChildren$m(`Node$I %node); `undefined$ `modify$m(optional `DOMString$ %alter, optional `DOMString$ %direction, optional `DOMString$ %granularity); [`CEReactions$] `undefined$ `deleteFromDocument$m(); `boolean$ `containsNode$m(`Node$I %node, optional `boolean$ %allowPartialContainment = false); `stringifier$m; }; dictionary `GetComposedRangesOptions@I { `sequence$<`ShadowRoot$I> `shadowRoots@mb = []; };
`新たな範囲oを作成する@ ときは、 所与の ( `境界点$ %A, `境界点$ %B ) に対し,次を走らす:
- ( %始端, %終端 ) ~LET [ %A は %B `より前$i ならば ( %A, %B ) / ~ELSE_ ( %B, %A ) ]
- %範囲o ~LET 新たな`~live範囲o$ `DOM$r
- %範囲o の`境界点を設定する$( `始端^i, %始端 の`~node$bp, %始端 の`~offset$bp )
- %範囲o の`境界点を設定する$( `終端^i, %終端 の`~node$bp, %終端 の`~offset$bp )
- ~RET %範囲o
【 この~algoは、 原文の共通な記述を集約したものである。 これは、 所与の 2 つの境界点を,必要に応じて入れ替える。 】
◎ ↓`anchorNode@m 取得子手続きは:
- ~IF[ コレの`~anchor$sL ~NEQ ~NULL ]~AND[ コレの`~anchor$sLは`文書~tree$内に在る ] ⇒ コレの`~anchor$sLの`~node$bp
- ~RET ~NULL
`anchorOffset@m 取得子手続きは:
- ~IF[ コレの`~anchor$sL ~NEQ ~NULL ]~AND[ コレの`~anchor$sLは`文書~tree$内に在る ] ⇒ ~RET コレの`~anchor$sLの`~offset$bp
- ~RET 0
`focusNode@m 取得子手続きは:
- ~IF[ コレの`~focus$sL ~NEQ ~NULL ]~AND[ コレの`~focus$sLは`文書~tree$内に在る ] ⇒ コレの`~focus$sLの`~node$bp
- ~RET ~NULL
`focusOffset@m 取得子手続きは:
- ~IF[ コレの`~focus$sL ~NEQ ~NULL ]~AND[ コレの`~focus$sLは`文書~tree$内に在る ] ⇒ コレの`~focus$sLの`~offset$bp
- ~RET 0
`type@m 取得子手続きは:
- ~IF[ コレの`範囲o$sL ~NEQ ~NULL ]~AND[ コレの`~anchor$sLは`文書~tree$内に在る ]~AND[ コレの`~focus$sLは`文書~tree$内に在る ] ⇒ ~RET [ コレの`範囲o$sLは`畳まれて$いるならば `Caret^l / ~ELSE_ `Range^l ]
- ~RET `None^l
`getRangeAt(index)@m ~method手続きは: ◎ getRangeAt() method
- ~IF[ %index ~EQ 0 ]~AND[ コレの`範囲o$sL ~NEQ ~NULL ]~AND[ コレの`~anchor$sLは`文書~tree$内に在る ]~AND[ コレの`~focus$sLは`文書~tree$内に在る ] ⇒ ~RET コレの`範囲o$sL ◎ ↓
- ~THROW `IndexSizeError$E ◎ The method must throw an IndexSizeError exception if index is not 0, or if this is empty or either focus or anchor is not in the document tree.\ Otherwise, it must return a reference to (not a copy of) this's range.
`getRangeAt$test ◎ tests: 1
注記: この~methodは、 コレの`範囲o$sLが ~NULL にされない限り,後続な~callに対し同じ~objを返し続ける。 ◎ Note Thus subsequent calls of this method returns the same range object if nothing has removed this's range in the meantime. In particular, getSelection().getRangeAt(0) === getSelection().getRangeAt(0) evaluates to true if the selection is not empty.
`addRange(range)@m ~method手続きは: ◎ addRange() method • The method must follow these steps:
- ~IF[ %range の`始端~node$の`根$ ~NEQ コレを結付けている`文書$ ] ⇒ ~RET ◎ If the root of the range's boundary points are not the document associated with this, abort these steps.
- ~IF[ コレの`範囲o$sL ~NEQ ~NULL ]~AND[ コレの`~anchor$sLは`文書~tree$内に在る ]~AND[ コレの`~focus$sLは`文書~tree$内に在る ]【!rangeCount is not 0】 ⇒ ~RET ◎ If rangeCount is not 0, abort these steps.
- コレの`範囲o$sL ~SET %range ◎ Set this's range to range by a strong reference (not by making a copy).
注記: `範囲o$sLは参照として追加されるので、 この~methodに対する後続な~callは,同じ~objを返す。 他の何かが`選択$の`範囲o$sLを ~NULL にするか置換するまで、 `選択$が追加された後における,~scriptによる`範囲o$sLに対する変更を反映することになる。 特に,次の~codeを走らせた後には、 `選択$は, %a ではなく %b を包含することになる: ◎ Note Since range is added by reference, subsequent calls to getRangeAt(0) returns the same object, and any changes that a script makes to range after it is added must be reflected in the selection, until something else removes or replaces this's range. In particular, the selection will contain b as opposed to a after running the following code:
var %r = document.createRange(); %r.selectNode(%a); getSelection().addRange(%r); %r.selectNode(%b);
注記: (`以下略$) ◎ Note At Step 2, Chrome 58 and Edge 25 do nothing. Firefox 51 gives you a multi-range selection. At least they keep the exisiting range. ◎ At Step 3, Chrome 58 and Firefox 51 store a reference, as described here. Edge 25 stores a copy. Firefox 51 changes its selection if the range is modified.
`removeRange(range)@m ~method手続きは:
- ~IF[ コレの`範囲o$sL ~NEQ %range ] ⇒ ~THROW `NotFoundError$E
- コレの`範囲o$sL ~SET ~NULL
`empty()@m ~methodは、 `removeAllRanges()$m の別名であり,それと同じに挙動するモノトスル。 ◎ empty() method • The method must be an alias, and behave identically, to removeAllRanges().
`getComposedRanges(options)@m ~method手続きは: ◎ getComposedRanges() method
- %範囲o ~LET コレの`範囲o$sL ◎ ↓
- ~IF[ %範囲o ~EQ ~NULL ] ⇒ ~RET « »【!empty array】 ◎ If this is empty, return an empty array.
- %始端~node ~LET %範囲o の`始端~node$ ◎ Otherwise, let startNode be start node of the range associated with this,\
- %始端~offset ~LET %範囲o の`始端~offset$ ◎ and let startOffset be start offset of the range.
-
~WHILE 無条件:
- %~host ~LET %始端~node の`根$の`~host$
- ~IF[ %~host ~EQ ~NULL ] ⇒ ~BREAK
- %options[ "`shadowRoots$mb" ] を成す ~EACH( %~shadow根 ) に対し ⇒ ~IF[ %始端~node の`根$は %~shadow根 の`~shadowも含めた広義-先祖$である ] ⇒ ~BREAK
- %始端~offset ~SET %~host の`~index$
- %始端~node ~SET %~host の`親$
- ~IF[ %始端~node ~EQ ~NULL ] ⇒ ~BREAK
- %終端~node ~LET %範囲o の`終端~node$ ◎ Let endNode be end node of the range associated with this,\
- %終端~offset ~LET %範囲o の`終端~offset$ ◎ and let endOffset be end offset of the range.
-
~WHILE 無条件:
- %~host ~LET %終端~node の`根$の`~host$
- ~IF[ %~host ~EQ ~NULL ] ⇒ ~BREAK
- %options[ "`shadowRoots$mb" ] を成す ~EACH( %~shadow根 ) に対し ⇒ ~EACH( %~shadow根 ) に対し ⇒ ~IF[ %終端~node の`根$は %~shadow根 の`~shadowも含めた広義-先祖$である ] ⇒ ~BREAK
- %終端~offset ~SET %~host の`~index$ ~PLUS 1
- %終端~node ~SET %~host の`親$
- ~IF[ %終端~node ~EQ ~NULL ] ⇒ ~BREAK
- %新たな範囲o ~LET 新たな `StaticRange$I — その ⇒# `始端~node$ ~SET %始端~node, `終端~node$ ~SET %終端~node, `始端~offset$ ~SET %始端~offset, `終端~offset$ ~SET %終端~offset ◎ Return an array consisting of new StaticRange whose start node is startNode, start offset is startOffset, end node is endNode, and end offset is endOffset.
- ~RET « %新たな範囲o » ◎ ↑
`collapse(node, offset)@m ~method手続きは: ◎ collapse() method • The method must follow these steps:
- ~IF[ %node ~EQ ~NULL ] ⇒# `removeAllRanges()$m と同じに挙動する; ~RET ◎ If node is null, this method must behave identically as removeAllRanges() and abort these steps.
- ~IF[ %node は`~doctype$である ] ⇒ ~THROW `InvalidNodeTypeError$E ◎ If node is a DocumentType, throw an InvalidNodeTypeError exception and abort these steps.
- ~IF[ %offset ~GT %node の`長さ$ ] ⇒ ~THROW `IndexSizeError$E ◎ The method must throw an IndexSizeError exception if offset is longer than node's length and abort these steps.
- ~IF[ コレを結付けている`文書$は %node の`~shadowも含めた広義-先祖$でない ] ⇒ ~RET ◎ If document associated with this is not a shadow-including inclusive ancestor of node, abort these steps.
- %境界点 ~LET `境界点$( %node, %offset ) ◎ ↓
- コレの`範囲o$sL ~SET `新たな範囲oを作成する$( %境界点, %境界点 ) ◎ Otherwise, let newRange be a new range. ◎ Set the start the start and the end of newRange to (node, offset). ◎ Set this's range to newRange.
`setPosition(node, offset)@m ~methodは、 `collapse()$m の別名であり,それと同じに挙動するモノトスル。 ◎ setPosition() method • The method must be an alias, and behave identically, to collapse().
`collapseToStart()@m ~method手続きは: ◎ collapseToStart() method
- ~IF[ コレの`範囲o$sL ~EQ ~NULL ] ⇒ ~THROW `InvalidStateError$E ◎ The method must throw InvalidStateError exception if the this is empty.\
- %境界点 ~LET コレの`範囲o$sLの`始端$ ◎ ↓
- コレの`範囲o$sL ~SET `新たな範囲oを作成する$( %境界点, %境界点 ) ◎ Otherwise, it must create a new range, set the start both its start and end to the start of this's range,\ ◎ and then set this's range to the newly-created range.
注記: (`以下略$) ◎ Note For collapseToStart/End, IE9 mutates the existing range, while Firefox 9.0a2 and Chrome 15 dev replace it with a new one. The spec follows the majority and replaces it with a new one, leaving the old Range object unchanged.
`collapseToEnd()@m ~method手続きは: ◎ collapseToEnd() method
- ~IF[ コレの`範囲o$sL ~EQ ~NULL ] ⇒ ~THROW `InvalidStateError$E ◎ The method must throw InvalidStateError exception if the this is empty.\
- %境界点 ~LET コレの`範囲o$sLの`終端$ ◎ ↓
- コレの`範囲o$sL ~SET `新たな範囲oを作成する$( %境界点, %境界点 ) ◎ Otherwise, it must create a new range, set the start both its start and end to the end of this's range,\ ◎ and then set this's range to the newly-created range.
`extend(node, offset)@m ~method手続きは: ◎ extend() method • The method must follow these steps:
- ~IF[ コレを結付けている`文書$は %node の`~shadowも含めた広義-先祖$でない ] ⇒ ~RET ◎ If the document associated with this is not a shadow-including inclusive ancestor of node, abort these steps.
- ~IF[ コレの`範囲o$sL ~EQ ~NULL ] ⇒ ~THROW `InvalidStateError$E ◎ If this is empty, throw an InvalidStateError exception and abort these steps.
- %旧-~anchor ~LET コレの`~anchor$sL 【! oldFocus 未利用】 ◎ Let oldAnchor and oldFocus be the this's anchor and focus,\
- %新-~focus ~LET `境界点$( %node, %offset ) ◎ and let newFocus be the boundary point (node, offset). ◎ ↓Let newRange be a new range.
- ~IF[ %node の`根$ ~NEQ コレの`範囲o$sLの`始端~node$の`根$ ] ⇒ %旧-~anchor ~SET %新-~focus ◎ If node's root is not the same as the this's range's root, set the start newRange's start and end to newFocus.
- コレの`範囲o$sL ~SET `新たな範囲oを作成する$( %旧-~anchor, %新-~focus ) ◎ Otherwise, if oldAnchor is before or equal to newFocus, set the start newRange's start to oldAnchor, then set its end to newFocus. ◎ Otherwise, set the start newRange's start to newFocus, then set its end to oldAnchor. ◎ Set this's range to newRange.
- コレの`方向$sL ~SET [ %新-~focus は %旧-~anchor `より前$i ならば `後方$i / ~ELSE_ `前方$i ] ◎ If newFocus is before oldAnchor, set this's direction to backwards. Otherwise, set it to forwards.
注記: (`以下略$) ◎ Note Reverse-engineered circa January 2011. IE doesn't support it, so I'm relying on Firefox (implemented extend() sometime before 2000) and WebKit (implemented extend() in 2007). I'm mostly ignoring Opera, because gsnedders tells me its implementation isn't compatible. Firefox 12.0a1 seems to mutate the existing range. IE9 doesn't support extend(), and it's impossible to tell whether Chrome 17 dev or Opera Next 12.00 alpha mutate or replace, because getRangeAt() returns a copy anyway. Nevertheless, I go against Gecko here, to be consistent with collapse().
`setBaseAndExtent(anchorNode, anchorOffset, focusNode, focusOffset)@m ~method手続きは: ◎ setBaseAndExtent() method • The method must follow these steps:
- ~IF[ %anchorOffset ~GT %anchorNode の`長さ$ ]~OR[ %focusOffset ~GT %focusNode の`長さ$ ] ⇒ ~THROW `IndexSizeError$E ◎ If anchorOffset is longer than anchorNode's length or if focusOffset is longer than focusNode's length, throw an IndexSizeError exception and abort these steps.
- ~IF[ コレを結付けている`文書$は[ %anchorNode / %focusNode ]の`~shadowも含めた広義-先祖$でない ] ⇒ ~RET ◎ If document associated with this is not a shadow-including inclusive ancestor of anchorNode or focusNode, abort these steps.
- %~anchor ~LET `境界点$( %anchorNode, %anchorOffset ) ◎ Let anchor be the boundary point (anchorNode, anchorOffset) and\
- %~focus ~LET `境界点$( %focusNode, %focusOffset ) ◎ let focus be the boundary point (focusNode, focusOffset).
- コレの`範囲o$sL ~SET `新たな範囲oを作成する$( %~anchor, %~focus ) ◎ Let newRange be a new range. ◎ If anchor is before focus, set the start the newRange's start to anchor and its end to focus. Otherwise, set the start them to focus and anchor respectively. ◎ Set this's range to newRange.
- コレの`方向$sL ~SET [ 次が満たされるならば `後方$i / ~ELSE_ `前方$i ] ⇒ %~focus は %~anchor `より前$i ◎ If focus is before anchor, set this's direction to backwards. Otherwise, set it to forwards
`selectAllChildren(node)@m ~method手続きは: ◎ selectAllChildren() method • The method must follow these steps:
- ~IF[ %node は`~doctype$である ] ⇒ ~THROW `InvalidNodeTypeError$E ◎ If node is a DocumentType, throw an InvalidNodeTypeError exception and abort these steps.
- ~IF[ %node の`根$ ~NEQ コレを結付けている`文書$ ] ⇒ ~RET ◎ If node's root is not the document associated with this, abort these steps.
- コレの`範囲o$sL ~SET `新たな範囲oを作成する$( `境界点$( %node, 0 ), `境界点$( %node, %~node の`子$の個数 ) ) ◎ Let newRange be a new range and childCount be the number of children of node. ◎ Set newRange's start to (node, 0). ◎ Set newRange's end to (node, childCount). ◎ Set this's range to newRange.
- コレの`方向$sL ~SET %前方 ◎ Set this's direction to forwards.
注記: (`以下略$) ◎ Note Based mostly on Firefox 9.0a2. It has a bug that I didn't reproduce, namely that if you pass a Document as the argument, the end offset becomes 1 instead of the number of children it has. It also throws a RangeException instead of DOMException, because its implementation predated their merging. ◎ IE9 behaves similarly but with glitches. It throws "Unspecified error." if the node is detached or display:none, and apparently in some random other cases too. It throws "Invalid argument." for detached comments (only!). Finally, if you pass it a comment, it seems to select the whole comment, unlike with text nodes. ◎ Chrome 16 dev behaves as you'd expect given its Selection implementation. It refuses to select anything that's not visible, so it's almost always wrong. Opera 11.50 just does nothing in all my tests, as usual.
注記: 新たな範囲oは、 既存の範囲oを変異することなく置換する。 (`以下略$) ◎ Note The new range replaces any existing one, doesn't mutate it. This matches IE9 and Firefox 12.0a1. (Chrome 17 dev and Opera Next 12.00 alpha can't be tested, because getRangeAt() returns a copy anyway.)
`modify(alter, direction, granularity)@m ~method手続きは: ◎ modify() method ◎ The method must follow these steps:
【 いずれの引数も,~IDLにおいては省略可能と指定されているが、 以下の手続きは,省略時の取扱いを欠いている(既定~値は指定されてない)。 】【 以下における文字列の比較は, 原文では`~ASCII大小無視$が利用されているが、 この訳では,予め引数を`~ASCII小文字~化する$ことにより簡素化する。 】
- %alter ~SET `~ASCII小文字~化する$( %alter ) ◎ ↓
- %direction ~SET `~ASCII小文字~化する$( %direction ) ◎ ↓
- %granularity ~SET `~ASCII小文字~化する$( %granularity ) ◎ ↓
-
~IF[ ~OR↓ ]…
- %alter ~NIN { `extend^l, `move^l }
- %direction ~NIN { `forward^l, `backward^l, `left^l, `right^l }
- %granularity ~NIN { `character^l, `word^l, `sentence^l, `line^l, `paragraph^l, `lineboundary^l, `sentenceboundary^l, `paragraphboundary^l, `documentboundary^l
- コレの`範囲o$sL ~EQ ~NULL
…ならば ⇒ ~RET
◎ If alter is not ASCII case-insensitive match with "extend" or "move", abort these steps. ◎ If direction is not ASCII case-insensitive match with "forward", "backward", "left", or "right", abort these steps. ◎ If granularity is not ASCII case-insensitive match with "character", "word", "sentence", "line", "paragraph", "lineboundary", "sentenceboundary", "paragraphboundary", "documentboundary", abort these steps. ◎ If this selection is empty, abort these steps. - %書字~方向 ~LET コレの`~focus$sLにおける`行内~基底~方向$に応じて ⇒# `ltr$v 【左から右へ】ならば `right^l `rtl$v 【右から左へ】ならば `left^l ◎ ↓
- コレの`方向$sL ~SET [ 次が満たされるならば `前方$i / ~ELSE_ `後方$i ] ⇒ %direction ~IN { `forward^l, %書字~方向 } ◎ Let effectiveDirection be backwards. ◎ If direction is ASCII case-insensitive match with "forward", set effectiveDirection to forwards. ◎ If direction is ASCII case-insensitive match with "right" and inline base direction of this selection's focus is ltr, set effectiveDirection to forwards. ◎ If direction is ASCII case-insensitive match with "left" and inline base direction of this selection's focus is rtl, set effectiveDirection to forwards. ◎ Set this selection's direction to effectiveDirection.
-
%alter に応じて: ◎ ↓
- `extend^l ⇒ コレの`~focus$sL ~SET [ 利用者が選択を %granularity により拡張するよう要請した ]とするときの所在 ◎ If alter is ASCII case-insensitive match with "extend", set this selection's focus to the location as if the user had requested to extend selection by granularity.
- `move^l ⇒ コレの[ `~focus$sL, `~anchor$sL ]~SET [ 利用者が選択を %granularity により移動するよう要請した ]とするときの所在 ◎ Otherwise, set this selection's focus and anchor to the location as if the user had requested to move selection by granularity.
注記: %granularity により選択を[ 拡張する/移動する ]とは何を意味するか,もっと精確に定義する必要がある。 ◎ Note We need to more precisely define what it means to extend or move selection by each granularity.
`deleteFromDocument()@m ~method手続きは ⇒ ~IF[ コレの`範囲o$sL ~NEQ ~NULL ]~AND[ コレの`~anchor$sLは`文書~tree$内に在る ]~AND[ コレの`~focus$sLは`文書~tree$内に在る ] ⇒ コレの`範囲o$sL上で `deleteContents()$m の手続きを呼出す `DOM$r ◎ deleteFromDocument() method • The method must invoke deleteContents() on this's range if this is not empty and both focus and anchor are in the document tree. Otherwise the method must do nothing.
注記: これは、 範囲oを置換することなく,実際に変異させる~methodの一つである。 (`以下略$) ◎ Note This is the one method that actually mutates the range instead of replacing it. This matches IE9 and Firefox 12.0a1. (Chrome 17 dev and Opera Next 12.00 alpha can't be tested, because getRangeAt() returns a copy anyway.)
`containsNode(node, allowPartialContainment)@m ~method手続きは:
- ~IF[ コレの`範囲o$sL ~EQ ~NULL ]~OR[ %node の`根$ ~NEQ コレを結付けている`文書$ ] ⇒ ~RET ~F
- %~node始端 ~LET `境界点$( %node, 0 )
- %~node終端 ~LET `境界点$( %node, %node の`長さ$ )
- %範囲o ~LET コレの`範囲o$sL
-
~IF[ %allowPartialContainment ~EQ ~F ] ⇒ ~RET ~IS ~AND↓:
- %範囲o の`始端$は %~node始端 `より前$i か “視覚的に等価”
- %範囲o の`終端$は %~node終端 `より後$i か “視覚的に等価”
【 すなわち, %範囲o は “視覚的” には~nodeを全部的に包含している 】
-
~ELSE ⇒ ~RET ~IS ~AND↓:
- %範囲o の`始端$は %~node終端 `より前$i か “視覚的に等価”
- %範囲o の`終端$は %~node始端 `より後$i か “視覚的に等価”
【 すなわち, %範囲o は “視覚的” には~nodeを部分的に包含している 】
【 “視覚的に等価” が具体的にどう決定されるかは、 定義されていない。 “2 つの境界点は、その合間に描画される内容は無いならば視覚的に等価とされる” のような定義は考えられるが。 】
◎ containsNode() method • The method must return false if this is empty or if node's root is not the document associated with this. • Otherwise, if allowPartialContainment is false, the method must return true if and only if start of its range is before or visually equivalent to the first boundary point in the node and end of its range is after or visually equivalent to the last boundary point in the node. • If allowPartialContainment is true, the method must return true if and only if start of its range is before or visually equivalent to the last boundary point in the node and end of its range is after or visually equivalent to the first boundary point in the node.`stringifier@m による`文字列~化の挙動$は、 次に従うモノトスル: ◎ stringifier • The stringification must\
- [ コレの`範囲o$sL ~NEQ ~NULL ]ならば、 【範囲oを成す内容のうち】 具現化された~textの連結を返す。 ◎ return the string, which is the concatenation of the rendered text if there is a range associated with this.
- 選択が[ `textarea$e / `input$e ]要素の中にある場合、 要素の値【`値@~HTMLforms#concept-fe-value$?】内で選択された部分文字列を返す。 ◎ If the selection is within a textarea or input element, it must return the selected substring in its value.
【 これは、 まだ,きちんとした手続きとして定義されてはいない。 例えば、 コレの`範囲o$sL ~EQ ~NULL の場合の挙動は指定されていない (たぶん、空~文字列を返すことになろうが)。 】
注記: `Gecko^ua による `nsISelection.idl@https://mxr.mozilla.org/mozilla/source/content/base/public/nsISelection.idl$ も見よ。 この仕様は、 まだ,そのすべては備えていない — 特に、 `selectionLanguageChange()^m, `containsNode()^m は欠落である。 それらが欠落なのは、 編集者が,それらを `Range^I の用語でどう定義するか作業できなかったためである。 ◎ Note See also nsISelection.idl from Gecko. This spec doesn't have everything from there yet, in particular selectionLanguageChange() and containsNode() are missing. They are missing because I couldn't work out how to define them in terms of Ranges.
`Selection$I ~interfaceは、 元々は `Netscape^ua の特能であった。 元の実装は `Gecko^ua( `Firefox^ua ) に持ち込まれ、 後に,他の~browser~engineも独立にこの特能を実装した。 `Netscape^ua 実装は、 単独の選択における複数の範囲oを常に許容していた — 一例として,利用者が~tableの ある~colも選択できるよう。 しかしながら,複数個の範囲oからなる選択は、 ~web開発者が知る由もない 不快な際どい事例があるものと立証され、 `Gecko^ua 開発者ですら,わずかしか正しく取扱っていなかった。 他の~browser~engineは、 この特能を実装したことは決してなく,様々な互換でない流儀で選択を単独の範囲oに切詰めていた。 ◎ Note Originally, the Selection interface was a Netscape feature. The original implementation was carried on into Gecko (Firefox), and the feature was later implemented independently by other browser engines. The Netscape implementation always allowed multiple ranges in a single selection, for instance so the user could select a column of a table However, multi-range selections proved to be an unpleasant corner case that web developers didn't know about and even Gecko developers rarely handled correctly. Other browser engines never implemented the feature, and clamped selections to a single range in various incompatible fashions.
この仕様は,選択を高々 1 個の範囲oに制約する~~点で `Gecko^ua 以外の~engineに従うが、 この~APIは,元々は任意な個数の範囲oを伴う選択~用に設計されていた。 `removeRange()$m と `removeAllRanges()$m の共存や, `getRangeAt()$m ~methodの整数~引数は常に 0 でなければならない奇妙さがあるのは、 それがためである。 ◎ This specification follows non-Gecko engines in restricting selections to at most one range, but the API was still originally designed for selections with arbitrary numbers of ranges. This explains oddities like the coexistence of removeRange() and removeAllRanges(), and a getRangeAt() method that takes an integer argument that must always be zero.
`Selection^I ~interfaceを成すすべての~memberは、 その~objが表現する`範囲o$用の演算の用語で定義される。 これらの演算は, `Range$I ~interfaceに定義されるように例外を投出し得る 【すなわち、`新たな範囲oを作成する$とき】。 したがって `Selection$I ~interfaceの各~memberも — そこで明示的に投出される例外の他に — 例外を投出することになる。 ◎ All of the members of the Selection interface are defined in terms of operations on the range object (if any) represented by the object. These operations can raise exceptions, as defined for the Range interface; this can therefore result in the members of the Selection interface raising exceptions as well, in addition to any explicitly called out above.
4. 他の~interfaceに対する拡張
この仕様は、 いくつかの~interfaceを拡張して、 この仕様にて定義される~interfaceへの入口を供する。 ◎ This specification extends several interfaces to provide entry points to the interfaces defined in this specification.
4.1. `Document^I ~interfaceに対する拡張
`Document$I ~interfaceは、 `HTML$r にて定義される。 ◎ The Document interface is defined in [HTML].
partial interface `Document$I { `Selection$I? getSelection(); };
`文書の選択@ は、 所与の ( `文書$ %文書 ) に対し,次を返す ⇒# %文書 が`属する閲覧~文脈$ ~NEQ ~NULL ならば %文書 の`選択$ / ~ELSE_ ~NULL ◎ ↓
4.2. `Window^I ~interfaceに対する拡張
`Window$I ~interfaceは `HTML$r にて定義される。 ◎ The Window interface is defined in [HTML].
partial interface `Window$I { `Selection$I? `~getSelectionW()$m; };
4.3. `GlobalEventHandlers^I ~interface~mixinに対する拡張
`GlobalEventHandlers$I ~interface~mixin【!~interface】は、 `HTML$r にて定義される。 ◎ The GlobalEventHandlers interface is defined in [HTML].
partial interface mixin `GlobalEventHandlers$I { attribute `EventHandler$I `onselectstart$m; attribute `EventHandler$I `onselectionchange$m; };
`onselectstart@m, `onselectionchange@m は、 順に[ `selectstart$et, `selectionchange$et ]~event用の`~event~handler~IDL属性$である。 すべての[ `~HTML要素$, `文書$, `Window$I ~obj ]は、 これらを~supportするモノトスル。 ◎ onselectstart • The attribute must be an event handler IDL attribute for the selectstart event supported by all HTML elements, Document objects, and Window objects. ◎ onselectionchange • The attribute must be an event handler IDL attribute for the selectionchange event supported by all HTML elements, Document objects, and Window objects.
5. ~DOM変異に対する応答-法
~UAは、 `~node$ %~node に対し,次に挙げる動作が生じたときは、 %~node の`~node文書$の`選択$の`範囲o$sLを[ それが`~live範囲o$であった ]かのように更新するモノトスル: ◎ ↓
- %~node は `CharacterData$I ~nodeである下で ⇒ %~node の`~dataを置換する@~DOM4#concept-cd-replace$とき 【!不要/ %~node の`~dataの部分文字列@~DOM4#concept-cd-substring$を得るとき】 ◎ When the user agent is to replace data or substring data on CharacterData, the user agent must update the range associated with selection of the node document of the CharacterData as if it's a live range.
- %~node は `Text$I ~nodeである下で ⇒ %~node を`分割する@~DOM4#concept-text-split$とき ◎ When the user agent is to split a Text node, the user agent must update the range associated with selection of the node document of the Text as if it's a live range.
- %~node 上で `normalize()$m ~method手続きを走らすとき ◎ When the user agent is to run steps for normalize() method, the user agent must update the range associated with selection of the node document of this as if it's a live range.
- %~node を`除去する@~DOM4#concept-node-remove$とき ◎ ↓
- %~node を親の中で`子の前に挿入する@~DOM4#concept-node-insert$とき ◎ When the user agent is to remove or insert a node, the user agent must update the range associated with selection of the node document of the node as if it's a live range.
6. 利用者-ヤリトリ
~UAは、 `作動中な文書$navに結付けられた`選択$を変更することを利用者に許容するベキである。 ◎ The user agent should allow the user to change the selection associated with the active document.\
利用者が選択を改変したときは、 ~UAは,次を走らすモノトスル: ◎ If the user makes any modification to a selection, the user agent must\
- ( %始端, %終端 ) ~LET 利用者による選択の ( 始端, 終端 ) を指す`境界点$ ( %始端 は %終端 `より後$i でない) ◎ ↓
- `選択$の`範囲o$sL ~SET `新たな範囲oを作成する$( %始端, %終端 ) (既存の`範囲o$sLは改変されない) ◎ create a new range with suitable start and end of the range and associate the selection with this new range (not modify the existing range), and\
-
`選択$の`方向$sL ~SET 利用者は[ %始端, %終端 ]どちらから選択し始めたかに応じて ⇒# %始端 と %終端 は一致するならば `前方$i/ %始端 から選択し始めたならば `前方$i / %終端 から選択し始めたならば `後方$i / ~platform規約に因り どちらから選択し始めたか決定できないならば `無方向$i† ◎ set update selection's direction to forwards if the start is before or equal to the end, backwards if if the end is before the start, or directionless if the start and the end cannot be ordered due to the platform convention.
【† 例えばダブルクリック等で単語を選択したときなど。 】【 原文の記述は、[ 始端/終端 ]と[ 選択し始めた地点/選択し終えた地点 ]とが混同されていて,はっきりしない所がある。 %始端 と %終端 が一致する場合と他の場合は両立し得るが、 `方向$sLの定義の記述に従うなら,一致する場合が優先されることになる。 しかしながら,常識的には、 “決定できない場合” がそれより優先されるべきであろう。 】
~UAは、 利用者-動作 (例:編集-不能な領域を~clickするなど) に呼応して`選択$の`範囲o$sLを ~NULL に設定しないモノトスル。 ◎ The user agent must not make a selection empty if it was not already empty in response to any user actions (e.g. clicking on a non-editable region).
注記: (`以下略$) ◎ Note See bug 15470. IE9 and Opera Next 12.00 alpha allow the user to reset the range to null after the fact by clicking somewhere; Firefox 12.0a1 and Chrome 17 dev do not. I follow Gecko/WebKit, because it lessens the chance of getRangeAt(0) throwing.
6.1. `selectstart@et ~event
~UAは、 利用者が起動した動作に呼応して,`選択$の`範囲o$sLに新たな`範囲o$ %新-範囲o を設定しようとするときは — `選択$の`範囲o$sLは それまで[ ~NULL であった/`畳まれて$いた ]場合には、 `選択$を変更するに先立って — 次を走らすモノトスル ⇒ `~eventを発火する$( %新-範囲o の`始端~node$, `selectstart^et ) — 次のように初期化して ⇒# `bubbles$m ~SET ~T, `cancelable$m ~SET ~T ◎ When the user agent is about to associate a new range newRange to the selection in response to a user initiated action, the user agent must fire an event named selectstart, which bubbles and is cancelable, at the node associated with the boundary point of newRange's start prior to changing the selection if the selection was previously empty or the previously associated range was collapsed.
当の~eventが取消された場合、 ~UAは,`選択$を変更しないモノトスル。 ◎ If the event is canceled, the user agent must not change the selection.
~UAは、 `選択$の`範囲o$sLを ~NULL に設定したときには,`~eventを発火-$しないモノトスル。 ◎ The user agent must not fire an event when the user agent sets the selection empty.
6.2. `selectionchange@et ~event
~UAは、 `選択$の`範囲o$sLが[ ~NULL または新たな`範囲o$にされた/ そのいずれかの`境界点$が利用者または内容~scriptにより変異された ]ときは,次を走らすモノトスル ⇒ `~selectionchange-ev~eventを~scheduleする$( 当の`選択$を結付けている`文書$ ) ◎ When the selection is dissociated with its range, associated with a new range, or the associated range's boundary point is mutated either by the user or the content script, the user agent must schedule a selectionchange event on document.
[ `input$e / `textarea$e ]要素 %要素 が~text選択を供していて,それが変化した(方向も含む)ときは、 ~UAは,次を走らすモノトスル ⇒ `~selectionchange-ev~eventを~scheduleする$( %要素 ) ◎ When an input or textarea element provide a text selection and its selection changes (in either extent or direction), the user agent must schedule a selectionchange event on the element.
6.2.1. `selectionchange^et ~eventの~schedule法
`~selectionchange-ev~eventを~scheduleする@ ときは、 所与の ( ~node %~target ) に対し,次の手続きを走らす: ◎ To schedule a selectionchange event on a node target, run these steps:
- ~IF[ %~target の`~selectionchange-ev~eventを~scheduleしたか$ ~EQ ~T ] ⇒ ~RET ◎ If target's has scheduled selectionchange event is true, abort these steps.
-
`~taskを~queueする$( `利用者~対話~task~source$, 次の手続き )
手続きは ⇒ `~selectionchange-ev~eventを発火する$( %~target )◎ Queue a task on the user interaction task source to fire a selectionchange event on target.
6.2.2. `selectionchange^et ~eventの発火-法
`~selectionchange-ev~eventを発火する@ ときは、 所与の ( ~node %~target ) に対し,次の手続きを走らす: ◎ To fire a selectionchange event on a node target, run these steps:
- %~target の`~selectionchange-ev~eventを~scheduleしたか$ ~SET ~F ◎ Set target's has scheduled selectionchange event to false.
- %浮上するか ~LET %~target に応じて ⇒# 要素であるならば ~T / 文書であるならば ~F ◎ ↓
- `~eventを発火する$( %~target, `selectionchange$et ) — 次のように初期化して ⇒# `bubbles$m ~SET %浮上するか, `cancelable$m ~SET ~F ◎ If target is an element, fire an event named selectionchange, which bubbles and not cancelable, at target. ◎ Otherwise, if target is a document, fire an event named selectionchange, which does not bubble and not cancelable, at target.
~security/~privacyの考慮点
この標準には、 既知な~securityの考慮点は無い。 ◎ There are no known security considerations for this standard.
この標準には、 利用者が支援技術を利用しているとき, そのことを公開するものになり得る~privacy~riskがある。 それを軽減するため、 `~UA$は,例えば次を採択してもヨイ ⇒ 利用者が文書の`選択$を改変したとき,概して[ `selectstart$et / `selectionchange$et ]~eventに結付けられる[ ~mouse~event/~keyboard~event ](順不同)を【~mouse/~keyboardで選択を改変したかのように】模倣する。 ◎ To mitigate potential privacy risks of exposing user's use of assistive technologies, for example, user agent may elect to emulate mouse and keyboard events typically associated with selectstart or selectionchange events when the user opts to modify the selection of a document.
謝辞
この仕様, および `HTML Editing API$cite 仕様の元の作者である `Aryeh Gregor^en 氏に。 ◎ Many thanks to ◎ Aryeh Gregor, who is the original author of this specification as well as HTML Editing API specification.
`HTML Editing API$cite 仕様に対し,~feedback, 参加, その他の助力を貢献された方々に: