User:DaxServer/BooksToSfn.js

//

/** * ––––– *      YOU ARE FULLY RESPONSIBLE FOR PUBLISHING EDITS USING THIS SCRIPT * ––––– * * This script is not ready for use, unless of course, if you know what you are doing. * You must verify if the conversion is successful and modify if not. * Recommended to also use the User:Trappist the monk/HarvErrors script in conjunction. */

$.when(   $.ready ).then(function  {    // Only on main namespace or sandbox    if ( ! [0, 2].includes(mw.config.get('wgNamespaceNumber'))) {       return    }

let articleName = mw.config.get('wgPageName') articleName = encodeURIComponent(articleName); // fix bug involving & not getting converted to &amp; let pageIsSandbox = articleName.match(/sandbox$/)

// Only in sandbox in user namespace if (2 === mw.config.get('wgNamespaceNumber') && ! pageIsSandbox) { return }

let notifyTitle = 'Books-to-Sfn'

// Activate portlet when VE source editor is enabled mw.hook( 've.activationComplete' ).add(function {        // Remove portlet when VE visual editor is enabled        if (0 === $('.ve-ui-surface-source').length) {            $('#ds-books-to-sfn').remove

return }

$.when(           mw.loader.using( [ 'mediawiki.util' ] )        ).then( function  {            main        }) })

// Remove portlet when VE is deactivated mw.hook( 've.deactivationComplete' ).add(function {        $('#ds-books-to-sfn').remove    })

