@@ -15,6 +15,20 @@ let styles = new Map();
15
15
let groups = new Map ( ) ;
16
16
var lastGroupId = 0 ;
17
17
18
+ /**
19
+ * Returns the document body's writing mode.
20
+ */
21
+ function getDocumentWritingMode ( ) {
22
+ return getComputedStyle ( document . body ) . writingMode ;
23
+ }
24
+
25
+ /**
26
+ * Returns the closest element ancestor of the given node.
27
+ */
28
+ function getContainingElement ( node ) {
29
+ return node . nodeType === Node . ELEMENT_NODE ? node : node . parentElement ;
30
+ }
31
+
18
32
/**
19
33
* Registers a list of additional supported Decoration Templates.
20
34
*
@@ -172,46 +186,108 @@ export function DecorationGroup(groupId, groupName) {
172
186
}
173
187
174
188
let itemContainer = document . createElement ( "div" ) ;
175
- itemContainer . setAttribute ( "id" , item . id ) ;
176
- itemContainer . setAttribute ( "data-style" , item . decoration . style ) ;
177
- itemContainer . style . setProperty ( "pointer-events" , "none" ) ;
178
-
179
- let viewportWidth = window . innerWidth ;
180
- let columnCount = parseInt (
181
- getComputedStyle ( document . documentElement ) . getPropertyValue (
182
- "column-count"
183
- )
184
- ) ;
185
- let pageWidth = viewportWidth / ( columnCount || 1 ) ;
186
- let scrollingElement = document . scrollingElement ;
187
- let xOffset = scrollingElement . scrollLeft ;
188
- let yOffset = scrollingElement . scrollTop ;
189
-
190
- function positionElement ( element , rect , boundingRect ) {
189
+ itemContainer . id = item . id ;
190
+ itemContainer . dataset . style = item . decoration . style ;
191
+ itemContainer . style . pointerEvents = "none" ;
192
+
193
+ const documentWritingMode = getDocumentWritingMode ( ) ;
194
+ const isVertical =
195
+ documentWritingMode === "vertical-rl" ||
196
+ documentWritingMode === "vertical-lr" ;
197
+
198
+ const scrollingElement = document . scrollingElement ;
199
+ const { scrollLeft : xOffset , scrollTop : yOffset } = scrollingElement ;
200
+ const viewportWidth = isVertical ? window . innerHeight : window . innerWidth ;
201
+ const viewportHeight = isVertical ? window . innerWidth : window . innerHeight ;
202
+
203
+ const columnCount =
204
+ parseInt (
205
+ getComputedStyle ( document . documentElement ) . getPropertyValue (
206
+ "column-count"
207
+ )
208
+ ) || 1 ;
209
+ const pageSize =
210
+ ( isVertical ? viewportHeight : viewportWidth ) / columnCount ;
211
+
212
+ function positionElement ( element , rect , boundingRect , writingMode ) {
191
213
element . style . position = "absolute" ;
192
-
193
- if ( style . width === "wrap" ) {
194
- element . style . width = `${ rect . width } px` ;
195
- element . style . height = `${ rect . height } px` ;
196
- element . style . left = `${ rect . left + xOffset } px` ;
197
- element . style . top = `${ rect . top + yOffset } px` ;
198
- } else if ( style . width === "viewport" ) {
199
- element . style . width = `${ viewportWidth } px` ;
200
- element . style . height = `${ rect . height } px` ;
201
- let left = Math . floor ( rect . left / viewportWidth ) * viewportWidth ;
202
- element . style . left = `${ left + xOffset } px` ;
203
- element . style . top = `${ rect . top + yOffset } px` ;
204
- } else if ( style . width === "bounds" ) {
205
- element . style . width = `${ boundingRect . width } px` ;
206
- element . style . height = `${ rect . height } px` ;
207
- element . style . left = `${ boundingRect . left + xOffset } px` ;
208
- element . style . top = `${ rect . top + yOffset } px` ;
209
- } else if ( style . width === "page" ) {
210
- element . style . width = `${ pageWidth } px` ;
211
- element . style . height = `${ rect . height } px` ;
212
- let left = Math . floor ( rect . left / pageWidth ) * pageWidth ;
213
- element . style . left = `${ left + xOffset } px` ;
214
- element . style . top = `${ rect . top + yOffset } px` ;
214
+ const isVerticalRL = writingMode === "vertical-rl" ;
215
+ const isVerticalLR = writingMode === "vertical-lr" ;
216
+
217
+ if ( isVerticalRL || isVerticalLR ) {
218
+ if ( style . width === "wrap" ) {
219
+ element . style . width = `${ rect . width } px` ;
220
+ element . style . height = `${ rect . height } px` ;
221
+ if ( isVerticalRL ) {
222
+ element . style . right = `${
223
+ - rect . right - xOffset + scrollingElement . clientWidth
224
+ } px`;
225
+ } else {
226
+ // vertical-lr
227
+ element . style . left = `${ rect . left + xOffset } px` ;
228
+ }
229
+ element . style . top = `${ rect . top + yOffset } px` ;
230
+ } else if ( style . width === "viewport" ) {
231
+ element . style . width = `${ rect . height } px` ;
232
+ element . style . height = `${ viewportWidth } px` ;
233
+ const top = Math . floor ( rect . top / viewportWidth ) * viewportWidth ;
234
+ if ( isVerticalRL ) {
235
+ element . style . right = `${ - rect . right - xOffset } px` ;
236
+ } else {
237
+ // vertical-lr
238
+ element . style . left = `${ rect . left + xOffset } px` ;
239
+ }
240
+ element . style . top = `${ top + yOffset } px` ;
241
+ } else if ( style . width === "bounds" ) {
242
+ element . style . width = `${ boundingRect . height } px` ;
243
+ element . style . height = `${ viewportWidth } px` ;
244
+ if ( isVerticalRL ) {
245
+ element . style . right = `${
246
+ - boundingRect . right - xOffset + scrollingElement . clientWidth
247
+ } px`;
248
+ } else {
249
+ // vertical-lr
250
+ element . style . left = `${ boundingRect . left + xOffset } px` ;
251
+ }
252
+ element . style . top = `${ boundingRect . top + yOffset } px` ;
253
+ } else if ( style . width === "page" ) {
254
+ element . style . width = `${ rect . height } px` ;
255
+ element . style . height = `${ pageSize } px` ;
256
+ const top = Math . floor ( rect . top / pageSize ) * pageSize ;
257
+ if ( isVerticalRL ) {
258
+ element . style . right = `${
259
+ - rect . right - xOffset + scrollingElement . clientWidth
260
+ } px`;
261
+ } else {
262
+ // vertical-lr
263
+ element . style . left = `${ rect . left + xOffset } px` ;
264
+ }
265
+ element . style . top = `${ top + yOffset } px` ;
266
+ }
267
+ } else {
268
+ if ( style . width === "wrap" ) {
269
+ element . style . width = `${ rect . width } px` ;
270
+ element . style . height = `${ rect . height } px` ;
271
+ element . style . left = `${ rect . left + xOffset } px` ;
272
+ element . style . top = `${ rect . top + yOffset } px` ;
273
+ } else if ( style . width === "viewport" ) {
274
+ element . style . width = `${ viewportWidth } px` ;
275
+ element . style . height = `${ rect . height } px` ;
276
+ const left = Math . floor ( rect . left / viewportWidth ) * viewportWidth ;
277
+ element . style . left = `${ left + xOffset } px` ;
278
+ element . style . top = `${ rect . top + yOffset } px` ;
279
+ } else if ( style . width === "bounds" ) {
280
+ element . style . width = `${ boundingRect . width } px` ;
281
+ element . style . height = `${ rect . height } px` ;
282
+ element . style . left = `${ boundingRect . left + xOffset } px` ;
283
+ element . style . top = `${ rect . top + yOffset } px` ;
284
+ } else if ( style . width === "page" ) {
285
+ element . style . width = `${ pageSize } px` ;
286
+ element . style . height = `${ rect . height } px` ;
287
+ const left = Math . floor ( rect . left / pageSize ) * pageSize ;
288
+ element . style . left = `${ left + xOffset } px` ;
289
+ element . style . top = `${ rect . top + yOffset } px` ;
290
+ }
215
291
}
216
292
}
217
293
@@ -230,32 +306,38 @@ export function DecorationGroup(groupId, groupName) {
230
306
}
231
307
232
308
if ( style . layout === "boxes" ) {
233
- let doNotMergeHorizontallyAlignedRects = true ;
234
- let clientRects = getClientRectsNoOverlap (
309
+ const doNotMergeHorizontallyAlignedRects =
310
+ ! documentWritingMode . startsWith ( "vertical" ) ;
311
+ const startElement = getContainingElement ( item . range . startContainer ) ;
312
+ // Decorated text may have a different writingMode from document body
313
+ const decoratorWritingMode = getComputedStyle ( startElement ) . writingMode ;
314
+
315
+ const clientRects = getClientRectsNoOverlap (
235
316
item . range ,
236
317
doNotMergeHorizontallyAlignedRects
237
- ) ;
238
-
239
- clientRects = clientRects . sort ( ( r1 , r2 ) => {
240
- if ( r1 . top < r2 . top ) {
241
- return - 1 ;
242
- } else if ( r1 . top > r2 . top ) {
243
- return 1 ;
318
+ ) . sort ( ( r1 , r2 ) => {
319
+ if ( r1 . top !== r2 . top ) return r1 . top - r2 . top ;
320
+ if ( decoratorWritingMode === "vertical-rl" ) {
321
+ return r2 . left - r1 . left ;
322
+ } else if ( decoratorWritingMode === "vertical-lr" ) {
323
+ return r1 . left - r2 . left ;
244
324
} else {
245
- return 0 ;
325
+ return r1 . left - r2 . left ;
246
326
}
247
327
} ) ;
248
328
249
329
for ( let clientRect of clientRects ) {
250
330
const line = elementTemplate . cloneNode ( true ) ;
251
- line . style . setProperty ( "pointer-events" , "none" ) ;
252
- positionElement ( line , clientRect , boundingRect ) ;
331
+ line . style . pointerEvents = "none" ;
332
+ line . dataset . writingMode = decoratorWritingMode ;
333
+ positionElement ( line , clientRect , boundingRect , documentWritingMode ) ;
253
334
itemContainer . append ( line ) ;
254
335
}
255
336
} else if ( style . layout === "bounds" ) {
256
337
const bounds = elementTemplate . cloneNode ( true ) ;
257
- bounds . style . setProperty ( "pointer-events" , "none" ) ;
258
- positionElement ( bounds , boundingRect , boundingRect ) ;
338
+ bounds . style . pointerEvents = "none" ;
339
+ bounds . dataset . writingMode = documentWritingMode ;
340
+ positionElement ( bounds , boundingRect , boundingRect , documentWritingMode ) ;
259
341
260
342
itemContainer . append ( bounds ) ;
261
343
}
@@ -276,9 +358,9 @@ export function DecorationGroup(groupId, groupName) {
276
358
function requireContainer ( ) {
277
359
if ( ! container ) {
278
360
container = document . createElement ( "div" ) ;
279
- container . setAttribute ( "id" , groupId ) ;
280
- container . setAttribute ( "data- group" , groupName ) ;
281
- container . style . setProperty ( "pointer-events" , "none" ) ;
361
+ container . id = groupId ;
362
+ container . dataset . group = groupName ;
363
+ container . style . pointerEvents = "none" ;
282
364
document . body . append ( container ) ;
283
365
}
284
366
return container ;
0 commit comments