MediaWiki:Gadget-GrAnnotations.js: Difference between revisions

No edit summary
No edit summary
Line 30: Line 30:
  * STORAGE
  * STORAGE
  * ───────
  * ───────
  * Comments  → MediaWiki page: <PageTitle>/Comments
  * Comments  → MediaWiki page: Talk:<PageTitle>/GrComments
  *            Format: {{GrComment|id=…|anchor=…|author=…|timestamp=…
*            Talk namespace is excluded from XML/PDF exports and never
*                              |quote=…|text=…}}
*            shown in the content editor — comments cannot affect exports.
  * Bookmarks → localStorage key: grantha_bm_<pageKey>
  *            Format: {{GrComment|id=…|author=…|timestamp=…|quote=…|text=…}}
  *            Format: JSON array of {id, name, quote, anchorHtml, ts}
  * Bookmarks → localStorage (per-user, per-page — not shared across users)
  *            Key: grantha_bm_<pageName>
  *
  *
  * ADMIN NOTIFICATION
  * ADMIN NOTIFICATION
  * ──────────────────
  * ──────────────────
  * On new comment: appends a section to User_talk:ADMIN_USER via MW API.
  * On new comment: sends email via MW EmailUser API (action=emailuser).
  * This triggers a standard Echo notification to the admin.
  * Email contains the comment text and a direct anchor link to the passage.
* Fallback: if admin has no email set, posts to User_talk:ADMIN_USER instead.
* Requires $wgEnableEmail = true and $wgEnableUserEmail = true (MW defaults).
  *
  *
  * DEPENDENCIES
  * DEPENDENCIES
Line 66: Line 69:
   var CMT_LS_KEY  = 'grantha_cmt_' + ( ( window.mw && mw.config.get( 'wgPageName' ) ) || '' );
   var CMT_LS_KEY  = 'grantha_cmt_' + ( ( window.mw && mw.config.get( 'wgPageName' ) ) || '' );
   var pageTitle  = ( window.mw && mw.config.get( 'wgPageName' ) ) || '';
   var pageTitle  = ( window.mw && mw.config.get( 'wgPageName' ) ) || '';
   var commentsPage = pageTitle + '/Comments';
  /* Comments stored on Talk:<PageTitle>/GrComments — talk namespace is
  * excluded from XML/PDF exports and never shown in the content editor,
  * so comments cannot tamper with document content or affect exports. */
   var commentsPage = 'Talk:' + pageTitle + '/GrComments';
   var currentUser  = ( window.mw && mw.config.get( 'wgUserName' ) ) || '';
   var currentUser  = ( window.mw && mw.config.get( 'wgUserName' ) ) || '';
   var userInitial  = currentUser ? currentUser.charAt( 0 ).toUpperCase() : '?';
   var userInitial  = currentUser ? currentUser.charAt( 0 ).toUpperCase() : '?';
Line 380: Line 386:
     // Persist to wiki
     // Persist to wiki
     saveCommentToWiki( id, quote, text, ts );
     saveCommentToWiki( id, quote, text, ts );
     notifyAdmin( quote, text, ts );
     notifyAdmin( _activeId || '', quote, text, ts );


     // Update panel
     // Update panel
Line 411: Line 417:
       api.postWithEditToken({
       api.postWithEditToken({
         action:'edit', title:commentsPage, text:updated,
         action:'edit', title:commentsPage, text:updated,
         summary:'New comment by ' + currentUser + ' on [[' + pageTitle + ']]',
         summary:'New comment by ' + currentUser + ' on [[' + pageTitle + ']] (stored off-page)',
         bot:0,
         bot:0,
       }).catch(function(){});
       }).catch(function(){});
