User:Feeglgeef/wikilambda editsource.js
Appearance
Note: After publishing, you may have to bypass your browser's cache to see the changes.
- Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
- Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
- Edge: Hold Ctrl while clicking Refresh, or press Ctrl-F5.
/*
Install by going to [[Special:mypage/common.js]] and add the following line:
mw.loader.load( '//www.wikifunctions.org/w/index.php?title=User:Feeglgeef/wikilambda_editsource.js&action=raw&ctype=text/javascript' );
*/
/*
Based off of original copy made by [[user:מקף]] at [[user:מקף/wikilambda_editsource.js]].
*/
( function () {
'use strict';
const LINK_LABEL = 'Edit Raw JSON';
const LINK_TOOLTIP = 'Edit this ZObject as raw JSON';
const DEFAULT_SUMMARY = 'edit via [[User:Feeglgeef/wikilambda_editsource.js|raw-JSON edit tool]]';
const zid = window.location.href.match( /\/(Z\d+)\b/ )?.[ 1 ];
function fetchJson( z ) {
const url = mw.util.getUrl( z, { action: 'raw' } );
return fetch( url ).then( function ( r ) {
if ( !r.ok ) {
throw new Error( 'HTTP ' + r.status + ' fetching ' + z );
}
return r.text();
} );
}
function save( z, newJson, summary ) {
const api = new mw.Api();
return api.post( {
action: 'wikilambda_edit',
format: 'json',
assert: 'user',
summary: summary || DEFAULT_SUMMARY,
zid: z,
zobject: newJson,
token: mw.user.tokens.get( 'csrfToken' )
} );
}
function describeError( code, data ) {
// mw.Api rejects its Deferred as (code, data). `code` is a short
// string like 'http' or 'ratelimited'; `data` usually carries the
// detailed API error object. Either may be missing.
if ( data && data.error && data.error.info ) {
return ( data.error.code || code ) + ': ' + data.error.info;
}
if ( data && data.exception ) {
return code + ': ' + data.exception;
}
if ( typeof code === 'string' ) {
return code;
}
try {
return JSON.stringify( code );
} catch ( _ ) {
return String( code );
}
}
function openEditor( z, content ) {
const editor = $(
'<div class="ext-wikilambda-widget-base" id="wikilambda_editsource" ' +
'style="background-color: ghostwhite; max-width: none; padding: 0.5em;"></div>'
);
const textarea = $( '<textarea></textarea>' )
.css( {
width: '100%',
height: '350px',
'min-height': '200px',
resize: 'vertical',
direction: 'ltr',
'font-family': 'monospace'
} )
.val( content );
const summaryInput = $( '<input>' )
.attr( {
type: 'text',
placeholder: 'Summary (default: "' + DEFAULT_SUMMARY + '")'
} )
.css( {
width: '75%',
height: '30px',
'margin-top': '0.25em'
} );
const status = $( '<span></span>' )
.css( { 'margin-right': '0.5em', color: '#555' } );
const saveBtn = $( '<button>Save</button>' )
.addClass(
'cdx-button cdx-button--action-progressive ' +
'cdx-button--weight-primary cdx-button--size-medium cdx-button--framed'
)
.css( { float: 'inline-end', margin: '0 0 0 0.25em' } );
const closeBtn = $( '<button>Close</button>' )
.addClass(
'cdx-button cdx-button--action-default ' +
'cdx-button--weight-primary cdx-button--size-medium cdx-button--framed'
)
.css( { float: 'inline-end', margin: '0' } );
saveBtn.on( 'click', function () {
const value = textarea.val();
if ( !value ) {
mw.notify( 'Please fill the source', { type: 'warn' } );
return;
}
if ( value === content ) {
mw.notify( 'No changes detected', { type: 'warn' } );
return;
}
try {
JSON.parse( value );
} catch ( e ) {
mw.notify( 'Invalid JSON: ' + e.message, {
type: 'error',
autoHide: false
} );
return;
}
saveBtn.prop( 'disabled', true );
closeBtn.prop( 'disabled', true );
status.text( 'Saving…' );
save( z, value, summaryInput.val() ).then(
function () {
editor.remove();
mw.notify(
$( '<a>' )
.append( $( '<strong>' ).text( 'Saved — click to reload' ) )
.on( 'click', function () {
window.location.assign(
window.location.href.replace(
/#wikilambda_editsource$/, ''
)
);
} ),
{ autoHide: false }
);
},
function ( code, data ) {
saveBtn.prop( 'disabled', false );
closeBtn.prop( 'disabled', false );
status.text( '' );
// Log the raw failure so the user can inspect via devtools.
mw.log.error( 'wikilambda_edit failed', code, data );
mw.notify(
$( '<strong>' ).text( 'Save failed: ' + describeError( code, data ) ),
{ type: 'error', autoHide: false }
);
}
);
} );
closeBtn.on( 'click', function () {
editor.remove();
} );
const buttonBar = $( '<div></div>' )
.css( { 'margin-top': '0.5em', overflow: 'auto' } )
.append( saveBtn, closeBtn, status );
editor.append( textarea, summaryInput, buttonBar );
$( '#bodyContent' ).prepend( editor );
}
function openForCurrentZid() {
$( '#wikilambda_editsource' ).remove();
if ( !zid ) {
return;
}
fetchJson( zid ).then(
function ( body ) {
openEditor( zid, body );
},
function ( err ) {
mw.notify(
$( '<strong>' ).text( 'Fetch failed: ' + ( err && err.message ? err.message : err ) ),
{ type: 'error', autoHide: false }
);
}
);
}
$.when(
mw.loader.using( [ 'mediawiki.util', 'mediawiki.api' ], $.ready )
).then( function () {
const contentModel = mw.config.get( 'wgPageContentModel' );
const eligible =
contentModel === 'wikilambda' ||
contentModel === 'Wikibase Item' ||
!!zid;
if ( !eligible ) {
return;
}
const node = mw.util.addPortletLink(
'p-views',
'#wikilambda_editsource',
LINK_LABEL,
'',
LINK_TOOLTIP,
'r'
);
$( node ).on( 'click', function ( e ) {
e.preventDefault();
openForCurrentZid();
} );
} );
}() );