Jump to content

User:WeWake/Add to TODO.js

From Wikipedia, the free encyclopedia
Note: After saving, you have to bypass your browser's cache to see the changes. Google Chrome, Firefox, Microsoft Edge and Safari: Hold down the ⇧ Shift key and click the Reload toolbar button. For details and instructions about other browsers, see Wikipedia:Bypass your cache.
/*
 * Adds a "Add to TODO" link to the Tools menu to add the current page to a personal todo list.
 * This version checks if the page exists to determine the wikilink format.
 */
(function () {

  // --- Configuration ---
  // The name of the subpage on your user page where the list is stored.
  var todoSubpage = 'Todo';
  // --- End Configuration ---

  function addToTodo() {
    var pageTitle = mw.config.get('wgTitle');
    var fullPageName = mw.config.get('wgPageName');
    var api = new mw.Api();

    // Check if the current page exists
    api.get({
      action: 'query',
      titles: fullPageName,
      prop: 'info'
    }).done(function (data) {
      var pageId = Object.keys(data.query.pages)[0];
      var pageExists = pageId > 0;

      var wikilink;
      if (pageExists) {
        wikilink = '[[' + fullPageName + ']]';
      } else {
        var userName = mw.config.get('wgUserName');
        wikilink = '[[User:' + userName + '/' + pageTitle + '|' + pageTitle + ']]';
      }

      // Format the current date.
      var now = new Date();
      var dateString = now.toLocaleDateString('en-US', {
        month: 'short',
        day: 'numeric',
        year: 'numeric'
      });

      // Prompt for an optional comment.
      var userComment = window.prompt('Add an optional comment for this entry:', '');

      // Start building the text to be added to the todo list.
      var newTodoText = '\n* ' + wikilink + ' - bookmarked on ' + dateString;

      // If a comment was provided, append it.
      if (userComment) {
        newTodoText += ' (Comment: ' + userComment + ')';
      }

      // --- MediaWiki API Call to add to the TODO list ---
      var userTodoPageTitle = 'User:' + mw.config.get('wgUserName') + '/' + todoSubpage;

      api.get({
        action: 'query',
        titles: userTodoPageTitle
      }).done(function (data) {
        var todoPageId = Object.keys(data.query.pages)[0];
        var editParams = {
          action: 'edit',
          title: userTodoPageTitle,
          summary: 'Added ' + wikilink + ' to the todo list.',
          format: 'json'
        };

        if (todoPageId > 0) {
          // Page exists, so we append the text.
          editParams.appendtext = newTodoText;
        } else {
          // Page does not exist, so we create it with the text.
          editParams.text = newTodoText.trim();
          editParams.summary = 'Creating TODO list and adding ' + wikilink + '.';
        }

        // Perform the edit (append or create).
        api.postWithEditToken(editParams).done(function () {
          mw.notify('Page successfully added to your TODO list.');
        }).fail(function () {
          mw.notify('An error occurred while trying to save the entry.', {
            type: 'error'
          });
        });
      });
    });
  }

  // Function to manage TODO items when viewing the TODO page
  function manageTodoItems() {
    var currentPageTitle = mw.config.get('wgPageName');
    var userName = mw.config.get('wgUserName');
    var userTodoPageTitle = 'User:' + userName + '/' + todoSubpage;

    // Check if we're on the user's TODO page
    if (currentPageTitle === userTodoPageTitle.replace(/ /g, '_')) {
      // Find all list items in the content
      $('#mw-content-text ul li').each(function (index) {
        var $listItem = $(this);
        var itemText = $listItem.text();

        // Skip items that already have management buttons or templates
        if ($listItem.find('.todo-controls').length > 0 ||
          itemText.includes('{{done}}') ||
          itemText.includes('{{not done}}')) {
          return;
        }

        // Create control buttons
        var $controls = $('<span class="todo-controls" style="margin-left: 10px; font-size: smaller;"></span>');

        var $removeBtn = $('<a href="#" style="color: red; margin-right: 5px;">(remove)</a>');
        var $doneBtn = $('<a href="#" style="color: green; margin-right: 5px;">(done)</a>');
        var $notDoneBtn = $('<a href="#" style="color: orange;">(not done)</a>');

        $controls.append($removeBtn).append($doneBtn).append($notDoneBtn);
        $listItem.append($controls);

        // Bind click events
        $removeBtn.on('click', function (e) {
          e.preventDefault();
          removeTodoItem(index, $listItem);
        });

        $doneBtn.on('click', function (e) {
          e.preventDefault();
          markTodoItem(index, $listItem, 'done');
        });

        $notDoneBtn.on('click', function (e) {
          e.preventDefault();
          markTodoItem(index, $listItem, 'not done');
        });
      });
    }
  }

  // Function to remove a TODO item
  function removeTodoItem(itemIndex, $listItem) {
    if (!confirm('Are you sure you want to remove this item from your TODO list?')) {
      return;
    }

    var api = new mw.Api();
    var userTodoPageTitle = 'User:' + mw.config.get('wgUserName') + '/' + todoSubpage;

    api.get({
      action: 'query',
      titles: userTodoPageTitle,
      prop: 'revisions',
      rvprop: 'content'
    }).done(function (data) {
      var pageId = Object.keys(data.query.pages)[0];
      var content = data.query.pages[pageId].revisions[0]['*'];

      // Split content into lines and remove the specific item
      var lines = content.split('\n');
      var listItemLines = lines.filter(line => line.trim().startsWith('*'));

      if (itemIndex < listItemLines.length) {
        // Find the actual line index in the full content
        var targetLine = listItemLines[itemIndex];
        var lineIndex = lines.indexOf(targetLine);
        if (lineIndex !== -1) {
          lines.splice(lineIndex, 1);
        }

        var newContent = lines.join('\n');

        api.postWithEditToken({
          action: 'edit',
          title: userTodoPageTitle,
          text: newContent,
          summary: 'Removed item from TODO list',
          format: 'json'
        }).done(function () {
          $listItem.fadeOut(300, function () {
            $(this).remove();
          });
          mw.notify('Item removed from TODO list.');
        }).fail(function () {
          mw.notify('Failed to remove item.', { type: 'error' });
        });
      }
    });
  }

  // Function to mark a TODO item as done or not done
  function markTodoItem(itemIndex, $listItem, status) {
    var template = status === 'done' ? '{{done}}' : '{{not done}}';
    var api = new mw.Api();
    var userTodoPageTitle = 'User:' + mw.config.get('wgUserName') + '/' + todoSubpage;

    api.get({
      action: 'query',
      titles: userTodoPageTitle,
      prop: 'revisions',
      rvprop: 'content'
    }).done(function (data) {
      var pageId = Object.keys(data.query.pages)[0];
      var content = data.query.pages[pageId].revisions[0]['*'];

      // Split content into lines and modify the specific item
      var lines = content.split('\n');
      var listItemLines = lines.filter(line => line.trim().startsWith('*'));

      if (itemIndex < listItemLines.length) {
        var targetLine = listItemLines[itemIndex];
        var lineIndex = lines.indexOf(targetLine);
        if (lineIndex !== -1) {
          lines[lineIndex] = targetLine + ' ' + template;
        }

        var newContent = lines.join('\n');

        api.postWithEditToken({
          action: 'edit',
          title: userTodoPageTitle,
          text: newContent,
          summary: 'Marked item as ' + status,
          format: 'json'
        }).done(function () {
          $listItem.find('.todo-controls').remove();
          $listItem.append(' <span style="font-weight: bold; color: ' +
            (status === 'done' ? 'green' : 'orange') + ';">' + template + '</span>');
          mw.notify('Item marked as ' + status + '.');
        }).fail(function () {
          mw.notify('Failed to mark item as ' + status + '.', { type: 'error' });
        });
      }
    });
  }

  // Add the "Add to TODO" link to the "Tools" menu after the page loads.
  $(function () {
    var link = mw.util.addPortletLink(
      'p-tb', // The ID of the "Tools" portlet
      '#',    // The URL (handled by the click event)
      'Add to TODO', // The display text of the link
      't-add-to-todo', // The ID for this link
      'Add this page to your personal TODO list' // The tooltip
    );

    // Bind the click event to our function.
    $(link).on('click', function (e) {
      e.preventDefault();
      addToTodo();
    });

    // Initialize TODO item management if on the TODO page
    manageTodoItems();
  });

}());