diff --git a/RefToolbar/RefToolbar.js b/RefToolbar/RefToolbar.js index 3003894..dbe3614 100644 --- a/RefToolbar/RefToolbar.js +++ b/RefToolbar/RefToolbar.js @@ -1,275 +1,271 @@ -/*jshint smarttabs:true, loopfunc:true,forin:false*/ -/*global mw, $ */ +/* jshint smarttabs:true, loopfunc:true, forin:false */ +/* global mw, $ */ // TODO: make autodate an option in the CiteTemplate object, not a preference // Global object // TODO: // * Remove this once the page is moved to a module 'ext.gadget.refToolbarDialogs' depending on 'ext.gadget.refToolbarBase' if (typeof CiteTB === 'undefined') { - var CiteTB = { - "Templates" : {}, // All templates - "Options" : {}, // Global options - "UserOptions" : {}, // User options - "DefaultOptions" : {}, // Script defaults - "ErrorChecks" : {} // Error check functions - }; + var CiteTB = { + "Templates": {}, // All templates + "Options": {}, // Global options + "UserOptions": {}, // User options + "DefaultOptions": {}, // Script defaults + "ErrorChecks": {} // Error check functions + }; } -// Only execute when editing/previewing wikitext pages -// TODO: Remove tests already done by [[MediaWiki:Gadget-refToolbar.js]] -if ( - ['edit', 'submit'].indexOf( mw.config.get('wgAction') ) !== -1 && - mw.config.get('wgPageContentModel') === 'wikitext' -) { - // TODO: Move this to [[MediaWiki:Gadget-refToolbarDialogs.css]] and add it to the definition of module 'ext.gadget.refToolbarDialogs' -mw.util.addCSS(".cite-form-td {"+ -"height: 0 !important;"+ -"padding: 0.1em !important;"+ -"}"); +mw.util.addCSS(".cite-form-td {" + + "height: 0 !important;" + + "padding: 0.1em !important;" + + "}"); // Default options, these mainly exist so the script won't break if a new option is added CiteTB.DefaultOptions = { - "date format" : "--", - "autodate fields" : [], - "months" : ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], - "modal" : true, - "autoparse" : false, - "expandtemplates": false + "date format": "--", + "autodate fields": [], + "months": ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec'], + "modal": true, + "autoparse": false, + "expandtemplates": false }; // Get an option - user settings override global which override defaults -CiteTB.getOption = function(opt) { - if (CiteTB.UserOptions[opt] !== undefined) { - return CiteTB.UserOptions[opt]; - } else if (CiteTB.Options[opt] !== undefined) { - return CiteTB.Options[opt]; - } - return CiteTB.DefaultOptions[opt]; +CiteTB.getOption = function (opt) { + if (CiteTB.UserOptions[opt] !== undefined) { + return CiteTB.UserOptions[opt]; + } else if (CiteTB.Options[opt] !== undefined) { + return CiteTB.Options[opt]; + } + return CiteTB.DefaultOptions[opt]; }; -CiteTB.init = function() { - /* Main stuff, build the actual toolbar structure - * 1. get the template list, make the dropdown list and set up the template dialog boxes - * 2. actually build the toolbar: - * * A section for cites - * ** dropdown for the templates (previously defined) - * ** button for named refs with a dialog box - * ** button for errorcheck - * 3. add the whole thing to the main toolbar - */ - - if (typeof $('div[rel=cites]')[0] !== 'undefined') { // Mystery IE bug workaround - return; - } - $('head').trigger('reftoolbarbase'); - var $target = $('#wpTextbox1'); - var temlist = {}; - for (var t in CiteTB.Templates) { - var tem = CiteTB.Templates[t]; - var sform = CiteTB.escStr(tem.shortform); - var actionobj = { - type: 'dialog', - module: 'cite-dialog-'+sform - }; - var dialogobj = {}; - dialogobj['cite-dialog-'+sform] = { - resizeme: false, - title: mw.message( 'cite-dialog-'+sform ).parse(), - id: 'citetoolbar-'+sform, - init: function() {}, - html: tem.getInitial(), - dialog: { - width:680, - open: function() { - $(this).html(CiteTB.getOpenTemplate().getForm()); - /** @param {jQuery.Event} e */ - $('.cite-prev-parse').on( 'click', function ( e ) { - e.preventDefault(); - CiteTB.prevParseClick(); - }); - }, - buttons: { - 'cite-form-submit': function() { - var ref = CiteTB.getRef(false, true); - $(this).dialog( 'close' ); - $.wikiEditor.modules.toolbar.fn.doAction( $(this).data( 'context' ), { - type: 'encapsulate', - options: { - post: ref - } - }, $(this) ); - }, - 'cite-form-showhide': CiteTB.showHideExtra, - 'cite-refpreview': function() { - var ref = CiteTB.getRef(false, false); - var template = CiteTB.getOpenTemplate(); - var div = $("#citetoolbar-"+CiteTB.escStr(template.shortform)); - div.find('.cite-preview-label').show(); - div.find('.cite-ref-preview').text(ref).show(); - if (CiteTB.getOption('autoparse')) { - CiteTB.prevParseClick(); - } else { - div.find('.cite-prev-parse').show(); - div.find('.cite-prev-parsed-label').hide(); - div.find('.cite-preview-parsed').html(''); - } - }, - 'wikieditor-toolbar-tool-link-cancel': function() { - $(this).dialog( 'close' ); - }, - 'cite-form-reset': function() { - CiteTB.resetForm(); - } - } - } - }; - try { - $target.wikiEditor('addDialog', dialogobj); - } catch (e) { - // TypeError: range is null - } - //if (!CiteTB.getOption('modal')) { - //$('#citetoolbar-'+sform).dialog('option', 'modal', false); - //} - temlist[sform] = {label: tem.templatename, action: actionobj }; - } +CiteTB.init = function () { + /* Main stuff, build the actual toolbar structure + * 1. get the template list, make the dropdown list and set up the template dialog boxes + * 2. actually build the toolbar: + * * A section for cites + * ** dropdown for the templates (previously defined) + * ** button for named refs with a dialog box + * ** button for errorcheck + * 3. add the whole thing to the main toolbar + */ - var refsection = { - 'sections': { - 'cites': { - type: 'toolbar', - label: mw.msg( 'cite-section-label' ), - groups: { - 'template': { - tools: { - 'template': { - type: 'select', - label: mw.msg( 'cite-template-list' ), - list: temlist - } - } - }, - 'namedrefs': { - label: mw.msg( 'cite-named-refs-label' ), - tools: { - 'nrefs': { - type: 'button', - action: { - type: 'dialog', - module: 'cite-toolbar-namedrefs' - }, - icon: '//upload.wikimedia.org/wikipedia/commons/thumb/b/be/Nuvola_clipboard_lined.svg/22px-Nuvola_clipboard_lined.svg.png', - section: 'cites', - group: 'namedrefs', - label: mw.msg( 'cite-named-refs-button' ) - } - } - }, - 'errorcheck': { - label: mw.msg( 'cite-errorcheck-label' ), - tools: { - 'echeck': { - type: 'button', - action: { - type: 'dialog', - module: 'cite-toolbar-errorcheck' - }, - icon: '//upload.wikimedia.org/wikipedia/commons/thumb/a/a3/Nuvola_apps_korganizer-NO.png/22px-Nuvola_apps_korganizer-NO.png', - section: 'cites', - group: 'errorcheck', - label: mw.msg( 'cite-errorcheck-button' ) - } - } - } - } - } - } - }; - - var defaultdialogs = { - 'cite-toolbar-errorcheck': { - title: mw.message( 'cite-errorcheck-label' ).parse(), - id: 'citetoolbar-errorcheck', - resizeme: false, - init: function() {}, - html: '
'+ - ''+ - ' '+mw.usability.getMsg('cite-loading')+'
', - dialog: { - width:550, - open: function() { - CiteTB.loadRefs(); - }, - buttons: { - 'cite-errorcheck-submit': function() { - var errorchecks = $("input[name='cite-err-test']:checked"); - var errors = []; - for (var i=0; i'+ - ''+ - ' '+mw.usability.getMsg('cite-loading')+'', - init: function() {}, - dialog: { - width: 550, - open: function() { - CiteTB.loadRefs(); - }, - buttons: { - 'cite-form-submit': function() { - var refname = $("#cite-namedref-select").val(); - if (refname === '') { - return; - } - $(this).dialog( 'close' ); - $.wikiEditor.modules.toolbar.fn.doAction( $(this).data( 'context' ), { - type: 'encapsulate', - options: { - post: CiteTB.getNamedRef(refname, true) - } - }, $(this) ); - }, - 'wikieditor-toolbar-tool-link-cancel': function() { - $(this).dialog( 'close' ); - } - } - } - } - }; - - try { - $target.wikiEditor('addDialog', defaultdialogs); - } catch (e) { - // error occurred setting up wikieditor. - } - $('#citetoolbar-namedrefs').off('dialogopen'); - if (!CiteTB.getOption('modal')) { - //$('#citetoolbar-namedrefs').dialog('option', 'modal', false); - //$('#citetoolbar-errorcheck').dialog('option', 'modal', false); - mw.util.addCSS(".ui-widget-overlay {"+ - "display:none !important;"+ - "}"); - } - try { - $target.wikiEditor('addToToolbar', refsection); - } catch (e) { - // error occurred setting up wikieditor. - } + if (typeof $('div[rel=cites]')[0] !== 'undefined') { // Mystery IE bug workaround + return; + } + $('head').trigger('reftoolbarbase'); + var $target = $('#wpTextbox1'); + var temlist = {}; + for (var t in CiteTB.Templates) { + var tem = CiteTB.Templates[t]; + var sform = CiteTB.escStr(tem.shortform); + var actionobj = { + type: 'dialog', + module: 'cite-dialog-' + sform + }; + var dialogobj = {}; + dialogobj['cite-dialog-' + sform] = { + resizeme: false, + title: mw.message('cite-dialog-' + sform), + id: 'citetoolbar-' + sform, + init: function () { + }, + html: tem.getInitial(), + dialog: { + width: 680, + open: function () { + $(this).html(CiteTB.getOpenTemplate().getForm()); + /** @param {jQuery.Event} e */ + $('.cite-prev-parse').on('click', function (e) { + e.preventDefault(); + CiteTB.prevParseClick(); + }); + }, + buttons: { + 'cite-form-submit': function () { + var ref = CiteTB.getRef(false, true); + $(this).dialog('close'); + $.wikiEditor.modules.toolbar.fn.doAction($(this).data('context'), { + type: 'encapsulate', + options: { + post: ref + } + }, $(this)); + }, + 'cite-form-showhide': CiteTB.showHideExtra, + 'cite-refpreview': function () { + var ref = CiteTB.getRef(false, false); + var template = CiteTB.getOpenTemplate(); + var div = $("#citetoolbar-" + CiteTB.escStr(template.shortform)); + div.find('.cite-preview-label').show(); + div.find('.cite-ref-preview').text(ref).show(); + if (CiteTB.getOption('autoparse')) { + CiteTB.prevParseClick(); + } else { + div.find('.cite-prev-parse').show(); + div.find('.cite-prev-parsed-label').hide(); + div.find('.cite-preview-parsed').html(''); + } + }, + 'wikieditor-toolbar-tool-link-cancel': function () { + $(this).dialog('close'); + }, + 'cite-form-reset': function () { + CiteTB.resetForm(); + } + } + } + }; + try { + $target.wikiEditor('addDialog', dialogobj); + } catch (e) { + // TypeError: range is null + } + //if (!CiteTB.getOption('modal')) { + //$('#citetoolbar-'+sform).dialog('option', 'modal', false); + //} + temlist[sform] = {label: tem.templatename, action: actionobj}; + } + + var refsection = { + 'sections': { + 'cites': { + type: 'toolbar', + label: mw.msg('cite-section-label'), + groups: { + 'template': { + tools: { + 'template': { + type: 'select', + label: mw.msg('cite-template-list'), + list: temlist + } + } + }, + 'namedrefs': { + label: mw.msg('cite-named-refs-label'), + tools: { + 'nrefs': { + type: 'button', + action: { + type: 'dialog', + module: 'cite-toolbar-namedrefs' + }, + icon: '//upload.wikimedia.org/wikipedia/commons/thumb/b/be/Nuvola_clipboard_lined.svg/60px-Nuvola_clipboard_lined.svg.png', + section: 'cites', + group: 'namedrefs', + label: mw.msg('cite-named-refs-button') + } + } + }, + 'errorcheck': { + label: mw.msg('cite-errorcheck-label'), + tools: { + 'echeck': { + type: 'button', + action: { + type: 'dialog', + module: 'cite-toolbar-errorcheck' + }, + icon: '//upload.wikimedia.org/wikipedia/commons/thumb/a/a3/Nuvola_apps_korganizer-NO.png/60px-Nuvola_apps_korganizer-NO.png', + section: 'cites', + group: 'errorcheck', + label: mw.msg('cite-errorcheck-button') + } + } + } + } + } + } + }; + + var defaultdialogs = { + 'cite-toolbar-errorcheck': { + title: mw.message('cite-errorcheck-label'), + id: 'citetoolbar-errorcheck', + resizeme: false, + init: function () { + }, + html: '
' + + '' + + ' ' + mw.messages.get('cite-loading') + '
', + dialog: { + width: 550, + open: function () { + CiteTB.loadRefs(); + }, + buttons: { + 'cite-errorcheck-submit': function () { + var errorchecks = $("input[name='cite-err-test']:checked"); + var errors = []; + for (var i = 0; i < errorchecks.length; i++) { + errors = errors.concat(CiteTB.ErrorChecks[$(errorchecks[i]).val()].run()); + } + CiteTB.displayErrors(errors); + $(this).dialog('close'); + }, + 'wikieditor-toolbar-tool-link-cancel': function () { + $(this).dialog('close'); + } + } + } + }, + 'cite-toolbar-namedrefs': { + title: mw.message('cite-named-refs-title'), + resizeme: false, + id: 'citetoolbar-namedrefs', + html: '
' + + '' + + ' ' + mw.messages.get('cite-loading') + '
', + init: function () { + }, + dialog: { + width: 550, + open: function () { + CiteTB.loadRefs(); + }, + buttons: { + 'cite-form-submit': function () { + var refname = $("#cite-namedref-select").val(); + if (refname === '') { + return; + } + $(this).dialog('close'); + $.wikiEditor.modules.toolbar.fn.doAction($(this).data('context'), { + type: 'encapsulate', + options: { + post: CiteTB.getNamedRef(refname, true) + } + }, $(this)); + }, + 'wikieditor-toolbar-tool-link-cancel': function () { + $(this).dialog('close'); + } + } + } + } + }; + + try { + $target.wikiEditor('addDialog', defaultdialogs); + } catch (e) { + // error occurred setting up wikieditor. + } + $('#citetoolbar-namedrefs').off('dialogopen'); + if (!CiteTB.getOption('modal')) { + //$('#citetoolbar-namedrefs').dialog('option', 'modal', false); + //$('#citetoolbar-errorcheck').dialog('option', 'modal', false); + mw.util.addCSS(".ui-widget-overlay {" + + "display:none !important;" + + "}"); + } + try { + $target.wikiEditor('addToToolbar', refsection); + } catch (e) { + // error occurred setting up wikieditor. + } }; // Load local data - messages, cite templates, etc. @@ -290,8 +286,8 @@ $(document).ready( function() { case 'fr': // Français mw.loader.load('/w/index.php?title=MediaWiki:RefToolbarMessages-fr.js&action=raw&ctype=text/javascript'); break; - case 'pl': // Polski - mw.loader.load('/w/index.php?title=MediaWiki:RefToolbarMessages-pl.js&action=raw&ctype=text/javascript'); + case 'pl': // Polski + mw.loader.load('/w/index.php?title=MediaWiki:RefToolbarMessages-pl.js&action=raw&ctype=text/javascript'); break; default: // English mw.loader.load('/w/index.php?title=MediaWiki:RefToolbarMessages-en.js&action=raw&ctype=text/javascript'); @@ -304,638 +300,788 @@ CiteTB.refsLoaded = false; // REF FUNCTIONS // Actually assemble a ref from user input -CiteTB.getRef = function(inneronly, forinsert) { - var i, j, g, group; - var template = CiteTB.getOpenTemplate(); - var templatename = template.templatename; - var res = ''; - var refobj = {'shorttag':false}; - if (!inneronly) { - group = $('#cite-'+CiteTB.escStr(template.shortform)+'-group').val(); - var refname = $('#cite-'+CiteTB.escStr(template.shortform)+'-name').val(); - res += '', i.toString()); - var field = $('#cite-'+CiteTB.escStr(template.shortform)+'-'+fieldid).val(); - if (field) { - content+=' |'+fieldid+'='; - content+= $.trim(field); - } - } - } - } - for( i=0; i', i.toString()); + var field = $('#cite-' + CiteTB.escStr(template.shortform) + '-' + fieldid).val(); + if (field) { + content += ' |' + fieldid + '='; + content += $.trim(field); + } + } + } + } + for (i = 0; i < template.basic.length; i++) { + if (template.basic[i].increment_group) { + continue; + } + var fieldname = template.basic[i].field; + var field = $('#cite-' + CiteTB.escStr(template.shortform) + '-' + fieldname).val(); + if (field) { + content += ' |' + fieldname + '='; + content += $.trim(field); + } + } + if ($('#cite-form-status').val() !== 'closed') { + for (i = 0; i < template.extra.length; i++) { + if (template.extra[i].increment_group) { + continue; + } + var fieldname = template.extra[i].field; + var field = $('#cite-' + CiteTB.escStr(template.shortform) + '-' + fieldname).val(); + if (field) { + content += ' |' + fieldname + '='; + content += $.trim(field); + } + } + } + content += '}}'; + res += content; + refobj.content = content; + if (!inneronly) { + res += ''; + } + if (forinsert) { + CiteTB.mainRefList.push(refobj); + } + return res; }; // Make a reference to a named ref -CiteTB.getNamedRef = function(refname, forinsert) { - if (forinsert) { - CiteTB.mainRefList.push( {'shorttag':true, 'refname':refname} ); - } - return ''; +CiteTB.getNamedRef = function (refname, forinsert) { + if (forinsert) { + CiteTB.mainRefList.push({'shorttag': true, 'refname': refname}); + } + return ''; }; // Function to load the ref list -CiteTB.loadRefs = function() { - if (CiteTB.refsLoaded) { - return; - } - CiteTB.getPageText(CiteTB.loadRefsInternal); +CiteTB.loadRefs = function () { + if (CiteTB.refsLoaded) { + return; + } + CiteTB.getPageText(CiteTB.loadRefsInternal); }; // Function that actually loads the list from the page text -CiteTB.loadRefsInternal = function(text) { - // What this does: extract first name/group extract second name/group shorttag inner content - var refsregex = /< *ref(?: +(name|group) *= *(?:"([^"]*?)"|'([^']*?)'|([^ '"\/\>]*?)) *)? *(?: +(name|group) *= *(?:"([^"]*?)"|'([^']*?)'|([^ '"\/\>]*?)) *)? *(?:\/ *>|>((?:.|\n)*?)< *\/ *ref *>)/gim; - // This should work regardless of the quoting used for names/groups and for linebreaks in the inner content - while (true) { - var ref = refsregex.exec(text); - if (ref === null) { - break; - } - var refobj = {}; - if (ref[9]) { // Content + short tag check - //alert('"'+ref[9]+'"'); - refobj.content = ref[9]; - refobj.shorttag = false; - } else { - refobj.shorttag = true; - } - if (ref[1] !== '') { // First name/group - if (ref[2]) { - refobj['ref'+ref[1]] = ref[2]; - } else if (ref[3]) { - refobj['ref'+ref[1]] = ref[3]; - } else { - refobj['ref'+ref[1]] = ref[4]; - } - } - if (ref[5] !== '') { // Second name/group - if (ref[6]) { - refobj['ref'+ref[5]] = ref[6]; - } else if (ref[7]) { - refobj['ref'+ref[5]] = ref[7]; - } else { - refobj['ref'+ref[5]] = ref[8]; - } - } - CiteTB.mainRefList.push(refobj); - } - CiteTB.refsLoaded = true; - CiteTB.setupErrorCheck(); - CiteTB.setupNamedRefs(); +CiteTB.loadRefsInternal = function (text) { + // What this does: extract first name/group extract second name/group shorttag inner content + var refsregex = /< *ref(?: +(name|group) *= *(?:"([^"]*?)"|'([^']*?)'|([^ '"\/\>]*?)) *)? *(?: +(name|group) *= *(?:"([^"]*?)"|'([^']*?)'|([^ '"\/\>]*?)) *)? *(?:\/ *>|>((?:.|\n)*?)< *\/ *ref *>)/gim; + // This should work regardless of the quoting used for names/groups and for linebreaks in the inner content + while (true) { + var ref = refsregex.exec(text); + if (ref === null) { + break; + } + var refobj = {}; + if (ref[9]) { // Content + short tag check + //alert('"'+ref[9]+'"'); + refobj.content = ref[9]; + refobj.shorttag = false; + } else { + refobj.shorttag = true; + } + if (ref[1] !== '') { // First name/group + if (ref[2]) { + refobj['ref' + ref[1]] = ref[2]; + } else if (ref[3]) { + refobj['ref' + ref[1]] = ref[3]; + } else { + refobj['ref' + ref[1]] = ref[4]; + } + } + if (ref[5] !== '') { // Second name/group + if (ref[6]) { + refobj['ref' + ref[5]] = ref[6]; + } else if (ref[7]) { + refobj['ref' + ref[5]] = ref[7]; + } else { + refobj['ref' + ref[5]] = ref[8]; + } + } + CiteTB.mainRefList.push(refobj); + } + CiteTB.refsLoaded = true; + CiteTB.setupErrorCheck(); + CiteTB.setupNamedRefs(); }; // AJAX FUNCTIONS // Parse some wikitext and hand it off to a callback function -CiteTB.parse = function(text, callback) { - $.post( mw.util.wikiScript( 'api' ), - {action:'parse', title:mw.config.get('wgPageName'), text:text, prop:'text', format:'json'}, - function(data) { - var html = data.parse.text['*']; - callback(html); - }, - 'json' - ); +CiteTB.parse = function (text, callback) { + $.post(mw.util.wikiScript('api'), + {action: 'parse', title: mw.config.get('wgPageName'), text: text, prop: 'text', format: 'json'}, + function (data) { + var html = data.parse.text['*']; + callback(html); + }, + 'json' + ); }; // Use the API to expand templates on some text -CiteTB.expandtemplates = function(text, callback) { - $.post( mw.util.wikiScript( 'api' ), - {action:'expandtemplates', title:mw.config.get('wgPageName'), text:text, format:'json'}, - function(data) { - var restext = data.expandtemplates['*']; - callback(restext); - }, - 'json' - ); +CiteTB.expandtemplates = function (text, callback) { + $.post(mw.util.wikiScript('api'), + {action: 'expandtemplates', title: mw.config.get('wgPageName'), text: text, format: 'json'}, + function (data) { + var restext = data.expandtemplates['*']; + callback(restext); + }, + 'json' + ); }; // Function to get the page text -CiteTB.getPageText = function(callback) { - var section = $("input[name='wpSection']").val(); - if ( section !== '' ) { - var postdata = {action:'query', prop:'revisions', rvprop:'content', pageids:mw.config.get('wgArticleId'), format:'json'}; - if (CiteTB.getOption('expandtemplates')) { - postdata.rvexpandtemplates = '1'; - } - $.get( mw.util.wikiScript( 'api' ), - postdata, - function(data) { - var pagetext = data.query.pages[mw.config.get('wgArticleId').toString()].revisions[0]['*']; - callback(pagetext); - }, - 'json' - ); - } else { - if (CiteTB.getOption('expandtemplates')) { - CiteTB.expandtemplates($('#wpTextbox1').wikiEditor('getContents').text(), callback); - } else { - callback($('#wpTextbox1').wikiEditor('getContents').text()); - } - } +CiteTB.getPageText = function (callback) { + var section = $("input[name='wpSection']").val(); + if (section !== '') { + var postdata = { + action: 'query', + prop: 'revisions', + rvprop: 'content', + pageids: mw.config.get('wgArticleId'), + format: 'json' + }; + if (CiteTB.getOption('expandtemplates')) { + postdata.rvexpandtemplates = '1'; + } + $.get(mw.util.wikiScript('api'), + postdata, + function (data) { + var pagetext = data.query.pages[mw.config.get('wgArticleId').toString()].revisions[0]['*']; + callback(pagetext); + }, + 'json' + ); + } else { + if (CiteTB.getOption('expandtemplates')) { + CiteTB.expandtemplates($('#wpTextbox1').wikiEditor('getContents').text(), callback); + } else { + callback($('#wpTextbox1').wikiEditor('getContents').text()); + } + } }; // Safe version of decodeURIComponent() that doesn't throw exceptions. // If the native decodeURIComponent() threw an exception, the original string will be returned. -CiteTB.safeDecodeURIComponent = function(s) { +CiteTB.safeDecodeURIComponent = function (s) { try { s = decodeURIComponent(s); - } catch (e) {} + } catch (e) { + } return s; }; +/** + * Convert one Citoid result into RefToolbar autofill properties. + * + * The property names must match the "autofillprop" values in + * MediaWiki:RefToolbarConfig.js, not the citation template parameters. + * + * @param {Object} entry One item from the Citoid response body. + * @param {string} tem Target citation template short name, e.g. 'book'. + * @return {Object} Autofill properties; empty if nothing matched. + */ +CiteTB.transformCitoidResponse = function (entry, tem) { + var result = {}; + // A pipe ends the template parameter. CiteTB.getRef joins the field + // values into wikitext and does not escape them. + var escapePipes = function (text) { + return typeof text === 'string' ? text.replace(/\|/g, '{{!}}') : text; + }; + // Citoid puts the chapter in "title" and the book in "bookTitle". Only + // cite book has a chapter field. + var isBookSection = entry.itemType === 'bookSection' && tem === 'book'; + + Object.keys(entry).forEach(function (key) { + var value = escapePipes(entry[key]); + + // Zotero has one field name for each item type. The /mediawiki/ + // format keeps them separate, so each case lists all the names that + // Zotero maps to the same base field. + switch (key) { + case 'publicationTitle': + case 'blogTitle': + case 'bookTitle': + case 'dictionaryTitle': + case 'encyclopediaTitle': + case 'forumTitle': + case 'proceedingsTitle': + case 'programTitle': + case 'websiteTitle': + // RefToolbar maps every containing-work title to journal + if (isBookSection) { + result.title = value; + } else { + result.journal = value; + } + break; + case 'title': + case 'caseName': + case 'nameOfAct': + case 'subject': + if (isBookSection) { + result.chapter = value; + } else { + result.title = value; + } + break; + case 'volume': + case 'codeVolume': + case 'reporterVolume': + result.volume = value; + break; + case 'issue': + result.issue = value; + break; + case 'edition': + // Citoid returns "1st ed"; the templates want "1st". + value = value.split(' edition').join(''); + value = value.split(' ed.').join(''); + value = value.split(' ed').join(''); + result.edition = value; + break; + case 'publisher': + case 'company': + case 'distributor': + case 'institution': + case 'label': + case 'network': + case 'studio': + case 'university': + result.publisher = value; + break; + case 'pages': + case 'codePages': + case 'firstPage': + result.pages = value; + break; + // Citoid can return several identifiers; the templates take one. + case 'ISBN': + result.isbn = escapePipes(Array.isArray(value) ? value[0] : value); + break; + case 'ISSN': + result.issn = escapePipes(Array.isArray(value) ? value[0] : value); + break; + case 'date': + case 'dateDecided': + case 'dateEnacted': + case 'issueDate': + result.date = value; + break; + case 'DOI': + result.doi = value; + break; + case 'language': + result.language = value; + break; + case 'place': + result.location = value; + break; + case 'author': + value.forEach(function (author) { + // Reject name parts that start with a digit. These are + // dates from bad metadata. + var firstName = /^\d/.test(author[0]) ? '' : escapePipes(author[0]); + var lastName = /^\d/.test(author[1]) ? '' : escapePipes(author[1]); + // Accept an institutional author, which has no first name. + if (lastName) { + if (!result.authors) { + result.authors = []; + } + // CiteTB.autoFill expects [last, first]. + result.authors.push([lastName, firstName || '']); + } + }); + break; + } + }); + + return result; +}; + // Autofill a template from an ID (ISBN, DOI, PMID, URL) -CiteTB.initAutofill = function() { - var elemid = $(this).attr('id'); - var res = /^cite\-auto\-(.*?)\-(.*)\-(.*)$/.exec(elemid); - var tem = res[1]; - var field = res[2]; - var autotype = res[3]; - var id = $('#cite-'+tem+'-'+field).val(); - if (!id) { - return false; - } - var url = '//reftoolbar.toolforge.org/lookup.php?'; - // Citoid expects minimally encoded input, so do some speculative decoding here to avoid - // 404 fetches. https://phabricator.wikimedia.org/T146539 - id = CiteTB.safeDecodeURIComponent(id); - url+=autotype+'='+encodeURIComponent(id); - url+='&template='+encodeURIComponent(tem); - var s = document.createElement('script'); - s.setAttribute('src', url); - s.setAttribute('type', 'text/javascript'); - document.getElementsByTagName('head')[0].appendChild(s); - return false; +CiteTB.initAutofill = function () { + var elemid = $(this).attr('id'); + var res = /^cite\-auto\-(.*?)\-(.*)\-(.*)$/.exec(elemid); + var tem = res[1]; + var field = res[2]; + var autotype = res[3]; + var id = $('#cite-' + tem + '-' + field).val(); + if (!id) { + return false; + } + var serviceUrl = mw.config.get('wgCitoidConfig').citoidServiceUrl; + if (!serviceUrl) { + return false; + } + // Citoid expects minimally encoded input, so do some speculative decoding here to avoid + // 404 fetches. https://phabricator.wikimedia.org/T146539 + id = CiteTB.safeDecodeURIComponent(id); + // This is a close copy of how ve.ui.CitoidInspector does this request: + (new mw.Api({ + ajax: { + // Older configuration has a trailing /api + url: serviceUrl.replace(/\/api$/, '') + '/mediawiki/' + encodeURIComponent(id), + // Request content language of wiki from citoid service + headers: { 'accept-language': mw.config.get('wgContentLanguage') }, + timeout: 30 * 1000, // 30 seconds + type: 'GET' + } + })).get().then(function (results) { + // A failed lookup is a 404, which rejects. Do not clear the fields + // the user already filled in. + if (!results || !results[0]) { + return; + } + CiteTB.autoFill(CiteTB.transformCitoidResponse(results[0], tem), tem, autotype); + }); + return false; }; // Callback for autofill -//TODO: Autofill the URL, at least for DOI -CiteTB.autoFill = function(data, template, type) { - var cl = 'cite-'+template+'-'; - var i,j, coauthors; - $('.'+cl+'title').val(data.title); - // Fill in authors - if (data.authors && data.authors.length > 0) { - if ($('.'+cl+'last-incr-1').length != 0) { - var classes = $('.'+cl+'last-incr-1').eq(0).attr('class').split(/\s+/); - var group = false; - var patt = /cite-[^-]*?-incr-(.*)/ - for (var c=0; c 0) { + if ($('.' + cl + 'last-incr-1').length != 0) { + var classes = $('.' + cl + 'last-incr-1').eq(0).attr('class').split(/\s+/); + var group = false; + var patt = /cite-[^-]*?-incr-(.*)/; + for (var c = 0; c < classes.length; c++) { + if (patt.exec(classes[c])) { + group = patt.exec(classes[c])[1]; + break; + } } - } - $('.'+cl+'last-incr-1').val(data.authors[0][0]) - $('.'+cl+'first-incr-1').val(data.authors[0][1]) - elemid = '#cite-incr-'+template+'-'+group; - for (var i=2; i', date); - datestr = datestr.replace('', zdate); - } else { - datestr = datestr.replace('', ''); - datestr = datestr.replace('', ''); - } - if (usemonth) { - datestr = datestr.replace('', month); - datestr = datestr.replace('', zmonth); - datestr = datestr.replace('', CiteTB.getOption('months')[DT.getUTCMonth()]); - } else { - datestr = datestr.replace('', ''); - datestr = datestr.replace('', ''); - datestr = datestr.replace('', ''); - } - datestr = datestr.replace('', DT.getUTCFullYear().toString()); - return datestr.replace(/^[ \/\-\,\.]*(.*?)[ \/\-\,\.]*$/g, "$1"); // Cleanup any dangling spaces or connectors that might result from omitting date/month +CiteTB.formatDate = function (DT, useday, usemonth) { + if (typeof useday == "undefined") { + useday = true; + } + if (typeof usemonth == "undefined") { + usemonth = true; + } + var datestr = CiteTB.getOption('date format'); + var zmonth = ''; + var month = DT.getUTCMonth() + 1; + if (month < 10) { + zmonth = "0" + month.toString(); + } else { + zmonth = month.toString(); + } + month = month.toString(); + var zdate = ''; + var date = DT.getUTCDate(); + if (date < 10) { + zdate = "0" + date.toString(); + } else { + zdate = date.toString(); + } + date = date.toString(); + if (useday) { + datestr = datestr.replace('', date); + datestr = datestr.replace('', zdate); + } else { + datestr = datestr.replace('', ''); + datestr = datestr.replace('', ''); + } + if (usemonth) { + datestr = datestr.replace('', month); + datestr = datestr.replace('', zmonth); + datestr = datestr.replace('', CiteTB.getOption('months')[DT.getUTCMonth()]); + } else { + datestr = datestr.replace('', ''); + datestr = datestr.replace('', ''); + datestr = datestr.replace('', ''); + } + datestr = datestr.replace('', DT.getUTCFullYear().toString()); + return datestr.replace(/^[ \/\-\,\.]*(.*?)[ \/\-\,\.]*$/g, "$1"); // Cleanup any dangling spaces or connectors that might result from omitting date/month }; // Function called after the ref list is loaded, to actually set the contents of the named ref dialog // Until the list is loaded, its just a "Loading" placeholder -CiteTB.setupNamedRefs = function() { - var names = [], i; - for( i=0; i'); - $('#citetoolbar-namedrefs').html( stuff ); - if (names.length === 0) { - stuff.html(mw.usability.getMsg('cite-no-namedrefs')); - } else { - stuff.html(mw.usability.getMsg('cite-namedrefs-intro')); - var select = $(''); + select.append($('