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.
(function () {
// https://gitlab.wikimedia.org/diegodlh/w2c-gadget/-/blob/ca75959e4612a6ce758d6142e91f4fe8107baefd/script.js
// Copyright (C) 2022 Diego de la Hera and contributors.
// This work is released under the terms of GPL-3.0 or any later version.
const EDIT_LABEL = "Web2Cit 🖉";
const TRACK_TOPIC = "stats.mediawiki_gadget_Web2Cit_total"
const API_USER_AGENT = "Web2Cit-Gadget (https://phabricator.wikimedia.org/tag/web2cit-gadget/)";
class Web2Cit {
  static disabledItem = 'web2cit.disabled';

  constructor() {
    this.unpatched = {};
    this.initialized = false;
    // this.mode = undefined;
    this.server = "https://web2cit.toolforge.org/";
    if (window.web2citServer) {
      try {
        this.server = new URL(window.web2citServer).href;
      } catch {
        console.log("Ignoring invalid web2citServer setting");
      }
    }
    this.search
  }

  get disabled() {
    return localStorage.getItem(this.disabledItem) === "true";
    // if (this.mode === "visual") {
    //   return localStorage.getItem(this.disabledItem) === "true";
    // } else {
    //   return false;
    // }    
  }

  set disabled(disabled) {
    localStorage.setItem(this.disabledItem, disabled === "true");
    // if (this.mode === "visual") {
    //   localStorage.setItem(this.disabledItem, disabled === "true");
    // } else {
    //   throw Error(`Cannot disable in ${this.mode} mode`);
    // }
  }

  init() {
    if (this.initialized) return;
    console.log('Web2Cit: Initializing...');
    this.patchInitialize();
    if(!this.disabled) this.enable();
    this.initialized = true;
    // const surface = ve.init.target.getSurface();
    // this.mode = surface.getMode();
    // if (this.mode === "visual") {
    //   this.patchInitialize();
    // }
    // if (!this.disabled || this.mode === "source") {
    //   this.enable();
    // }
  }

  enable() {
    console.log("Web2Cit: Enabling...");
    this.patchAjax();
    this.patchPerformLookup();
    // if (this.mode === "visual") {
    //   this.patchBuildTemplateResults();
    // };
  }

  disable() {
    console.log("Web2Cit: Disabling...");
    this.unpatchAjax();
    this.unpatchPerformLookup();
    this.editButton.toggle(false);
    // if (this.mode === "visual") {
    //   this.unpatchBuildTemplateResults();
    // }
  }

  getSearch() {
    return this.search;
  }

  setSearch(search) {
    this.search = search;
  }

  patchInitialize () {
    // console.log("Web2Cit: Patching CitoidInspector's \"initalize\"...")
    const initialize = ve.ui.CitoidInspector.prototype.initialize;
    // const toggle = new OO.ui.ToggleSwitchWidget({
    //   value: !this.disabled
    // });
    const toggle = new OO.ui.CheckboxInputWidget({
      selected: !this.disabled,
    });
    const field = new OO.ui.FieldLayout( toggle, {
      align: 'inline',
      label: 'Web2Cit'
    } );
    const onToggleChange = (event) => {
      if (event.target.checked) {
        this.disabled = false;
        this.enable();
        // console.log('{ action: "enable" }');
        mw.track(TRACK_TOPIC, 1, { action: "enable" });
      } else {
        this.disabled = true;
        this.disable();
        // console.log('{ action: "disable" }');
        mw.track(TRACK_TOPIC, 1, { action: "disable" });
      }
    };

    // a dedicated Web2Cit credit label
    this.web2citCredit = new OO.ui.LabelWidget( {
		  classes: [ 've-ui-citoidInspector-credit' ]
	  } );
    this.web2citCredit.setLabel($(`<div>${
      ve.msg(
        'citoid-citoiddialog-credit',
        `<a href="" target="_blank">${EDIT_LABEL}</a>`
      )
    }</div>`))
    this.web2citCredit.$element.on("click", (event) => {
      if (event.target.tagName == "A") {
        // console.log('{ action: "edit" }');
        mw.track(TRACK_TOPIC, 1, { action: "edit" });
      }
    });

    // a button widget to edit Web2Cit configuration from Citoid error message
    const editButton = new OO.ui.ButtonWidget( {
      label: EDIT_LABEL,
      flags: [ 'progressive' ],
    } );
    const onEditButtonClick = () => {
      window.open(this.server + this.search, "_blank");
      // console.log('{ action: "edit_error" }');
      mw.track(TRACK_TOPIC, 1, { action: "edit_error" });
    };
    editButton.toggle(false);
    this.editButton = editButton;

    ve.ui.CitoidInspector.prototype.initialize = function () {
      initialize.bind(this)();

      toggle.$element.on("change", onToggleChange);
      const parentElement = this.autoProcessPanels.lookup.$element;
      field.$element.insertAfter(parentElement.children().first());

      editButton.$element.on("click", onEditButtonClick)
      this.errorMessage.label.children().last().append( editButton.$element );
    }
  }

  patchPerformLookup() {
    if (this.unpatched.performLookup) return;
    // console.log("Web2Cit: Patching CitoidInspector's \"performLookup\"...");
    const performLookup = ve.ui.CitoidInspector.prototype.performLookup;
    this.unpatched.performLookup = performLookup;
    const server = this.server;
    const getSearch = this.getSearch.bind(this);
    const setSearch = this.setSearch.bind(this);
    const web2citCredit = this.web2citCredit;
    const editButton = this.editButton;
    const onCitationInsert = (web2cit) => {
      if (web2cit) {
        // console.log("Web2Cit: Web2Cit citation inserted");
        updateEditSummary();
        // console.log('{ action: "insert" }');
        mw.track(TRACK_TOPIC, 1, { action: "insert" });
      } else {
        // console.log('{ action: "insert_other" }');
        mw.track(TRACK_TOPIC, 1, { action: "insert_other" });
      }
    };
    ve.ui.CitoidInspector.prototype.performLookup = function () {
      setSearch();
      editButton.toggle(false)

      return performLookup.bind(this)().then(() => {
        const search = getSearch();
        const results = this.results;
        if (search) {

          // update web2citCredit href
          web2citCredit.label.children()[0].href = server + search;

          if (results.length) {
            // move Citoid credit into first reference widget
            this.previewSelectWidget.items[0].$element.append(this.credit.$element)

            if (!results.at(-1).source.includes("Web2Cit")) {
              // if no Web2Cit citation, create and append an empty reference widget
              const widget = new OO.ui.Widget()
              widget.$element.addClass( 've-ui-citoidReferenceWidget' )
              widget.destroy = () => {};
              this.previewSelectWidget.insertItem(widget)
            }

            // get last reference widget
            const refWidget = this.previewSelectWidget.items.at(-1);

            // append Web2Cit credit
            refWidget.$element.append(web2citCredit.$element);

            // add Web2Cit reference widget class
            const w2cRefWidgetClass = "web2citReferenceWidget";
            refWidget.$element.addClass(w2cRefWidgetClass);

            // register citation insert handler for all widgets
            for (const refWidget of this.previewSelectWidget.items) {
              if (refWidget.insertButton) {  // may be undefined if we created it above
                const web2cit = refWidget.$element.hasClass(w2cRefWidgetClass);
                refWidget.insertButton.$button.on(
                  "click", () => { onCitationInsert(web2cit) }
                );
              }
            }
          } else {
            // assume error
            editButton.toggle(true)
          }
        }
      })
    }
  }

  patchAjax() {
    if (this.unpatched.ajax) return;
    // console.log("Web2Cit: Patching ajax...")
    const ajax = $.ajax;
    this.unpatched.ajax = ajax;
    const server = this.server;
    const setSearch = this.setSearch.bind(this);
    $.ajax = function(url, options) {
      // If url is an object, simulate pre-1.5 signature
      if ( typeof url === "object" ) {
        options = url;
        url = undefined;
      }
      // Force options to be an object
      options = options || {};
      
      url = url || options.url;
      const match = url.match(
        /^\/api\/rest_v1\/data\/citation\/mediawiki\/(?<search>.+)/
      );

      const headers = { ...options.headers };

      if (match !== null) {
        let { search } = match.groups;

        // consider using ve.safeDecodeURIComponent()?
        search = decodeURIComponent(search);
        
        // mimick citoid's CitoidService.js
        search = search.trim()//.toLowerCase();
  
        // if the query does not begin with either http:// or https://
        // only assume that the user meant a url if it follows the pattern
        // www.something.somethingelse
        // otherwise, we may miss DOIs, QIDs, PMCIDs, ISBNs or PMIDs
        // which are handled by Citoid differently
        // instruct the user to always add http:// or https:// at the beginning
        // to explicitly mean a url
        if (search.match(/^www\..+\..+/i)) {
          search = "http://" + search;
        };
        if (
          search.match(/^https?:\/\/.+/i) &&
          // to prevent an endless loop, continue using web2cit through citoid
          // if user explicitly asks to translate a web2cit url
          !search.match(
            new RegExp(`^https?://${server.replace(/^https?:\/\//i, "")}.+`, "i")
          )
        ) {
          setSearch(search);
          console.log('Web2Cit: Search will be resolved using Web2Cit + Citoid...')
          url = server + "translate";
          options.data = {
            "citoid": "true",
            "format": "mediawiki",
            "url": search
          };

          // Add custom Api-User-Agent (T390791)
          const key = Object.keys(headers).find(
            k => k.toLowerCase() === 'api-user-agent'
          ) || "Api-User-Agent";
          headers[key] = (
            headers[key] ? headers[key] + " " : ""
          ) + API_USER_AGENT;

          // only track web2cit generate actions
          // console.log("{ action: 'generate' }");
          mw.track(TRACK_TOPIC, 1, { action: "generate" });
        }
      }
      return ajax.bind(this)(url, {...options, headers});
    }  
  }

  unpatchAjax() {
    if (!this.unpatched.ajax) return;
    // console.log("Web2Cit: Unpatching ajax...");
    $.ajax = this.unpatched.ajax;
    delete this.unpatched.ajax;
  }

  unpatchPerformLookup() {
    if (!this.unpatched.performLookup) return;
    // console.log("Web2Cit: Unpatching CitoidInspector's \"performLookup\"...");
    ve.ui.CitoidInspector.prototype.performLookup = this.unpatched.performLookup;
    delete this.unpatched.performLookup;
  }
}

function updateEditSummary() {
  const hashtag = "#Web2Cit";
  const saveDialog = ve.init.target.saveDialog;
  const initialEditSummary = (
    ve.init.target.editSummaryValue || ve.init.target.initialEditSummary
  );
  let editSummaryValue = (
    saveDialog ?
    saveDialog.editSummaryInput.getValue() :
    initialEditSummary
  ) || "";
  if (!editSummaryValue.includes(hashtag)) {
    const prefix = ve.msg("citoid-citoiddialog-title");  // "Add a citation"
    if (!editSummaryValue.trim()) {  // empty edit summary
      editSummaryValue = prefix;
    } else if (editSummaryValue == initialEditSummary) {
      editSummaryValue += prefix;
    }
    // we need a space before hashtag, otherwise Hashtags tool won't pick it (T262234)
    editSummaryValue = (
      editSummaryValue.trimEnd() + ` [[m:Web2Cit| ${hashtag}]] `
    );

    if (saveDialog) {
      saveDialog.setEditSummary(editSummaryValue);
    } else {
      ve.init.target.editSummaryValue = editSummaryValue;
    }
  }
}

// a "gadget loader" - a small gadget that tells VE to load the real gadget
// once VE is activated by the user
// https://www.mediawiki.org/wiki/VisualEditor/Gadgets#Deployment
mw.loader.using( 'ext.visualEditor.desktopArticleTarget.init', function () {
  // console.log("Web2Cit script will load...");
  // return mw.loader.getScript('/w/index.php?title=User:Diegodlh/Web2Cit/script.js&action=raw&ctype=text/javascript'); 
  window.web2cit = new Web2Cit();
  mw.hook( 've.activationComplete' ).add( function () {
    // console.log('Web2Cit: Running "ve.activationComplete" hook...')
    window.web2cit.init();
  });
  // mw.hook( 've.wikitextInteractive' ).add( function () {
  //   console.log('Web2Cit: Running "ve.wikitextInteractive" hook...')
  //   window.web2cit.init();
  // } );
});
}())