function main { const node = mw.util.addPortletLink('p-tb', '#', 'Books to Sfn', 'ds-books-to-sfn', 'Convert to ')

$( node ).click(function (e) {           let books = []            let textBox = $('#wpTextbox1')            let match, page, cite            let errors = 0            let index = 0            let errorMatches = []

if ( ! checkIfRefSectionExists(textBox)) { return }

// ToDo Add support for quotes?

while (true) { match = getNextMatch(index)

if (null === match) { break }

// Determine author names let authorNames = determineAuthorNames(match[2], 'last') console.log('Last name(s)', authorNames)

if (0 === authorNames.length) { authorNames = determineAuthorNames(match[2], 'author') console.log('Author(s)', authorNames) }

if (0 === authorNames.length) { authorNames = determineAuthorNames(match[2], 'editor') console.log('Editor(s)', authorNames) }

if (authorNames.length > 4) { console.error('More than four authors found. Please fix it manually.', authorNames, match) // mw.notify('More than four authors found. Please fix it manually.', {                   //     type: 'error',                    //     title: notifyTitle,                    // }) errors++ errorMatches.push({                       error: 'More than four authors found',                        match,                    })

// Increment index as we need the next match index = match.index + 1

break }

if (0 === authorNames.length) { console.error('Last name(s) / author(s) / editor(s) could not be determined. Please fix it manually.', authorNames, match) // mw.notify('Last name(s) and author(s) could not be determined. Please fix it manually.', {                   //     type: 'error',                    //     title: notifyTitle,                    // }) errors++ errorMatches.push({                       error: 'Last name(s) / author(s) / editor(s) could not be determined',                        match,                    })

// Increment index as we need the next match index = match.index + 1

continue }               // End author names

// Determine year let year = determineYear(match[2]) console.log('Year', year)

if (null === year) { console.error('Year could not be determined. Please fix it manually.', match) // mw.notify('Year could not be determined. Please fix it manually.', {                   //     type: 'error',                    //     title: notifyTitle,                    // }) errors++ errorMatches.push({                       error: 'Year could not be determined',                        match,                    })

// Increment index as we need the next match index = match.index + 1

break }

// Determine page ({page, cite} = determinePage(match[2])) console.log('Page(s)', page) console.log(cite)

// Duplicate Refs to replace with Sfn duplicateRefs(textBox, match[1], match[0])

// Replace with Sfn replaceWithSfn(textBox, authorNames, year, page, match[0])

books.push(cite)

// One conversion per click break }

if (0 === books.length) { if (errors > 0) { mw.notify(`First error: ${errorMatches[0]['error']}. Please fix it manually.`, {                       type: 'error',                        title: `${notifyTitle}: ${errors} error(s)`,                        autoHideSeconds: 'long',                    })

// Highlight the first error let content = textBox.textSelection('getContents')

textBox.textSelection('setSelection', {                       start: content.indexOf(errorMatches[0]['match'][0]),                        end: content.indexOf(errorMatches[0]['match'][0]) + errorMatches[0]['match'][0].length,                    })

console.log(errorMatches) } else { mw.notify('No books to convert', {                       title: notifyTitle,                    }) }

return }

// Create Bibliography sub-section under References createBiblioSectionIfNotExists(textBox)

// Add Sfns to Bibliography section addBooksToBibliography(textBox, books)

// Hook to add edit summary mw.hook( 've.saveDialog.stateChanged' ).add(prefillEditSummary)

e.preventDefault })   }

const matchRe = / *(\{\{cite book\s?\|[|\w\s=?-–-—&'#.:+,%\/[\]]+\}\})<\/ref>/imu const yearRe = /(?<=year\s*=)([\w\s]*)(?=\||}})/im const dateRe = /(?<!access-?)date\s*=([\w\s-]*)(?=\||}})/im const pageRe = /\|\s*page\s*=([\w\s]*)(?=\||}})/im const pagesRe = /\|\s*pages\s*=([\w\s–]*)(?=\||}})/im const reflistRe = /==\s?References\s?==\s*/im const biblioRe = /(===? ?Bibliography ?===?\s?\{\{Refbegin(\|.*)?\}\}\s(?:\*\s\{\{cite book[|\w\s=?-–-&'#.:+,%\/[\]]+\}\}\s){0,})\{\{Refend\}\}/imu

function getNextMatch(index) { console.log('Index for match to start from', index) const content = $('#wpTextbox1').textSelection('getContents')

if ( ! matchRe.test(content.substring(index))) { console.log('No matches')

return null }

return matchRe.exec(content.substring(index)) }

function determineAuthorNames(cite, type) { let match let names = [] let nameReStr = `\\|\\s*${type}\\s*=([\\w\\s\\.]*)(?=\\|\|\\}\\})` let re = new RegExp(nameReStr, 'imu')

console.log(cite)

// Determine name without index if (re.test(cite)) { match = re.exec(cite) names.push(match[1].trim) }

let nameIndex = 1

// Determine nth name with indexing while (true) { nameReStr = `\\|\\s*${type}${nameIndex}\\s*=([\\w\\s\\.]*)(?=\\|\|\\}\\})` re = new RegExp(nameReStr, 'imu')

// nth name not found. No further searches for names if ( ! re.test(cite)) { break }

match = re.exec(cite) names.push(match[1].trim)

nameIndex++ }

return names }

function determineYear(cite) { if (yearRe.test(cite)) { return yearRe.exec(cite)[1].trim }

// Determine year from date if ( ! dateRe.test(cite)) { return null }

return (new Date(dateRe.exec(cite)[1])).getFullYear }

function determinePage(cite) { let result = { page: '', cite, }

if (pageRe.test(cite)) { result.page = `|p=${pageRe.exec(cite)[1].trim}` result.cite = cite.replace(pageRe, '') } else { if (pagesRe.test(cite)) { result.page = `|pp=${pagesRe.exec(cite)[1].trim}` result.cite = cite.replace(pagesRe, '') }       }

return result }

// Duplicate Refs to replace with Sfn function duplicateRefs(textBox, refName, fullRef) { console.log('RefName', refName)

// Ref not duplicated if (undefined === refName) { return }

const reStr = ` ` const content = textBox.textSelection('getContents')

textBox.textSelection('setContents', content.replaceAll(new RegExp(reStr, 'imgu'), fullRef)) }

function replaceWithSfn(textBox, authorNames, year, page, fullRef) { // page will have pipe set let sfn = ``

console.log('Sfn', sfn);

const content = textBox.textSelection('getContents')

textBox.textSelection('setContents', content.replaceAll(fullRef, sfn))

mw.notify( `Replaced ${sfn}`, {           type: 'success',            title: notifyTitle,        }) }

function checkIfRefSectionExists(textBox) { const content = textBox.textSelection('getContents')

// Bibliography section exists if (biblioRe.test(content)) { return true }

// References section exists, but not Bibliography which can be created if (reflistRe.test(content)) { return true; }

// References section regex failure mw.notify('References section not found. Possible regex failure.', {           type: 'error',            title: notifyTitle,        })

return false }

function createBiblioSectionIfNotExists(textBox) { const content = textBox.textSelection('getContents')

// Section exists if (biblioRe.test(content)) { return; }

const reflistMatch = reflistRe.exec(content)

// Add Bibliography section textBox.textSelection('encapsulateSelection', {           post: `\n\n=== Bibliography ===\n\n`,            selectionStart: content.indexOf(reflistMatch[0]),            selectionEnd: content.indexOf(reflistMatch[0]) + reflistMatch[0].length,        }) }

function addBooksToBibliography(textBox, books) { const content = textBox.textSelection('getContents')

let bookRefStr = '' for (let book of books) { bookRefStr += `* ${book}\n` }

const biblioMatch = biblioRe.exec(content)

textBox.textSelection('encapsulateSelection', {           post: bookRefStr,            selectionStart: content.indexOf(biblioMatch[1]),            selectionEnd: content.indexOf(biblioMatch[1]) + biblioMatch[1].length,        }) }

function prefillEditSummary { if (ve.init.target.saveDialog) { ve.init.target.saveDialog.editSummaryInput.$input.val('Convert Template:Cite book reference(s) to Sfns (BooksToSfn.js)') }

// Remove hook upon prefilling mw.hook( 've.saveDialog.stateChanged' ).remove(prefillEditSummary) } })

//