Line 417: Line 423:
   }
   }


   function notifyAdmin( quote, commentText, ts ) {
   function notifyAdmin( anchorId, quote, commentText, ts ) {
     if ( !window.mw || !ADMIN_USER || !currentUser ) return;
    /* Send a real email to the admin via MW's built-in EmailUser API.
    var adminTalk = 'User_talk:' + ADMIN_USER;
    * This requires:
    var msg = '== New comment on [[' + pageTitle.replace(/_/g,' ') + ']] ==\n'
    *  1. The admin account (ADMIN_USER) has a confirmed email address set
            + '; By: ' + currentUser + '\n'
    *      in Special:Preferences.
            + '; Time: ' + ts + '\n'
    *  2. $wgEnableEmail and $wgEnableUserEmail are true in LocalSettings.php
            + '; Quoted text: //' + quote + '//\n\n'
    *      (both are true by default in MW).
            + commentText.slice(0,500)
    * The email contains a direct scrollable anchor link to the passage. */
            + (commentText.length>500?'\n…':'')
     if ( !window.mw || !ADMIN_USER ) return;
            + '\n\n[[User:Chandrashekars|Chandrashekars]] ([[User talk:Chandrashekars|talk]]) 08:59, 24 April 2026 (UTC)';
 
    new mw.Api().postWithEditToken({
    /* Build a deep-link URL with the anchor ID so the admin can jump
      action:'edit', title:adminTalk, section:'new',
    * directly to the highlighted passage with one click. */
      sectiontitle:'Comment on ' + pageTitle.replace(/_/g,' '),
    var articlePath = ( mw.config.get('wgArticlePath') || '/wiki/$1' )
      text:msg,
                        .replace( '$1', pageTitle );
      summary:'Comment notification from [[' + pageTitle.replace(/_/g,' ') + ']]',
    var anchorLink  = window.location.origin + articlePath
      bot:0,
                    + ( anchorId ? '#' + anchorId : '' );
    }).catch(function(){});
 
    var pageDisplay = pageTitle.replace( /_/g, ' ' );
    var subject    = '[Grantha] New comment on "' + pageDisplay + '"';
    var body        = 'A new comment has been posted on ' + pageDisplay + '.
 
'
                    + 'Posted by : ' + ( currentUser || 'Anonymous' ) + '
'
                    + 'Time      : ' + ts + '
'
                    + 'Passage  : "' + quote + '"
 
'
                    + 'Comment  :
' + commentText + '
 
'
                    + '──────────────────────────────────
'
                    + 'Jump to passage:
' + anchorLink + '
 
'
                    + 'View all comments:
'
                    + window.location.origin
                    + ( mw.config.get('wgArticlePath') || '/wiki/$1' )
                        .replace( '$1', 'Talk:' + pageTitle + '/GrComments' )
                    + '
';
 
    new mw.Api().post({
      action:  'emailuser',
      target:  ADMIN_USER,
      subject:  subject,
      text:    body,
      token:    mw.user.tokens.get( 'csrfToken' ),
    }).catch(function(){
      /* EmailUser failed (e.g. admin has no email set) — fall back to
      * a talk-page notification so the admin still gets an Echo alert. */
      if ( !currentUser ) return;
      var adminTalk = 'User_talk:' + ADMIN_USER;
      var wikimsg = '== New comment on [[' + pageDisplay + ']] ==
'
                  + '; By: ' + ( currentUser || 'Anonymous' ) + '
'
                  + '; Passage: //' + quote + '//
'
                  + '; Link: ' + anchorLink + '
 
'
                  + commentText.slice(0,500)
                  + ( commentText.length > 500 ? '
' : '' )
                  + '
 
[[User:Chandrashekars|Chandrashekars]] ([[User talk:Chandrashekars|talk]]) 10:47, 24 April 2026 (UTC)';
      new mw.Api().postWithEditToken({
        action:'edit', title:adminTalk, section:'new',
        sectiontitle:'Comment on ' + pageDisplay,
        text:wikimsg,
        summary:'Comment notification from [[' + pageDisplay + ']]',
        bot:0,
      }).catch(function(){});
    });
   }
   }