మీడియావికీ:Gadget-ImportPagelist.js

వికీసోర్స్ నుండి

గమనిక: భద్రపరచిన తర్వాత, మార్పులను చూడాలంటే మీ విహారిణి కోశాన్ని తీసేయాల్సిరావచ్చు.

  • ఫైర్‌ఫాక్స్‌ / సఫారి: Shift మీటని నొక్కిపట్టి Reloadని నొక్కండి లేదా Ctrl-F5 గానీ Ctrl-R (మాకింటోషులో ⌘-Shift-R) గానీ నొక్కండి
  • గూగుల్ క్రోమ్: Ctrl-Shift-R (మాక్ లో ⌘-Shift-R) నొక్కండి
  • ఇంటర్నెట్ ఎక్ప్లోరర్/ఎడ్జి: Ctrl ను నొక్కిపట్టి Refresh నొక్కండి లేదా Ctrl-F5 నొక్కండి.
  • ఒపేరా:* Ctrl-F5 నొక్కండి.
/**
 * Import pagelist gadget
 *
 * Adds a link to import a pagelist from a given IA identifier
 *
 * Uses the pagelister.toolforge.org tool
 *
 * Changelog:
 *   * 2020-10-24:  Initial version
 *   * 2020-11-27:  Update cover image from title page, if there is one
 */

"use strict";

