@@ -74,6 +74,10 @@ interface GutterConfig {
7474 updateSpacer ?: null | ( ( spacer : GutterMarker , update : ViewUpdate ) => GutterMarker )
7575 /// Supply event handlers for DOM events on this gutter.
7676 domEventHandlers ?: Handlers ,
77+ /// By default, gutters are shown horizontally before the editor
78+ /// content (to the left in a left-to-right layout). Set this to
79+ /// `"after"` to show a gutter on the other side of the content.
80+ side ?: "before" | "after"
7781}
7882
7983const defaults = {
@@ -86,7 +90,8 @@ const defaults = {
8690 lineMarkerChange : null ,
8791 initialSpacer : null ,
8892 updateSpacer : null ,
89- domEventHandlers : { }
93+ domEventHandlers : { } ,
94+ side : "before" as const
9095}
9196
9297const activeGutters = Facet . define < Required < GutterConfig > > ( )
@@ -120,18 +125,22 @@ export function gutters(config?: {fixed?: boolean}): Extension {
120125const gutterView = ViewPlugin . fromClass ( class {
121126 gutters : SingleGutterView [ ]
122127 dom : HTMLElement
128+ domAfter : HTMLElement | null = null
123129 fixed : boolean
124130 prevViewport : { from : number , to : number }
125131
126132 constructor ( readonly view : EditorView ) {
127133 this . prevViewport = view . viewport
128134 this . dom = document . createElement ( "div" )
129- this . dom . className = "cm-gutters"
135+ this . dom . className = "cm-gutters cm-gutters-before "
130136 this . dom . setAttribute ( "aria-hidden" , "true" )
131137 this . dom . style . minHeight = ( this . view . contentHeight / this . view . scaleY ) + "px"
132138 this . gutters = view . state . facet ( activeGutters ) . map ( conf => new SingleGutterView ( view , conf ) )
133- for ( let gutter of this . gutters ) this . dom . appendChild ( gutter . dom )
134139 this . fixed = ! view . state . facet ( unfixGutters )
140+ for ( let gutter of this . gutters ) {
141+ if ( gutter . config . side == "after" ) this . getDOMAfter ( ) . appendChild ( gutter . dom )
142+ else this . dom . appendChild ( gutter . dom )
143+ }
135144 if ( this . fixed ) {
136145 // FIXME IE11 fallback, which doesn't support position: sticky,
137146 // by using position: relative + event handlers that realign the
@@ -142,6 +151,18 @@ const gutterView = ViewPlugin.fromClass(class {
142151 view . scrollDOM . insertBefore ( this . dom , view . contentDOM )
143152 }
144153
154+ getDOMAfter ( ) {
155+ if ( ! this . domAfter ) {
156+ this . domAfter = document . createElement ( "div" )
157+ this . domAfter . className = "cm-gutters cm-gutters-after"
158+ this . domAfter . setAttribute ( "aria-hidden" , "true" )
159+ this . domAfter . style . minHeight = ( this . view . contentHeight / this . view . scaleY ) + "px"
160+ this . domAfter . style . position = this . fixed ? "sticky" : ""
161+ this . view . scrollDOM . appendChild ( this . domAfter )
162+ }
163+ return this . domAfter
164+ }
165+
145166 update ( update : ViewUpdate ) {
146167 if ( this . updateGutters ( update ) ) {
147168 // Detach during sync when the viewport changed significantly
@@ -152,18 +173,24 @@ const gutterView = ViewPlugin.fromClass(class {
152173 this . syncGutters ( vpOverlap < ( vpB . to - vpB . from ) * 0.8 )
153174 }
154175 if ( update . geometryChanged ) {
155- this . dom . style . minHeight = ( this . view . contentHeight / this . view . scaleY ) + "px"
176+ let min = ( this . view . contentHeight / this . view . scaleY ) + "px"
177+ this . dom . style . minHeight = min
178+ if ( this . domAfter ) this . domAfter . style . minHeight = min
156179 }
157180 if ( this . view . state . facet ( unfixGutters ) != ! this . fixed ) {
158181 this . fixed = ! this . fixed
159182 this . dom . style . position = this . fixed ? "sticky" : ""
183+ if ( this . domAfter ) this . domAfter . style . position = this . fixed ? "sticky" : ""
160184 }
161185 this . prevViewport = update . view . viewport
162186 }
163187
164188 syncGutters ( detach : boolean ) {
165189 let after = this . dom . nextSibling
166- if ( detach ) this . dom . remove ( )
190+ if ( detach ) {
191+ this . dom . remove ( )
192+ if ( this . domAfter ) this . domAfter . remove ( )
193+ }
167194 let lineClasses = RangeSet . iter ( this . view . state . facet ( gutterLineClass ) , this . view . viewport . from )
168195 let classSet : GutterMarker [ ] = [ ]
169196 let contexts = this . gutters . map ( gutter => new UpdateContext ( gutter , this . view . viewport , - this . view . documentPadding . top ) )
@@ -188,7 +215,10 @@ const gutterView = ViewPlugin.fromClass(class {
188215 }
189216 }
190217 for ( let cx of contexts ) cx . finish ( )
191- if ( detach ) this . view . scrollDOM . insertBefore ( this . dom , after )
218+ if ( detach ) {
219+ this . view . scrollDOM . insertBefore ( this . dom , after )
220+ if ( this . domAfter ) this . view . scrollDOM . appendChild ( this . domAfter )
221+ }
192222 }
193223
194224 updateGutters ( update : ViewUpdate ) {
@@ -214,7 +244,10 @@ const gutterView = ViewPlugin.fromClass(class {
214244 g . dom . remove ( )
215245 if ( gutters . indexOf ( g ) < 0 ) g . destroy ( )
216246 }
217- for ( let g of gutters ) this . dom . appendChild ( g . dom )
247+ for ( let g of gutters ) {
248+ if ( g . config . side == "after" ) this . getDOMAfter ( ) . appendChild ( g . dom )
249+ else this . dom . appendChild ( g . dom )
250+ }
218251 this . gutters = gutters
219252 }
220253 return change
@@ -223,14 +256,16 @@ const gutterView = ViewPlugin.fromClass(class {
223256 destroy ( ) {
224257 for ( let view of this . gutters ) view . destroy ( )
225258 this . dom . remove ( )
259+ if ( this . domAfter ) this . domAfter . remove ( )
226260 }
227261} , {
228262 provide : plugin => EditorView . scrollMargins . of ( view => {
229263 let value = view . plugin ( plugin )
230264 if ( ! value || value . gutters . length == 0 || ! value . fixed ) return null
265+ let before = value . dom . offsetWidth * view . scaleX , after = value . domAfter ? value . domAfter . offsetWidth * view . scaleX : 0
231266 return view . textDirection == Direction . LTR
232- ? { left : value . dom . offsetWidth * view . scaleX }
233- : { right : value . dom . offsetWidth * view . scaleX }
267+ ? { left : before , right : after }
268+ : { right : before , left : after }
234269 } )
235270} )
236271
0 commit comments