Fossil SCM
Style improvements. Hooked up the buttons but they don't yet fetch anything.
Commit
f0984389baa138b60a386cfdc121077c7549e4f2fbb28a1322dfb6348935a483
Parent
7cc651c87f0aedb…
2 files changed
+32
-17
+76
-27
+32
-17
| --- src/default.css | ||
| +++ src/default.css | ||
| @@ -535,38 +535,43 @@ | ||
| 535 | 535 | /* Rules governing diff layout and colors */ |
| 536 | 536 | table.diff { |
| 537 | 537 | width: 100%; |
| 538 | 538 | border-spacing: 0; |
| 539 | 539 | border: 1px solid black; |
| 540 | - padding: 0 0.5em; | |
| 540 | +} | |
| 541 | +table.diff td.diffln{ | |
| 542 | + padding: 0 0.25em 0 0.5em; | |
| 541 | 543 | } |
| 542 | 544 | table.diff td { |
| 543 | 545 | vertical-align: top; |
| 544 | 546 | } |
| 545 | 547 | table.diff pre { |
| 546 | 548 | margin: 0 0 0 0; |
| 547 | 549 | } |
| 548 | -tr.diffskip.jchunk:hover { | |
| 550 | +tr.diffskip.jchunk { | |
| 549 | 551 | /* jchunk gets added from JS to diffskip rows when they are |
| 550 | 552 | plugged into the /jchunk route and removed after that data |
| 551 | 553 | is fetched. */ |
| 554 | + background-color: aliceblue; | |
| 555 | + padding: 0; | |
| 556 | +} | |
| 557 | +tr.diffskip.jchunk > td { | |
| 558 | + padding: 0.25em 0.5em; | |
| 559 | + margin: 0; | |
| 552 | 560 | } |
| 553 | 561 | tr.diffskip.jchunk:hover { |
| 554 | 562 | /*background-color: rgba(127,127,127,0.5); |
| 555 | 563 | cursor: pointer;*/ |
| 556 | 564 | } |
| 557 | 565 | tr.diffskip > td.chunkctrl { |
| 558 | 566 | text-align: left; |
| 559 | 567 | font-family: monospace; |
| 560 | - /* Border is only for visibility during development. Remove it when done. */ | |
| 561 | - border-width: 1px; | |
| 562 | - border-style: dotted; | |
| 563 | 568 | } |
| 564 | 569 | tr.diffskip > td.chunkctrl > div { |
| 565 | 570 | /* Exists solely for layout purposes. */ |
| 566 | 571 | } |
| 567 | -tr.diffskip > td.chunkctrl > div > .button { | |
| 572 | +tr.diffskip > td.chunkctrl .button { | |
| 568 | 573 | min-width: 2.5em; |
| 569 | 574 | max-width: 2.5em; |
| 570 | 575 | text-align: center; |
| 571 | 576 | display: inline-block; |
| 572 | 577 | padding: 0.1em 1em; |
| @@ -578,25 +583,35 @@ | ||
| 578 | 583 | border-color: rgba(0,0,0,0);*/ |
| 579 | 584 | border-radius: 0.5em; |
| 580 | 585 | opacity: 0.7; |
| 581 | 586 | /*filter: drop-shadow(0.08em 0.08em 0.08em black);*/ |
| 582 | 587 | } |
| 583 | -tr.diffskip > td.chunkctrl > div > .button > span { | |
| 588 | +tr.diffskip > td.chunkctrl .button.up:not(.down){ | |
| 589 | + /* Simulate an arrow pointing up */ | |
| 590 | + border-radius: 3em 3em 0.25em 0.25em; | |
| 591 | +} | |
| 592 | +tr.diffskip > td.chunkctrl .button.down:not(.up){ | |
| 593 | + /* Simulate an arrow pointing down */ | |
| 594 | + border-radius: 0.25em 0.25em 3em 3em; | |
| 595 | +} | |
| 596 | +tr.diffskip > td.chunkctrl .button > span { | |
| 584 | 597 | /* In order to increase the glyph size w/o increasing the em-based |
| 585 | 598 | button size or border-radius, we need an extra layer of DOM |
| 586 | 599 | element for the glyph. */ |
| 587 | 600 | font-size: 150%; |
| 588 | 601 | } |
| 589 | -tr.diffskip > td.chunkctrl > div > .button.up:not(.down){ | |
| 590 | - /* Simulate an arrow pointing up */ | |
| 591 | - border-radius: 3em 3em 0.25em 0.25em; | |
| 592 | -} | |
| 593 | -tr.diffskip > td.chunkctrl > div > .button.down:not(.up){ | |
| 594 | - /* Simulate an arrow pointing down */ | |
| 595 | - border-radius: 0.25em 0.25em 3em 3em; | |
| 596 | -} | |
| 597 | -tr.diffskip > td.chunkctrl > div > .button:hover { | |
| 602 | +tr.diffskip > td.chunkctrl .button.up:not(.down) > span::before { | |
| 603 | + content: '⇡'; | |
| 604 | +} | |
| 605 | +tr.diffskip > td.chunkctrl .button.down:not(.up) > span::before { | |
| 606 | + content: '⇣'; | |
| 607 | +} | |
| 608 | +tr.diffskip > td.chunkctrl .button.up.down > span::before { | |
| 609 | + content: '⇡⇣'; | |
| 610 | +} | |
| 611 | + | |
| 612 | +tr.diffskip > td.chunkctrl .button:hover { | |
| 598 | 613 | /*border-color: rgba(75,75,75,1);*/ |
| 599 | 614 | cursor: pointer; |
| 600 | 615 | opacity: 1; |
| 601 | 616 | filter: contrast(3); |
| 602 | 617 | } |
| @@ -608,11 +623,11 @@ | ||
| 608 | 623 | td.difflne { |
| 609 | 624 | padding-bottom: 0.4em; |
| 610 | 625 | } |
| 611 | 626 | td.diffsep { |
| 612 | 627 | width: 1px; |
| 613 | - padding: 0 0.3em 0 1em; | |
| 628 | + padding: 0 0.3em 0 0.5em; | |
| 614 | 629 | } |
| 615 | 630 | td.difftxt pre { |
| 616 | 631 | overflow-x: auto; |
| 617 | 632 | } |
| 618 | 633 | td.diffln ins { |
| 619 | 634 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -535,38 +535,43 @@ | |
| 535 | /* Rules governing diff layout and colors */ |
| 536 | table.diff { |
| 537 | width: 100%; |
| 538 | border-spacing: 0; |
| 539 | border: 1px solid black; |
| 540 | padding: 0 0.5em; |
| 541 | } |
| 542 | table.diff td { |
| 543 | vertical-align: top; |
| 544 | } |
| 545 | table.diff pre { |
| 546 | margin: 0 0 0 0; |
| 547 | } |
| 548 | tr.diffskip.jchunk:hover { |
| 549 | /* jchunk gets added from JS to diffskip rows when they are |
| 550 | plugged into the /jchunk route and removed after that data |
| 551 | is fetched. */ |
| 552 | } |
| 553 | tr.diffskip.jchunk:hover { |
| 554 | /*background-color: rgba(127,127,127,0.5); |
| 555 | cursor: pointer;*/ |
| 556 | } |
| 557 | tr.diffskip > td.chunkctrl { |
| 558 | text-align: left; |
| 559 | font-family: monospace; |
| 560 | /* Border is only for visibility during development. Remove it when done. */ |
| 561 | border-width: 1px; |
| 562 | border-style: dotted; |
| 563 | } |
| 564 | tr.diffskip > td.chunkctrl > div { |
| 565 | /* Exists solely for layout purposes. */ |
| 566 | } |
| 567 | tr.diffskip > td.chunkctrl > div > .button { |
| 568 | min-width: 2.5em; |
| 569 | max-width: 2.5em; |
| 570 | text-align: center; |
| 571 | display: inline-block; |
| 572 | padding: 0.1em 1em; |
| @@ -578,25 +583,35 @@ | |
| 578 | border-color: rgba(0,0,0,0);*/ |
| 579 | border-radius: 0.5em; |
| 580 | opacity: 0.7; |
| 581 | /*filter: drop-shadow(0.08em 0.08em 0.08em black);*/ |
| 582 | } |
| 583 | tr.diffskip > td.chunkctrl > div > .button > span { |
| 584 | /* In order to increase the glyph size w/o increasing the em-based |
| 585 | button size or border-radius, we need an extra layer of DOM |
| 586 | element for the glyph. */ |
| 587 | font-size: 150%; |
| 588 | } |
| 589 | tr.diffskip > td.chunkctrl > div > .button.up:not(.down){ |
| 590 | /* Simulate an arrow pointing up */ |
| 591 | border-radius: 3em 3em 0.25em 0.25em; |
| 592 | } |
| 593 | tr.diffskip > td.chunkctrl > div > .button.down:not(.up){ |
| 594 | /* Simulate an arrow pointing down */ |
| 595 | border-radius: 0.25em 0.25em 3em 3em; |
| 596 | } |
| 597 | tr.diffskip > td.chunkctrl > div > .button:hover { |
| 598 | /*border-color: rgba(75,75,75,1);*/ |
| 599 | cursor: pointer; |
| 600 | opacity: 1; |
| 601 | filter: contrast(3); |
| 602 | } |
| @@ -608,11 +623,11 @@ | |
| 608 | td.difflne { |
| 609 | padding-bottom: 0.4em; |
| 610 | } |
| 611 | td.diffsep { |
| 612 | width: 1px; |
| 613 | padding: 0 0.3em 0 1em; |
| 614 | } |
| 615 | td.difftxt pre { |
| 616 | overflow-x: auto; |
| 617 | } |
| 618 | td.diffln ins { |
| 619 |
| --- src/default.css | |
| +++ src/default.css | |
| @@ -535,38 +535,43 @@ | |
| 535 | /* Rules governing diff layout and colors */ |
| 536 | table.diff { |
| 537 | width: 100%; |
| 538 | border-spacing: 0; |
| 539 | border: 1px solid black; |
| 540 | } |
| 541 | table.diff td.diffln{ |
| 542 | padding: 0 0.25em 0 0.5em; |
| 543 | } |
| 544 | table.diff td { |
| 545 | vertical-align: top; |
| 546 | } |
| 547 | table.diff pre { |
| 548 | margin: 0 0 0 0; |
| 549 | } |
| 550 | tr.diffskip.jchunk { |
| 551 | /* jchunk gets added from JS to diffskip rows when they are |
| 552 | plugged into the /jchunk route and removed after that data |
| 553 | is fetched. */ |
| 554 | background-color: aliceblue; |
| 555 | padding: 0; |
| 556 | } |
| 557 | tr.diffskip.jchunk > td { |
| 558 | padding: 0.25em 0.5em; |
| 559 | margin: 0; |
| 560 | } |
| 561 | tr.diffskip.jchunk:hover { |
| 562 | /*background-color: rgba(127,127,127,0.5); |
| 563 | cursor: pointer;*/ |
| 564 | } |
| 565 | tr.diffskip > td.chunkctrl { |
| 566 | text-align: left; |
| 567 | font-family: monospace; |
| 568 | } |
| 569 | tr.diffskip > td.chunkctrl > div { |
| 570 | /* Exists solely for layout purposes. */ |
| 571 | } |
| 572 | tr.diffskip > td.chunkctrl .button { |
| 573 | min-width: 2.5em; |
| 574 | max-width: 2.5em; |
| 575 | text-align: center; |
| 576 | display: inline-block; |
| 577 | padding: 0.1em 1em; |
| @@ -578,25 +583,35 @@ | |
| 583 | border-color: rgba(0,0,0,0);*/ |
| 584 | border-radius: 0.5em; |
| 585 | opacity: 0.7; |
| 586 | /*filter: drop-shadow(0.08em 0.08em 0.08em black);*/ |
| 587 | } |
| 588 | tr.diffskip > td.chunkctrl .button.up:not(.down){ |
| 589 | /* Simulate an arrow pointing up */ |
| 590 | border-radius: 3em 3em 0.25em 0.25em; |
| 591 | } |
| 592 | tr.diffskip > td.chunkctrl .button.down:not(.up){ |
| 593 | /* Simulate an arrow pointing down */ |
| 594 | border-radius: 0.25em 0.25em 3em 3em; |
| 595 | } |
| 596 | tr.diffskip > td.chunkctrl .button > span { |
| 597 | /* In order to increase the glyph size w/o increasing the em-based |
| 598 | button size or border-radius, we need an extra layer of DOM |
| 599 | element for the glyph. */ |
| 600 | font-size: 150%; |
| 601 | } |
| 602 | tr.diffskip > td.chunkctrl .button.up:not(.down) > span::before { |
| 603 | content: '⇡'; |
| 604 | } |
| 605 | tr.diffskip > td.chunkctrl .button.down:not(.up) > span::before { |
| 606 | content: '⇣'; |
| 607 | } |
| 608 | tr.diffskip > td.chunkctrl .button.up.down > span::before { |
| 609 | content: '⇡⇣'; |
| 610 | } |
| 611 | |
| 612 | tr.diffskip > td.chunkctrl .button:hover { |
| 613 | /*border-color: rgba(75,75,75,1);*/ |
| 614 | cursor: pointer; |
| 615 | opacity: 1; |
| 616 | filter: contrast(3); |
| 617 | } |
| @@ -608,11 +623,11 @@ | |
| 623 | td.difflne { |
| 624 | padding-bottom: 0.4em; |
| 625 | } |
| 626 | td.diffsep { |
| 627 | width: 1px; |
| 628 | padding: 0 0.3em 0 0.5em; |
| 629 | } |
| 630 | td.difftxt pre { |
| 631 | overflow-x: auto; |
| 632 | } |
| 633 | td.diffln ins { |
| 634 |
+76
-27
| --- src/fossil.diff.js | ||
| +++ src/fossil.diff.js | ||
| @@ -205,42 +205,51 @@ | ||
| 205 | 205 | }); |
| 206 | 206 | }; |
| 207 | 207 | |
| 208 | 208 | /** |
| 209 | 209 | Installs chunk-loading controls into TR element tr. isSplit is true |
| 210 | - if the parent table is a split diff, else false.) | |
| 211 | - | |
| 210 | + if the parent table is a split diff, else false. | |
| 212 | 211 | |
| 213 | 212 | The goal is to base these controls closely on github's, a good example |
| 214 | 213 | of which, for use as a model, is: |
| 215 | 214 | |
| 216 | 215 | https://github.com/msteveb/autosetup/commit/235925e914a52a542 |
| 216 | + | |
| 217 | + Each instance corresponds to a single TR.diffskip element. | |
| 217 | 218 | */ |
| 218 | 219 | Diff.ChunkLoadControls = function(isSplit, tr){ |
| 219 | 220 | this.isSplit = isSplit; |
| 220 | - this.e = {/*DOM elements*/}; | |
| 221 | - this.pos = { | |
| 222 | - start: +tr.dataset.startln, | |
| 223 | - end: +tr.dataset.endln | |
| 221 | + this.e = {/*DOM elements*/ | |
| 222 | + tr: tr | |
| 224 | 223 | }; |
| 225 | 224 | tr.$chunker = this /* keep GC from reaping this */; |
| 226 | - this.e.tr = tr; | |
| 225 | + this.pos = { | |
| 226 | + /* These line numbers correspond to the LHS file. Because the | |
| 227 | + contents are common to both sides, we have the same number | |
| 228 | + for the RHS, but need to extract those line numbers from the | |
| 229 | + neighboring TR blocks */ | |
| 230 | + startLhs: +tr.dataset.startln, | |
| 231 | + endLhs: +tr.dataset.endln | |
| 232 | + }; | |
| 227 | 233 | D.clearElement(tr); |
| 228 | 234 | this.e.td = D.addClass( |
| 235 | + /* Holder for our UI controls */ | |
| 229 | 236 | D.attr(D.td(tr), 'colspan', isSplit ? 5 : 4), |
| 230 | 237 | 'chunkctrl' |
| 231 | 238 | ); |
| 232 | 239 | this.e.btnWrapper = D.div(); |
| 233 | 240 | D.append(this.e.td, this.e.btnWrapper); |
| 234 | 241 | /** |
| 235 | - Depending on various factors, we need one of: | |
| 242 | + Depending on various factors, we need one or more of: | |
| 243 | + | |
| 244 | + - A single button to load the initial chunk incrementally | |
| 236 | 245 | |
| 237 | 246 | - A single button to load all lines then remove this control |
| 238 | 247 | |
| 239 | - - A single button to load the initial chunk | |
| 240 | - | |
| 241 | 248 | - Two buttons: one to load upwards, one to load downwards |
| 249 | + | |
| 250 | + - A single button to load the final chunk incrementally | |
| 242 | 251 | */ |
| 243 | 252 | if(tr.nextElementSibling){ |
| 244 | 253 | this.pos.next = { |
| 245 | 254 | startLhs: extractLineNo(true, true, tr.nextElementSibling, isSplit), |
| 246 | 255 | startRhs: extractLineNo(false, true, tr.nextElementSibling, isSplit) |
| @@ -259,40 +268,65 @@ | ||
| 259 | 268 | /* Place a single button to load the whole block, rather |
| 260 | 269 | than separate up/down buttons. */ |
| 261 | 270 | btnDown = false; |
| 262 | 271 | btnUp = D.append( |
| 263 | 272 | D.addClass(D.span(), 'button', 'up', 'down'), |
| 264 | - D.append(D.span(), this.config.glyphDown, this.config.glyphUp) | |
| 273 | + D.span(/*glyph holder*/) | |
| 274 | + //D.append(D.span(), this.config.glyphDown, this.config.glyphUp) | |
| 265 | 275 | ); |
| 266 | 276 | }else{ |
| 267 | 277 | /* Figure out which chunk-load buttons to add... */ |
| 268 | 278 | if(this.pos.prev){ |
| 269 | 279 | btnDown = D.append( |
| 270 | 280 | D.addClass(D.span(), 'button', 'down'), |
| 271 | - D.append(D.span(), this.config.glyphDown) | |
| 281 | + D.span(/*glyph holder*/) | |
| 282 | + //D.append(D.span(), this.config.glyphDown) | |
| 272 | 283 | ); |
| 273 | 284 | } |
| 274 | 285 | if(this.pos.next){ |
| 275 | 286 | btnUp = D.append( |
| 276 | 287 | D.addClass(D.span(), 'button', 'up'), |
| 277 | - D.append(D.span(), this.config.glyphUp) | |
| 288 | + D.span(/*glyph holder*/) | |
| 289 | + //D.append(D.span(), this.config.glyphUp) | |
| 278 | 290 | ); |
| 279 | 291 | } |
| 280 | 292 | } |
| 281 | - if(btnDown) D.append(this.e.btnWrapper, btnDown); | |
| 282 | - if(btnUp) D.append(this.e.btnWrapper, btnUp); | |
| 283 | - D.append(this.e.btnWrapper, D.append(D.span(), JSON.stringify(this.pos))); | |
| 293 | + if(btnDown){ | |
| 294 | + D.append(this.e.btnWrapper, btnDown); | |
| 295 | + btnDown.addEventListener('click', ()=>this.fetchChunk(1),false); | |
| 296 | + } | |
| 297 | + if(btnUp){ | |
| 298 | + D.append(this.e.btnWrapper, btnUp); | |
| 299 | + btnUp.addEventListener( | |
| 300 | + 'click', ()=>this.fetchChunk(btnUp.classList.contains('down') ? 0 : -1), | |
| 301 | + false); | |
| 302 | + } | |
| 303 | + /* For debugging only... */ | |
| 304 | + this.e.posState = D.span(); | |
| 305 | + D.append(this.e.btnWrapper, this.e.posState); | |
| 306 | + this.updatePosDebug(); | |
| 284 | 307 | }; |
| 285 | 308 | |
| 286 | 309 | Diff.ChunkLoadControls.prototype = { |
| 287 | 310 | config: { |
| 311 | + /* | |
| 288 | 312 | glyphUp: '⇡', //'&#uarr;', |
| 289 | 313 | glyphDown: '⇣' //'&#darr;' |
| 314 | + */ | |
| 315 | + }, | |
| 316 | + updatePosDebug: function(){ | |
| 317 | + if(this.e.posState){ | |
| 318 | + D.append(D.clearElement(this.e.posState), JSON.stringify(this.pos)); | |
| 319 | + } | |
| 320 | + return this; | |
| 290 | 321 | }, |
| 322 | + | |
| 291 | 323 | destroy: function(){ |
| 292 | 324 | delete this.tr.$chunker; |
| 293 | - D.remove(this.tr); | |
| 325 | + D.remove(this.e.tr); | |
| 326 | + delete this.e; | |
| 327 | + delete this.pos; | |
| 294 | 328 | }, |
| 295 | 329 | /** |
| 296 | 330 | Creates and returns a new TR element, including its TD elements (depending |
| 297 | 331 | on this.isSplit), but does not fill it with any information nor inject it |
| 298 | 332 | into the table (it doesn't know where to do so). |
| @@ -310,29 +344,44 @@ | ||
| 310 | 344 | D.append(D.addClass( D.td(tr), 'diffln', 'difflnr' ), D.pre()); |
| 311 | 345 | D.addClass( D.td(tr), 'diffsep' ); |
| 312 | 346 | D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtu' ), D.pre()); |
| 313 | 347 | } |
| 314 | 348 | return tr; |
| 349 | + }, | |
| 350 | + | |
| 351 | + fetchChunk: function(direction/*-1=prev, 1=next, 0=both*/){ | |
| 352 | + /* Forewarning, this is a bit confusing: when fetching the | |
| 353 | + previous lines, we're doing so on behalf of the *next* diff | |
| 354 | + chunk (this.pos.next), and vice versa. */ | |
| 355 | + if(this.isFetching) return this; | |
| 356 | + if(direction<0/*prev chunk*/ && !this.pos.next){ | |
| 357 | + console.error("Attempt to fetch previous diff lines but don't have any."); | |
| 358 | + return this; | |
| 359 | + }else if(direction>0/*next chunk*/ && !this.pos.prev){ | |
| 360 | + console.error("Attempt to fetch next diff lines but don't have any."); | |
| 361 | + return this; | |
| 362 | + } | |
| 363 | + console.debug("Going to fetch in direction",direction); | |
| 364 | + this.updatePosDebug(); | |
| 365 | + return this; | |
| 315 | 366 | } |
| 316 | 367 | }; |
| 317 | 368 | |
| 318 | 369 | Diff.addDiffSkipHandlers = function(){ |
| 319 | - const tables = document.querySelectorAll('table.diff[data-lefthash]'); | |
| 320 | - if(!tables.length) return F; | |
| 321 | - const addDiffSkipToTr = function f(isSplit, tr){ | |
| 322 | - D.addClass(tr, 'jchunk'); | |
| 323 | - //tr.addEventListener('click', f._handler, false); | |
| 324 | - /* TODO/in progress... */ | |
| 325 | - new Diff.ChunkLoadControls(isSplit, tr); | |
| 326 | - }; | |
| 370 | + const tables = document.querySelectorAll('table.diff[data-lefthash]:not(.diffskipped)'); | |
| 371 | + /* Potential performance-related TODO: instead of installing all | |
| 372 | + of these at once, install them as the corresponding TR is | |
| 373 | + scrolled into view. */ | |
| 327 | 374 | tables.forEach(function(table){ |
| 375 | + D.addClass(table, 'diffskipped'/*avoid processing these more than once */); | |
| 376 | + const isSplit = table.classList.contains('splitdiff')/*else udiff*/; | |
| 328 | 377 | table.querySelectorAll('tr.diffskip[data-startln]').forEach(function(tr){ |
| 329 | - addDiffSkipToTr(table.classList.contains('splitdiff')/*else udiff*/, tr); | |
| 378 | + new Diff.ChunkLoadControls(isSplit, D.addClass(tr, 'jchunk')); | |
| 330 | 379 | }); |
| 331 | 380 | }); |
| 381 | + return F; | |
| 332 | 382 | }; |
| 333 | - | |
| 334 | 383 | Diff.addDiffSkipHandlers(); |
| 335 | 384 | }); |
| 336 | 385 | |
| 337 | 386 | /** |
| 338 | 387 | 2021-09-07: refactoring the following for use in the higher-level |
| 339 | 388 |
| --- src/fossil.diff.js | |
| +++ src/fossil.diff.js | |
| @@ -205,42 +205,51 @@ | |
| 205 | }); |
| 206 | }; |
| 207 | |
| 208 | /** |
| 209 | Installs chunk-loading controls into TR element tr. isSplit is true |
| 210 | if the parent table is a split diff, else false.) |
| 211 | |
| 212 | |
| 213 | The goal is to base these controls closely on github's, a good example |
| 214 | of which, for use as a model, is: |
| 215 | |
| 216 | https://github.com/msteveb/autosetup/commit/235925e914a52a542 |
| 217 | */ |
| 218 | Diff.ChunkLoadControls = function(isSplit, tr){ |
| 219 | this.isSplit = isSplit; |
| 220 | this.e = {/*DOM elements*/}; |
| 221 | this.pos = { |
| 222 | start: +tr.dataset.startln, |
| 223 | end: +tr.dataset.endln |
| 224 | }; |
| 225 | tr.$chunker = this /* keep GC from reaping this */; |
| 226 | this.e.tr = tr; |
| 227 | D.clearElement(tr); |
| 228 | this.e.td = D.addClass( |
| 229 | D.attr(D.td(tr), 'colspan', isSplit ? 5 : 4), |
| 230 | 'chunkctrl' |
| 231 | ); |
| 232 | this.e.btnWrapper = D.div(); |
| 233 | D.append(this.e.td, this.e.btnWrapper); |
| 234 | /** |
| 235 | Depending on various factors, we need one of: |
| 236 | |
| 237 | - A single button to load all lines then remove this control |
| 238 | |
| 239 | - A single button to load the initial chunk |
| 240 | |
| 241 | - Two buttons: one to load upwards, one to load downwards |
| 242 | */ |
| 243 | if(tr.nextElementSibling){ |
| 244 | this.pos.next = { |
| 245 | startLhs: extractLineNo(true, true, tr.nextElementSibling, isSplit), |
| 246 | startRhs: extractLineNo(false, true, tr.nextElementSibling, isSplit) |
| @@ -259,40 +268,65 @@ | |
| 259 | /* Place a single button to load the whole block, rather |
| 260 | than separate up/down buttons. */ |
| 261 | btnDown = false; |
| 262 | btnUp = D.append( |
| 263 | D.addClass(D.span(), 'button', 'up', 'down'), |
| 264 | D.append(D.span(), this.config.glyphDown, this.config.glyphUp) |
| 265 | ); |
| 266 | }else{ |
| 267 | /* Figure out which chunk-load buttons to add... */ |
| 268 | if(this.pos.prev){ |
| 269 | btnDown = D.append( |
| 270 | D.addClass(D.span(), 'button', 'down'), |
| 271 | D.append(D.span(), this.config.glyphDown) |
| 272 | ); |
| 273 | } |
| 274 | if(this.pos.next){ |
| 275 | btnUp = D.append( |
| 276 | D.addClass(D.span(), 'button', 'up'), |
| 277 | D.append(D.span(), this.config.glyphUp) |
| 278 | ); |
| 279 | } |
| 280 | } |
| 281 | if(btnDown) D.append(this.e.btnWrapper, btnDown); |
| 282 | if(btnUp) D.append(this.e.btnWrapper, btnUp); |
| 283 | D.append(this.e.btnWrapper, D.append(D.span(), JSON.stringify(this.pos))); |
| 284 | }; |
| 285 | |
| 286 | Diff.ChunkLoadControls.prototype = { |
| 287 | config: { |
| 288 | glyphUp: '⇡', //'&#uarr;', |
| 289 | glyphDown: '⇣' //'&#darr;' |
| 290 | }, |
| 291 | destroy: function(){ |
| 292 | delete this.tr.$chunker; |
| 293 | D.remove(this.tr); |
| 294 | }, |
| 295 | /** |
| 296 | Creates and returns a new TR element, including its TD elements (depending |
| 297 | on this.isSplit), but does not fill it with any information nor inject it |
| 298 | into the table (it doesn't know where to do so). |
| @@ -310,29 +344,44 @@ | |
| 310 | D.append(D.addClass( D.td(tr), 'diffln', 'difflnr' ), D.pre()); |
| 311 | D.addClass( D.td(tr), 'diffsep' ); |
| 312 | D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtu' ), D.pre()); |
| 313 | } |
| 314 | return tr; |
| 315 | } |
| 316 | }; |
| 317 | |
| 318 | Diff.addDiffSkipHandlers = function(){ |
| 319 | const tables = document.querySelectorAll('table.diff[data-lefthash]'); |
| 320 | if(!tables.length) return F; |
| 321 | const addDiffSkipToTr = function f(isSplit, tr){ |
| 322 | D.addClass(tr, 'jchunk'); |
| 323 | //tr.addEventListener('click', f._handler, false); |
| 324 | /* TODO/in progress... */ |
| 325 | new Diff.ChunkLoadControls(isSplit, tr); |
| 326 | }; |
| 327 | tables.forEach(function(table){ |
| 328 | table.querySelectorAll('tr.diffskip[data-startln]').forEach(function(tr){ |
| 329 | addDiffSkipToTr(table.classList.contains('splitdiff')/*else udiff*/, tr); |
| 330 | }); |
| 331 | }); |
| 332 | }; |
| 333 | |
| 334 | Diff.addDiffSkipHandlers(); |
| 335 | }); |
| 336 | |
| 337 | /** |
| 338 | 2021-09-07: refactoring the following for use in the higher-level |
| 339 |
| --- src/fossil.diff.js | |
| +++ src/fossil.diff.js | |
| @@ -205,42 +205,51 @@ | |
| 205 | }); |
| 206 | }; |
| 207 | |
| 208 | /** |
| 209 | Installs chunk-loading controls into TR element tr. isSplit is true |
| 210 | if the parent table is a split diff, else false. |
| 211 | |
| 212 | The goal is to base these controls closely on github's, a good example |
| 213 | of which, for use as a model, is: |
| 214 | |
| 215 | https://github.com/msteveb/autosetup/commit/235925e914a52a542 |
| 216 | |
| 217 | Each instance corresponds to a single TR.diffskip element. |
| 218 | */ |
| 219 | Diff.ChunkLoadControls = function(isSplit, tr){ |
| 220 | this.isSplit = isSplit; |
| 221 | this.e = {/*DOM elements*/ |
| 222 | tr: tr |
| 223 | }; |
| 224 | tr.$chunker = this /* keep GC from reaping this */; |
| 225 | this.pos = { |
| 226 | /* These line numbers correspond to the LHS file. Because the |
| 227 | contents are common to both sides, we have the same number |
| 228 | for the RHS, but need to extract those line numbers from the |
| 229 | neighboring TR blocks */ |
| 230 | startLhs: +tr.dataset.startln, |
| 231 | endLhs: +tr.dataset.endln |
| 232 | }; |
| 233 | D.clearElement(tr); |
| 234 | this.e.td = D.addClass( |
| 235 | /* Holder for our UI controls */ |
| 236 | D.attr(D.td(tr), 'colspan', isSplit ? 5 : 4), |
| 237 | 'chunkctrl' |
| 238 | ); |
| 239 | this.e.btnWrapper = D.div(); |
| 240 | D.append(this.e.td, this.e.btnWrapper); |
| 241 | /** |
| 242 | Depending on various factors, we need one or more of: |
| 243 | |
| 244 | - A single button to load the initial chunk incrementally |
| 245 | |
| 246 | - A single button to load all lines then remove this control |
| 247 | |
| 248 | - Two buttons: one to load upwards, one to load downwards |
| 249 | |
| 250 | - A single button to load the final chunk incrementally |
| 251 | */ |
| 252 | if(tr.nextElementSibling){ |
| 253 | this.pos.next = { |
| 254 | startLhs: extractLineNo(true, true, tr.nextElementSibling, isSplit), |
| 255 | startRhs: extractLineNo(false, true, tr.nextElementSibling, isSplit) |
| @@ -259,40 +268,65 @@ | |
| 268 | /* Place a single button to load the whole block, rather |
| 269 | than separate up/down buttons. */ |
| 270 | btnDown = false; |
| 271 | btnUp = D.append( |
| 272 | D.addClass(D.span(), 'button', 'up', 'down'), |
| 273 | D.span(/*glyph holder*/) |
| 274 | //D.append(D.span(), this.config.glyphDown, this.config.glyphUp) |
| 275 | ); |
| 276 | }else{ |
| 277 | /* Figure out which chunk-load buttons to add... */ |
| 278 | if(this.pos.prev){ |
| 279 | btnDown = D.append( |
| 280 | D.addClass(D.span(), 'button', 'down'), |
| 281 | D.span(/*glyph holder*/) |
| 282 | //D.append(D.span(), this.config.glyphDown) |
| 283 | ); |
| 284 | } |
| 285 | if(this.pos.next){ |
| 286 | btnUp = D.append( |
| 287 | D.addClass(D.span(), 'button', 'up'), |
| 288 | D.span(/*glyph holder*/) |
| 289 | //D.append(D.span(), this.config.glyphUp) |
| 290 | ); |
| 291 | } |
| 292 | } |
| 293 | if(btnDown){ |
| 294 | D.append(this.e.btnWrapper, btnDown); |
| 295 | btnDown.addEventListener('click', ()=>this.fetchChunk(1),false); |
| 296 | } |
| 297 | if(btnUp){ |
| 298 | D.append(this.e.btnWrapper, btnUp); |
| 299 | btnUp.addEventListener( |
| 300 | 'click', ()=>this.fetchChunk(btnUp.classList.contains('down') ? 0 : -1), |
| 301 | false); |
| 302 | } |
| 303 | /* For debugging only... */ |
| 304 | this.e.posState = D.span(); |
| 305 | D.append(this.e.btnWrapper, this.e.posState); |
| 306 | this.updatePosDebug(); |
| 307 | }; |
| 308 | |
| 309 | Diff.ChunkLoadControls.prototype = { |
| 310 | config: { |
| 311 | /* |
| 312 | glyphUp: '⇡', //'&#uarr;', |
| 313 | glyphDown: '⇣' //'&#darr;' |
| 314 | */ |
| 315 | }, |
| 316 | updatePosDebug: function(){ |
| 317 | if(this.e.posState){ |
| 318 | D.append(D.clearElement(this.e.posState), JSON.stringify(this.pos)); |
| 319 | } |
| 320 | return this; |
| 321 | }, |
| 322 | |
| 323 | destroy: function(){ |
| 324 | delete this.tr.$chunker; |
| 325 | D.remove(this.e.tr); |
| 326 | delete this.e; |
| 327 | delete this.pos; |
| 328 | }, |
| 329 | /** |
| 330 | Creates and returns a new TR element, including its TD elements (depending |
| 331 | on this.isSplit), but does not fill it with any information nor inject it |
| 332 | into the table (it doesn't know where to do so). |
| @@ -310,29 +344,44 @@ | |
| 344 | D.append(D.addClass( D.td(tr), 'diffln', 'difflnr' ), D.pre()); |
| 345 | D.addClass( D.td(tr), 'diffsep' ); |
| 346 | D.append(D.addClass( D.td(tr), 'difftxt', 'difftxtu' ), D.pre()); |
| 347 | } |
| 348 | return tr; |
| 349 | }, |
| 350 | |
| 351 | fetchChunk: function(direction/*-1=prev, 1=next, 0=both*/){ |
| 352 | /* Forewarning, this is a bit confusing: when fetching the |
| 353 | previous lines, we're doing so on behalf of the *next* diff |
| 354 | chunk (this.pos.next), and vice versa. */ |
| 355 | if(this.isFetching) return this; |
| 356 | if(direction<0/*prev chunk*/ && !this.pos.next){ |
| 357 | console.error("Attempt to fetch previous diff lines but don't have any."); |
| 358 | return this; |
| 359 | }else if(direction>0/*next chunk*/ && !this.pos.prev){ |
| 360 | console.error("Attempt to fetch next diff lines but don't have any."); |
| 361 | return this; |
| 362 | } |
| 363 | console.debug("Going to fetch in direction",direction); |
| 364 | this.updatePosDebug(); |
| 365 | return this; |
| 366 | } |
| 367 | }; |
| 368 | |
| 369 | Diff.addDiffSkipHandlers = function(){ |
| 370 | const tables = document.querySelectorAll('table.diff[data-lefthash]:not(.diffskipped)'); |
| 371 | /* Potential performance-related TODO: instead of installing all |
| 372 | of these at once, install them as the corresponding TR is |
| 373 | scrolled into view. */ |
| 374 | tables.forEach(function(table){ |
| 375 | D.addClass(table, 'diffskipped'/*avoid processing these more than once */); |
| 376 | const isSplit = table.classList.contains('splitdiff')/*else udiff*/; |
| 377 | table.querySelectorAll('tr.diffskip[data-startln]').forEach(function(tr){ |
| 378 | new Diff.ChunkLoadControls(isSplit, D.addClass(tr, 'jchunk')); |
| 379 | }); |
| 380 | }); |
| 381 | return F; |
| 382 | }; |
| 383 | Diff.addDiffSkipHandlers(); |
| 384 | }); |
| 385 | |
| 386 | /** |
| 387 | 2021-09-07: refactoring the following for use in the higher-level |
| 388 |