MediaWiki:Gadget-GrAnnotations.js: Difference between revisions

No edit summary
No edit summary
 
(6 intermediate revisions by the same user not shown)
Line 123: Line 123:
     $ntComposer = $( [
     $ntComposer = $( [
       '<div class="gra-composer" id="gra-nt-composer" role="dialog" aria-label="Add note">',
       '<div class="gra-composer" id="gra-nt-composer" role="dialog" aria-label="Add note">',
       '  <div class="gra-bm-composer-label">',
       '  <div class="gra-composer-user">',
       '    <span class="gra-icon gra-icon-note" aria-hidden="true"></span>',
       '    <div class="gra-avatar">' + esc(currentUser ? userInitial : '✎') + '</div>',
       '    <span> Add Note </span>',
       '    <div class="gra-composer-uname">' + esc(currentUser || 'Notes') + '</div>',
       '  </div>',
       '  </div>',
       '  <textarea class="gra-composer-input" id="gra-nt-input" placeholder="Write a note…" rows="3"></textarea>',
       '  <textarea class="gra-composer-input" id="gra-nt-input" placeholder="Write a note…" rows="3"></textarea>',
       '  <div class="gra-composer-actions">',
       '  <div class="gra-composer-actions">',
       '    <button class="gra-btn-cancel" id="gra-nt-cancel">Cancel</button>',
       '    <button class="gra-btn-cancel" id="gra-nt-cancel">Cancel</button>',
       '    <button class="gra-btn-submit" id="gra-nt-submit" disabled>Save</button>',
       '    <button class="gra-btn-submit" id="gra-nt-submit" disabled>Save Note</button>',
       '  </div>',
       '  </div>',
       '</div>',
       '</div>',
Line 140: Line 140:
       '  <div class="gra-bm-composer-label">',
       '  <div class="gra-bm-composer-label">',
       '    <span class="gra-icon gra-icon-bookmark" aria-hidden="true"></span>',
       '    <span class="gra-icon gra-icon-bookmark" aria-hidden="true"></span>',
       '    <span> Save bookmark </span>',
       '    Save bookmark',
       '  </div>',
       '  </div>',
       '  <input class="gra-composer-input" id="gra-bm-input" type="text" placeholder="Name this bookmark…" autocomplete="off">',
       '  <input class="gra-composer-input" id="gra-bm-input" type="text" placeholder="Name this bookmark…" autocomplete="off">',
Line 472: Line 472:
       html += '<div class="gra-note-card" data-gra-id="'+esc(n.id)+'">'
       html += '<div class="gra-note-card" data-gra-id="'+esc(n.id)+'">'
             + '<div class="gra-card-header">'
             + '<div class="gra-card-header">'
             + '<div class="gra-avatar"></div>'
             + '<span class="gra-icon gra-icon-note" aria-hidden="true"></span>'
             + '<div class="gra-card-meta">'
             + '<div class="gra-card-meta">'
             + (n.ts ? '<div class="gra-card-ts">'+esc(fmtTs(n.ts))+'</div>' : '')
             + (n.ts ? '<div class="gra-card-ts">'+esc(fmtTs(n.ts))+'</div>' : '')
Line 545: Line 545:
     });
     });


     /* Mobile: show fab once selection settles (~350ms, alongside native menu).
    /* Separate timers so mobile + desktop never clobber each other */
       Strategy B: don't race the native menu — appear with it, in our own space. */
    var _selTimer    = null;  /* desktop debounce */
    var _lastTouchEnd = 0;
    var _mobShowTimer = null; /* mobile show-on-touchend */
 
     /* Mobile: show fab quickly after finger lifts (selection settled).
       180ms feels instant while still letting the range stabilise. */
     document.addEventListener('touchend', function(e) {
     document.addEventListener('touchend', function(e) {
       if (!_mobile) return;
       if (!_mobile) return;
       if ($fab[0] && $fab[0].contains(e.target)) return;
       if ($fab[0] && $fab[0].contains(e.target)) return;
      _lastTouchEnd = Date.now();
       clearTimeout(_mobShowTimer);
       clearTimeout(_selTimer);
       _mobShowTimer = setTimeout(function() {
       _selTimer = setTimeout(function() {
         var sel = window.getSelection();
         var sel = window.getSelection();
         if (!sel || sel.isCollapsed || !sel.toString().trim()) return;
         if (!sel || sel.isCollapsed || !sel.toString().trim()) return;
         tryShowActions();
         tryShowActions();
       }, 350);
       }, 180);
     }, { passive: true });
     }, { passive: true });


     /* Mobile: reposition fab live while user drags the selection handles,
     /* Mobile: only HIDE the fab when selection is cleared while it's visible.
       hide it if selection is cleared */
      (Reposition isn't needed now that the bar is docked, and re-running
       showFab here was causing the lag/flicker.) */
     document.addEventListener('selectionchange', function() {
     document.addEventListener('selectionchange', function() {
       if (!_mobile) return;
       if (!_mobile) return;
       if (!$fab.hasClass('gra-fab-visible')) return;
       if (!$fab.hasClass('gra-fab-visible')) return;
       clearTimeout(_selTimer);
       var sel = window.getSelection();
      _selTimer = setTimeout(function() {
      if (!sel || sel.isCollapsed || !sel.toString().trim()) {
        var sel = window.getSelection();
        clearTimeout(_mobShowTimer);
        if (!sel || sel.isCollapsed || !sel.toString().trim()) { hideActions(); return; }
         hideActions();
         if (captureSelection()) showFab(_selRect);
       }
       }, 250);
     });
     });


     /* selectionchange debounced (desktop) */
     /* selectionchange debounced (desktop only) */
    var _selTimer = null;
     document.addEventListener('selectionchange', function() {
     document.addEventListener('selectionchange', function() {
      if (_mobile) return;
       _selVersion++;
       _selVersion++;
       clearTimeout(_selTimer);
       clearTimeout(_selTimer);
Line 582: Line 584:
         if (v !== _selVersion) return;
         if (v !== _selVersion) return;
         if (_fabSelVer === v) return;
         if (_fabSelVer === v) return;
        if (_mobile) return; /* mobile uses touchend instead */
         tryShowActions();
         tryShowActions();
       }, 600);
       }, 600);