// IIFE used when including as a user script (to allow debug or config)
// Default gadget use will get an IIFE wrapper as well
(function($, mw) {

var gadget_name = "import_pagelist";

var IPL = {
    enabled: true,
    configured: false,
    host: "https://pagelister.toolforge.org",
    link_label: "Import pagelist",
    link_style: {'font-size': '92%'},
    error_message: "An error occurred:",
    bad_response_msg: "Bad response from pagelist server",
    cancel_btn: "Cancel",
    import_btn: "Import",
    dialog_title: "Import pagelist",
};

/*
 * Read config from user. function fired by hook
 */
function apply_config(cfg) {
    console.log("Configuring " + gadget_name);

    // Bail if the config looks like junk
    if (!cfg || typeof cfg !== "object") {
        console.error("Invalid " + gadget_name + " config", cfg);
        return;
    }

    if (typeof cfg.enabled === "boolean") {
        IPL.enabled = cfg.enabled;
    }

    if (typeof cfg.host === "string") {
        IPL.host = cfg.host;
    }

    IPL.configured = true;
}


function install_dialog() {

  var ParamDialog = function(config) {
    ParamDialog.super.call(this, config);
  };
  OO.inheritClass(ParamDialog, OO.ui.ProcessDialog);

  // Specify a name for .addWindows()
  ParamDialog.static.name = 'importPageListDialog';
  ParamDialog.static.title = IPL.dialog_title;
  // Specify the static configurations: title and action set
  ParamDialog.static.actions = [{
      flags: 'primary',
      label: IPL.import_btn,
      action: 'open'
    },
    {
      flags: 'safe',
      label: IPL.cancel_btn,
    }
  ];

  // Customize the initialize() function to add content and layouts:
  ParamDialog.prototype.initialize = function() {
    ParamDialog.super.prototype.initialize.call(this);
    this.panel = new OO.ui.PanelLayout({
      padded: true,
      expanded: false
    });
    this.content = new OO.ui.FieldsetLayout();

    this.inputs = {};
    this.fields = {};

    this.inputs['source'] = new OO.ui.DropdownInputWidget({
      options: [
        // {data: 'ht', label: 'Hathi Trust'},
        {data: 'ia', label: 'Internet Archive'},
      ]});

    // this.inputs['source'].selectItem( option1 );

    this.fields['source'] = new OO.ui.FieldLayout(this.inputs['source'], {
            label: 'Source',
            align: 'right'
          });
    this.content.addItems([this.fields['source']]);

    this.inputs['id'] = new OO.ui.TextInputWidget();

    this.fields['id'] = new OO.ui.FieldLayout(this.inputs['id'], {
            label: 'ID',
            align: 'right'
          });
    this.content.addItems([this.fields['id']]);

    this.panel.$element.append(this.content.$element);
    this.$body.append(this.panel.$element);
  }

  ParamDialog.prototype.prefill_id = function(link) {
    this.inputs['id'].setValue(link['id']);
    this.inputs['source'].setValue(link['source']);
  }

  // Use getSetupProcess() to set up the window with data passed to it at the time 
  // of opening (e.g., url: 'http://www.mediawiki.org', in this example).
  ParamDialog.prototype.getSetupProcess = function(data) {
    var self = this;
    data = data || {};
    return ParamDialog.super.prototype.getSetupProcess.call(this, data)
      .next(function() {
        // Fire off a request to see if we can find any useful IDs in the commons page
        find_likely_ids(function(data){
          self.prefill_id(data);
        });
      }, this);
  };

  function report_error(msg) {
    alert(IPL.error_message + "\n\n" + msg);
  }

  // Specify processes to handle the actions.
  ParamDialog.prototype.getActionProcess = function(action) {
    var dialog = this;
    if (action === 'open') {
      // Create a new process to handle the action
      return new OO.ui.Process(function() {
        set_pl_enabled(false);

        fetch(IPL.host + '/pagelist/v1/list?' + new URLSearchParams({
          'source': paramDlg.inputs['source'].getValue(),
          'id': paramDlg.inputs['id'].getValue(),
        }))
          .then(function(response){return response.json();})
          .then(function(data){
            if (data){

              if (data['errors'] !== undefined) {
                var errors = data['errors'].map(function(e){
                    return e['msg'];
                  }).join("\n");
                report_error(errors)
              } else if (data['pagelist'] !== undefined) {
                var plv = data['pagelist'];
                set_pl_value(plv);
                set_cover_value(plv);
              } else {
                report_error(IPL.bad_response_msg)
              }
            }
          })
          .finally(function(){set_pl_enabled(true);});

        dialog.close({
          action: action
        });
      }, this);
    }
    // Fallback to parent handler
    return ParamDialog.super.prototype.getActionProcess.call(this, action);
  };

  ParamDialog.prototype.getTeardownProcess = function(data) {
    return ParamDialog.super.prototype.getTeardownProcess.call(this, data)
      .first(function() {
        // Perform any cleanup as needed
      }, this);
  };

  // Create and append a window manager.
  var windowManager = new OO.ui.WindowManager();
  $('body').append(windowManager.$element);

  // Create a new process dialog window.
  var paramDlg = new ParamDialog();

  // Add the window to window manager using the addWindows() method.
  windowManager.addWindows([paramDlg]);

  // Open the window!
  windowManager.openWindow(paramDlg);

  // focus the input in just a moment
  setTimeout(function() {
    paramDlg.$body.find("input")[0].focus();
  }, 300);
}

function get_ia_id_from_url(url) {
  var rx = new RegExp("(details|manage|download)/([^/]*)");
  var match = rx.exec(url);

  if (match)
    return match[2];

  return null;
}

// Find IA links in a page's content
function find_useful_links(data) {

  for (var page in data['query']['pages']) {
    for (var i = 0; i < data['query']['pages'][page]['extlinks'].length; i++) {
      var l = data['query']['pages'][page]['extlinks'][i];
      if (l['*'].match("https?://archive.org")) {
        var id = get_ia_id_from_url(l['*']);
        if (id !== null) {
          return {'source': 'ia', 'id': id};
        }
      }
    }

    for (var i = 0; i < data['query']['pages'][page]['iwlinks'].length; i++) {
      var l = data['query']['pages'][page]['iwlinks'][i];
      if (l['prefix'] === "iarchive") {
        return {'source': 'ia', 'id': l['*']};
      }
    }
  }

  return null;
};

function find_likely_ids(callback) {
  // Get all external links from the Commons file page
  mw.loader.using('mediawiki.ForeignApi').done( function () {
    var api = new mw.ForeignApi( 'https://commons.wikimedia.org/w/api.php' );
    var com_pg = "File:" + mw.config.get('wgTitle');
    api.get( {
      'action': 'query',
      'format': 'json',
      'prop': 'extlinks|iwlinks',
      'titles': com_pg,
      'ellimit': 100,
      'iwlimit': 100,
    } ).done( function(data) {
      var link = find_useful_links(data);

      if (link !== null) {
        callback(link);
      }

    }).fail( function(data) {
      console.log("Commons GET Failed:", data);
    });
  });
};

function set_pl_value(plv) {
  OO.ui.infuse($('#wpprpindex-Pages').parent()).setValue(plv);
}

function set_cover_value(plv) {
  // Set the cover image if there is one
  var match = /(\d+)=["']?[Tt]itle["']\s/.exec(plv);

  if (match) {
    $('#wpprpindex-Image').val(match[1]);
  }
}

function set_pl_enabled(enabled) {
  OO.ui.infuse($('#wpprpindex-Pages').parent()).setDisabled(!enabled);
}

// User clicked - install the dialog
function activate() {
  mw.loader.using(['mediawiki.util', 'oojs-ui-core', 'oojs-ui-widgets'],
    install_dialog);
}

// Insert the button next to the right field
function insert_button() {
  var btn = $("<a href='javascript:void(0);'></a>")
          .append(IPL.link_label)
          .addClass("import_pagelist_link")
          .click(activate);
  $("#ooui-php-1").append([" (", btn, ")"]);
}

function add_css_rule(rule, css) {
  css = JSON.stringify(css).replace(/"/g, "").replace(/,/g, ";");
  $("<style>").prop("type", "text/css").html(rule + css).appendTo("head");
}

function ipl_setup() {

  // Get user config, if any
  mw.hook(gadget_name + ".config").add(apply_config);

  // only care for editing in the Index: namespace
  if (!(mw.config.get('wgAction') === 'edit' || mw.config.get('wgAction') ===
      'submit') ||
    mw.config.get('wgCanonicalNamespace') !== "Index") {
    return;
  }

  add_css_rule(".import_pagelist_link", IPL.link_style);

  insert_button();
}
$(ipl_setup);

}(jQuery, mediaWiki));