Many hyperlinks are disabled.
Use anonymous login
to enable hyperlinks.
Overview
Comment: | Style tweaks and re-did how the OPTION elements are marked is-new/is-modified so that the mobile browsers can show that state. |
---|---|
Downloads: | Tarball | ZIP archive |
Timelines: | family | ancestors | descendants | both | trunk |
Files: | files | file ages | folders |
SHA3-256: |
d9f4b6dbedbe051de94fad5f91ce6fa0 |
User & Date: | stephan 2020-08-01 17:56:24.361 |
Context
2020-08-01
| ||
18:47 | Updated the wiki CLI command to account for the sandbox pseudo-page and removed an obsolete TODO. ... (check-in: 7bc942704d user: stephan tags: trunk) | |
17:56 | Style tweaks and re-did how the OPTION elements are marked is-new/is-modified so that the mobile browsers can show that state. ... (check-in: d9f4b6dbed user: stephan tags: trunk) | |
16:07 | Reworked how /wikiedit edit status is displayed, added history/attachment links to the new info bar, and remove attachment links from the Help tab. ... (check-in: fb77abd3b5 user: stephan tags: trunk) | |
Changes
Changes to src/fossil.page.wikiedit.js.
︙ | ︙ | |||
63 64 65 66 67 68 69 | ); */ const E = (s)=>document.querySelector(s), D = F.dom, P = F.page; P.config = { | | < < | 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 | ); */ const E = (s)=>document.querySelector(s), D = F.dom, P = F.page; P.config = { /* Symbolic markers to denote certain edit state. */ editStateMarkers: { isNew: '[+]', isModified: '[*]' } }; /** |
︙ | ︙ | |||
266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 | forceEvent = true; } if(forceEvent){ // Force UI update s.dispatchEvent(new Event('change',{target:s})); } }; /** Sets up and maintains the widgets for the list of wiki pages. */ const WikiList = { e: { filterCheckboxes: { /*map of wiki page type to checkbox for list filtering purposes, except for "sandbox" type, which is assumed to be covered by the "normal" type filter. */}, }, cache: { names: { /* Map of page names to "something." We don't map to their winfo bits because those regularly get swapped out via de/serialization. We need this map to support the add-new-page feature, to give us a way to check for dupes without asking the server or walking through the whole selection list. */} }, | > > > > > > > > > > > > > > > > > > > > > > > > > > > > | | > > > > > > > > > > | < > | | | | > | | > | | | | > | | > > > | > | 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 | forceEvent = true; } if(forceEvent){ // Force UI update s.dispatchEvent(new Event('change',{target:s})); } }; /** Internal helper to get an edit status indicator for the given winfo object. */ const getEditMarker = function f(winfo, textOnly){ const esm = P.config.editStateMarkers; if(1===winfo){ /* force is-new */ return textOnly ? esm.isNew : D.addClass(D.append(D.span(),esm.isNew), 'is-new'); }else if(2===winfo){ /* force is-modified */ return textOnly ? esm.isModified : D.addClass(D.append(D.span(),esm.isModified), 'is-modified'); }else if(winfo && winfo.version){ /* is existing page modified? */ if($stash.getWinfo(winfo)){ return textOnly ? esm.isModified : D.addClass(D.append(D.span(),esm.isModified), 'is-modified'); } } else if(winfo){ /* is new non-sandbox or is modified sandbox? */ if('sandbox'!==winfo.type){ return textOnly ? esm.isNew : D.addClass(D.append(D.span(),esm.isNew), 'is-new'); }else if($stash.getWinfo(winfo)){ return textOnly ? esm.isModified : D.addClass(D.append(D.span(),esm.isModified), 'is-modified'); } } return textOnly ? '' : D.span(); }; /** Sets up and maintains the widgets for the list of wiki pages. */ const WikiList = { e: { filterCheckboxes: { /*map of wiki page type to checkbox for list filtering purposes, except for "sandbox" type, which is assumed to be covered by the "normal" type filter. */}, }, cache: { names: { /* Map of page names to "something." We don't map to their winfo bits because those regularly get swapped out via de/serialization. We need this map to support the add-new-page feature, to give us a way to check for dupes without asking the server or walking through the whole selection list. */} }, /** Updates OPTION elements to reflect whether the page has local changes or is new/unsaved. This implementation is horribly inefficient, in that we have to walk and validate the whole list for each stash-level change. Reminder to self: in order to mark is-edited/is-new state we have to update the OPTION element's inner text to reflect the is-modified/is-new flags, rather than use CSS classes to tag them, because mobile Chrome can neither restyle OPTION elements no render ::before content on them. We *also* use CSS tags, but they aren't sufficient for the mobile browsers. */ _refreshStashMarks: function callee(){ if(!callee.eachOpt){ const self = this; callee.eachOpt = function(key){ const opt = self.e.select.options[key]; const stashed = $stash.getWinfo({name:opt.value}); var prefix = ''; if(stashed){ const isNew = 'sandbox'===stashed.type ? false : !stashed.version; prefix = getEditMarker(isNew ? 1 : 2, true); D.addClass(opt, isNew ? 'stashed-new' : 'stashed'); }else{ D.removeClass(opt, 'stashed', 'stashed-new'); } opt.innerText = prefix + opt.value; self.cache.names[opt.value] = true; }; } this.cache.names = {/*must reset it to acount for local page removals*/}; Object.keys(this.e.select.options).forEach(callee.eachOpt); }, /** Removes the given wiki page entry from the page selection list, if it's in the list. */ removeEntry: function(name){ const sel = this.e.select; var ndx = sel.selectedIndex; sel.value = name; if(sel.selectedIndex>-1){ if(ndx === sel.selectedIndex) ndx = -1; sel.options.remove(sel.selectedIndex); } sel.selectedIndex = ndx; }, /** Rebuilds the selection list. Necessary when it's loaded from the server or we locally create a new page. */ _rebuildList: function callee(){ /* Jump through some hoops to integrate new/unsaved pages into the list of existing pages... We use a map as an intermediary in order to filter out any local-stash dupes from server-side copies. */ const list = this.cache.pageList; if(!list) return; |
︙ | ︙ | |||
354 355 356 357 358 359 360 | const wtype = opt.dataset.wtype = winfo.type==='sandbox' ? 'normal' : (winfo.type||'normal'); const cb = self.e.filterCheckboxes[wtype]; if(cb && !cb.checked) D.addClass(opt, 'hidden'); }); D.enable(sel); if(P.winfo) sel.value = P.winfo.name; | | | 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 | const wtype = opt.dataset.wtype = winfo.type==='sandbox' ? 'normal' : (winfo.type||'normal'); const cb = self.e.filterCheckboxes[wtype]; if(cb && !cb.checked) D.addClass(opt, 'hidden'); }); D.enable(sel); if(P.winfo) sel.value = P.winfo.name; this._refreshStashMarks(); }, /** Loads the page list and populates the selection list. */ loadList: function callee(){ delete this.pageMap; if(!callee.onload){ const self = this; |
︙ | ︙ | |||
451 452 453 454 455 456 457 | sel) ); D.attr(sel, 'size', 15); D.option(D.disable(D.clearElement(sel)), "Loading..."); /** Set up filter checkboxes for the various types of wiki pages... */ | | | 494 495 496 497 498 499 500 501 502 503 504 505 506 507 508 | sel) ); D.attr(sel, 'size', 15); D.option(D.disable(D.clearElement(sel)), "Loading..."); /** Set up filter checkboxes for the various types of wiki pages... */ const fsFilter = D.fieldset("Page types"), fsFilterBody = D.div(), filters = ['normal', 'branch', 'checkin', 'tag'] ; D.append(fsFilter, fsFilterBody); D.addClass(fsFilterBody, 'flex-container', 'flex-column', 'stretch'); const filterSelection = function(wtype, show){ sel.querySelectorAll('option[data-wtype='+wtype+']').forEach(function(opt){ |
︙ | ︙ | |||
489 490 491 492 493 494 495 | the OPTION elements to denote certain state. */ const fsLegend = D.fieldset("Edit status"), fsLegendBody = D.div(); D.append(fsLegend, fsLegendBody); D.addClass(fsLegendBody, 'flex-container', 'flex-column', 'stretch'); D.append( fsLegendBody, | | | < < | 532 533 534 535 536 537 538 539 540 541 542 543 544 545 546 547 | the OPTION elements to denote certain state. */ const fsLegend = D.fieldset("Edit status"), fsLegendBody = D.div(); D.append(fsLegend, fsLegendBody); D.addClass(fsLegendBody, 'flex-container', 'flex-column', 'stretch'); D.append( fsLegendBody, D.append(D.span(), getEditMarker(1,false)," = page is new/unsaved"), D.append(D.span(), getEditMarker(2,false)," = page has local edits") ); const fsNewPage = D.fieldset("Create new page"), fsNewPageBody = D.div(), newPageName = D.input('text'), newPageBtn = D.button("Add page locally") ; |
︙ | ︙ | |||
526 527 528 529 530 531 532 | D.append(parentElem, btn); btn.addEventListener('click', ()=>this.loadList(), false); this.loadList(); const onSelect = (e)=>P.loadPage(e.target.value); sel.addEventListener('change', onSelect, false); sel.addEventListener('dblclick', onSelect, false); | | | 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 | D.append(parentElem, btn); btn.addEventListener('click', ()=>this.loadList(), false); this.loadList(); const onSelect = (e)=>P.loadPage(e.target.value); sel.addEventListener('change', onSelect, false); sel.addEventListener('dblclick', onSelect, false); F.page.addEventListener('wiki-stash-updated', ()=>this._refreshStashMarks()); delete this.init; } }; /** Keep track of how many in-flight AJAX requests there are so we can disable input elements while any are pending. For |
︙ | ︙ | |||
682 683 684 685 686 687 688 | "To really discard this page,", "first clear its content", "then use the Discard button."); return; } P.unstashContent() if(w.version || w.type==='sandbox'){ | | < > | 723 724 725 726 727 728 729 730 731 732 733 734 735 736 737 738 739 740 741 | "To really discard this page,", "first clear its content", "then use the Discard button."); return; } P.unstashContent() if(w.version || w.type==='sandbox'){ P.loadPage(w); }else{ WikiList.removeEntry(w.name); delete P.winfo; P.updatePageTitle(); F.message("Discarded new page ["+w.name+"]."); } }, ticks: 3 }); F.confirmer(P.e.btnSave, { confirmText: "Really save changes?", |
︙ | ︙ | |||
790 791 792 793 794 795 796 | */ const affirmPageLoaded = function(quiet){ if(!P.winfo && !quiet) F.error("No wiki page is loaded."); return !!P.winfo; }; /** Updates the in-tab title/edit status information */ | | | < < < < < | < < < | < < < | | | 831 832 833 834 835 836 837 838 839 840 841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859 860 861 862 863 864 865 866 867 868 869 870 871 872 873 874 875 876 877 878 879 880 881 882 883 884 885 886 887 888 889 890 | */ const affirmPageLoaded = function(quiet){ if(!P.winfo && !quiet) F.error("No wiki page is loaded."); return !!P.winfo; }; /** Updates the in-tab title/edit status information */ P.updateEditStatus = function f(){ if(!f.eLinks){ f.eName = P.e.editStatus.querySelector('span.name'); f.eLinks = P.e.editStatus.querySelector('span.links'); } const wi = this.winfo; D.clearElement(f.eName, f.eLinks); if(!wi){ D.append(f.eName, '(no page loaded)'); return; } var marker = getEditMarker(wi, false); D.append(f.eName,marker,wi.name,); if(wi.version){ D.append( f.eLinks, D.a(F.repoUrl('whistory',{name:wi.name}),'[history]'), D.a(F.repoUrl('attachlist',{page:wi.name}),"[attachments]"), D.a(F.repoUrl('attachadd',{page:wi.name,from: F.repoUrl('wikiedit',{name: wi.name})}), "[attach]") ); } }; /** Update the page title and header based on the state of this.winfo. A no-op if this.winfo is not set. Returns this. */ P.updatePageTitle = function f(){ if(!f.titleElement){ f.titleElement = document.head.querySelector('title'); } const wi = P.winfo, marker = getEditMarker(wi, true), title = wi ? wi.name : 'no page loaded'; f.titleElement.innerText = 'Wiki Editor: ' + marker + title; this.updateEditStatus(); return this; }; /** Change the save button depending on whether we have stuff to save or not. */ P.updateSaveButton = function(){ if(!this.winfo || !this.getStashedWinfo(this.winfo)){ D.disable(this.e.btnSave).innerText = "No changes to save"; }else{ D.enable(this.e.btnSave).innerText = "Save changes"; } return this; }; /** |
︙ | ︙ | |||
949 950 951 952 953 954 955 | /* Assume winfo-like object */ const arg = arguments[0]; name = arg.name; } const onload = (r)=>this.dispatchEvent('wiki-page-loaded', r); const stashWinfo = this.getStashedWinfo({name: name}); if(stashWinfo){ // fake a response from the stash... | | < | 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 | /* Assume winfo-like object */ const arg = arguments[0]; name = arg.name; } const onload = (r)=>this.dispatchEvent('wiki-page-loaded', r); const stashWinfo = this.getStashedWinfo({name: name}); if(stashWinfo){ // fake a response from the stash... F.message("Fetched from the local-edit storage:", stashWinfo.name); onload({ name: stashWinfo.name, mimetype: stashWinfo.mimetype, type: stashWinfo.type, version: stashWinfo.version, parent: stashWinfo.parent, content: $stash.stashedContent(stashWinfo) |
︙ | ︙ |
Changes to src/style.wikiedit.css.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 | body.wikieedit.waiting * { /* Triggered during AJAX requests. */ cursor: wait; } body.wikiedit textarea, body.wikiedit textarea:focus, body.wikiedit input, body.wikiedit input:focus, body.wikiedit select, body.wikiedit select:focus{ /* The sudden appearance of a border (as in the Ardoise skin) shifts the layout in unsightly ways */ border: initial; } body.wikiedit div.wikiedit-preview { margin: 0; padding: 0; } body.wikiedit #wikiedit-tabs { margin: 1em 0 0 0; | > | 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 | body.wikieedit.waiting * { /* Triggered during AJAX requests. */ cursor: wait; } body.wikiedit textarea, body.wikiedit textarea:focus, body.wikiedit input, body.wikiedit input:focus, body.wikiedit select, body.wikiedit select:focus{ /* The sudden appearance of a border (as in the Ardoise skin) shifts the layout in unsightly ways */ border: initial; border-width: 1px; } body.wikiedit div.wikiedit-preview { margin: 0; padding: 0; } body.wikiedit #wikiedit-tabs { margin: 1em 0 0 0; |
︙ | ︙ | |||
51 52 53 54 55 56 57 | display: flex; flex-direction: column; align-items: start; } body.wikiedit .WikiList select { font-size: 110%; margin: initial; | | > | | < < < < < | | > > > | 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 | display: flex; flex-direction: column; align-items: start; } body.wikiedit .WikiList select { font-size: 110%; margin: initial; height: initial /* some skins set these to a fixed height */; font-family: monospace; } body.wikiedit .WikiList select option { margin: 0 0 0.5em 0.55em; } body.wikiedit .WikiList select option.stashed, body.wikiedit .WikiList select option.stashed-new { margin-left: -1em; } body.wikiedit textarea { max-width: initial; } body.wikiedit .tabs .tab-panel { /* Needed for wide diffs */ overflow: auto; } body.wikiedit .WikiList fieldset { padding: 0.25em; border-width: 1px /* Ardoise skin sets this to 0 */; min-width: 6em; border-style: inset; } body.wikiedit .WikiList legend { font-size: 90%; margin: 0 0 0 0.5em; } body.wikiedit .WikiList fieldset > :not(legend) { /* Stretch page selection list when it's empty or only has short page names */ width: 100%; } body.wikiedit .WikiList .fieldset-wrapper { /* Container for the filter and edit status fieldsets */ |
︙ | ︙ | |||
131 132 133 134 135 136 137 138 139 140 141 | justify-content: space-between; font-family: monospace; font-size: 1.2em; } body.wikiedit #wikiedit-edit-status > span { display: block; } body.wikiedit #wikiedit-edit-status > span.links > a { margin: 0 0.25em; } | > > > > | 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 | justify-content: space-between; font-family: monospace; font-size: 1.2em; } body.wikiedit #wikiedit-edit-status > span { display: block; } body.wikiedit .WikiList span.is-new, body.wikiedit .WikiList span.is-modified { font-family: monospace; } body.wikiedit #wikiedit-edit-status > span.links > a { margin: 0 0.25em; } |