Twinkle mobile test adapter v4: pre-create p-cactions in overflow menu |
Twinkle mobile test adapter v5: on-screen panel like English Wikipedia |
||
| Line 1: | Line 1: | ||
// Twinkle mobile TEST adapter | // Twinkle mobile TEST adapter v5 - personal test only | ||
// Page: User:Bharatwiki Socrates/minerva.js (Minerva skin only) | // Page: User:Bharatwiki Socrates/minerva.js (Minerva skin only) | ||
// | // v4 worked (Twinkle item + inline sub-list inside the More menu), | ||
// | // but the user wants the English Wikipedia behaviour: tap "Twinkle" | ||
// | // and the options open as a panel ON the screen, not buried inside | ||
// | // the scrolling menu. | ||
// | // v5 change: the #p-cactions portlet Twinkle needs is now a floating | ||
// | // panel (fixed position, hidden). The "Twinkle" entry in the More | ||
// | // menu only toggles that panel: tapping it closes the menu and opens | ||
// | // the panel with all Twinkle options. Tapping an option closes the | ||
// panel and opens that module's dialog. | |||
// All user-facing strings in English. | // All user-facing strings in English. | ||
| Line 41: | Line 42: | ||
'.morebits-dialog-content { overflow-x: auto; }' + | '.morebits-dialog-content { overflow-x: auto; }' + | ||
'.select2-container { max-width: 90vw; }' + | '.select2-container { max-width: 90vw; }' + | ||
'#p-cactions .twinkle-mobile- | '#p-cactions.twinkle-mobile-panel { position: fixed;' + | ||
' top: 52px; left: 2vw; width: 96vw; max-height: 72vh;' + | |||
' overflow-y: auto; z-index: 999; background: #fff;' + | |||
' border: 1px solid #a2a9b1; border-radius: 4px;' + | |||
' | ' box-shadow: 0 4px 16px rgba(0,0,0,0.35); padding: 0 0 6px; }' + | ||
'#p-cactions.twinkle-mobile-panel ul { list-style: none;' + | |||
' | ' margin: 0; padding: 0; }' + | ||
' box-shadow: 0 4px 16px rgba(0,0,0,0. | '#p-cactions.twinkle-mobile-panel li a { display: block;' + | ||
'#twinkle-mobile-panel ul { list-style: none | ' padding: 12px 16px; color: #202122; text-decoration: none;' + | ||
' padding: 0; }' + | ' font-size: 1em; border-top: 1px solid #eaecf0; }' + | ||
'#twinkle-mobile-panel li a { display: block;' + | '#p-cactions.twinkle-mobile-panel li a:active {' + | ||
' padding: | ' background: #eaecf0; }' + | ||
'.twinkle-panel-head { display: flex;' + | |||
' justify-content: space-between; align-items: center;' + | |||
' padding: 10px 16px; font-weight: bold; }' + | |||
'.twinkle-panel-close { background: none; border: 0;' + | |||
' font-size: 20px; line-height: 1; padding: 4px 8px;' + | |||
' cursor: pointer; }' | |||
); | ); | ||
rawCss( 'MediaWiki:Gadget-Twinkle.css' ); | rawCss( 'MediaWiki:Gadget-Twinkle.css' ); | ||
rawCss( 'MediaWiki:Gadget-morebits.css' ); | rawCss( 'MediaWiki:Gadget-morebits.css' ); | ||
rawCss( 'MediaWiki:Gadget-select2.min.css' ); | rawCss( 'MediaWiki:Gadget-select2.min.css' ); | ||
var panel = null; | |||
function togglePanel( show ) { | |||
if ( !panel ) { | |||
return; | |||
} | |||
panel.style.display = show ? 'block' : 'none'; | |||
} | |||
function closeOverflow() { | |||
var cb = document.getElementById( | |||
'page-actions-overflow-checkbox' ); | |||
if ( cb ) { | |||
cb.checked = false; | |||
} | |||
} | |||
function createPortlet() { | function createPortlet() { | ||
if ( document.getElementById( 'p-cactions' ) ) { | if ( document.getElementById( 'p-cactions' ) ) { | ||
panel = document.getElementById( 'p-cactions' ); | |||
return true; | return true; | ||
} | } | ||
// The floating panel IS the p-cactions portlet. | |||
panel = document.createElement( 'div' ); | |||
panel.id = 'p-cactions'; | |||
panel.className = 'twinkle-mobile-panel'; | |||
panel.style.display = 'none'; | |||
var head = document.createElement( 'div' ); | |||
head.className = 'twinkle-panel-head'; | |||
var title = document.createElement( 'span' ); | |||
title.textContent = 'Twinkle'; | |||
var closeBtn = document.createElement( 'button' ); | |||
closeBtn.className = 'twinkle-panel-close'; | |||
closeBtn.textContent = '×'; | |||
closeBtn.addEventListener( 'click', function () { | |||
togglePanel( false ); | |||
} ); | |||
head.appendChild( title ); | |||
head.appendChild( closeBtn ); | |||
panel.appendChild( head ); | |||
var list = document.createElement( 'ul' ); | |||
panel.appendChild( list ); | |||
document.body.appendChild( panel ); | |||
// Any tap on a module link closes the panel (dialog opens). | |||
panel.addEventListener( 'click', function ( e ) { | |||
if ( e.target.closest( 'li a' ) && | |||
!e.target.closest( '.twinkle-panel-head' ) ) { | |||
togglePanel( false ); | |||
} | |||
} ); | |||
// Entry inside the More (overflow) menu toggles the panel. | |||
var overflow = document.querySelector( 'ul#p-tb' ) || | var overflow = document.querySelector( 'ul#p-tb' ) || | ||
document.querySelector( '.page-actions-overflow-list' ); | document.querySelector( '.page-actions-overflow-list' ); | ||
| Line 67: | Line 120: | ||
var li = document.createElement( 'li' ); | var li = document.createElement( 'li' ); | ||
li.className = 'toggle-list-item'; | li.className = 'toggle-list-item'; | ||
var a = document.createElement( 'a' ); | |||
var | a.className = 'toggle-list-item__anchor'; | ||
a.href = '#'; | |||
var label = document.createElement( 'span' ); | var label = document.createElement( 'span' ); | ||
label.className = 'toggle-list-item__label'; | label.className = 'toggle-list-item__label'; | ||
label.textContent = 'Twinkle'; | label.textContent = 'Twinkle'; | ||
a.appendChild( label ); | |||
a.addEventListener( 'click', function ( e ) { | |||
e.preventDefault(); | e.preventDefault(); | ||
closeOverflow(); | |||
togglePanel( true ); | |||
} ); | } ); | ||
li.appendChild( | li.appendChild( a ); | ||
overflow.appendChild( li ); | overflow.appendChild( li ); | ||
} else { | |||
// Fallback: floating TW button toggles the panel. | |||
var btn = document.createElement( 'button' ); | |||
btn.textContent = 'TW'; | |||
btn.style.cssText = 'position:fixed;right:12px;' + | |||
'bottom:64px;z-index:998;padding:10px 14px;' + | |||
'border-radius:20px;background:#202122;color:#fff;' + | |||
'border:0;'; | |||
btn.addEventListener( 'click', function () { | |||
togglePanel( panel.style.display === 'none' ); | |||
} ); | |||
document.body.appendChild( btn ); | |||
} | } | ||
return true; | return true; | ||
} | } | ||
| Line 124: | Line 162: | ||
return; | return; | ||
} | } | ||
mw.notify( 'Twinkle loaded but its links did not arrive ( | mw.notify( 'Twinkle loaded but its links did not arrive (v5)', | ||
{ type: 'error' } ); | { type: 'error' } ); | ||
} | } | ||
Revision as of 05:26, 1 November 2026
// Twinkle mobile TEST adapter v5 - personal test only
// Page: User:Bharatwiki Socrates/minerva.js (Minerva skin only)
// v4 worked (Twinkle item + inline sub-list inside the More menu),
// but the user wants the English Wikipedia behaviour: tap "Twinkle"
// and the options open as a panel ON the screen, not buried inside
// the scrolling menu.
// v5 change: the #p-cactions portlet Twinkle needs is now a floating
// panel (fixed position, hidden). The "Twinkle" entry in the More
// menu only toggles that panel: tapping it closes the menu and opens
// the panel with all Twinkle options. Tapping an option closes the
// panel and opens that module's dialog.
// All user-facing strings in English.
( function () {
if ( mw.config.get( 'skin' ) !== 'minerva' ) {
return;
}
if ( window.twinkleMobileTestLoaded ) {
return;
}
window.twinkleMobileTestLoaded = true;
var indexPhp = mw.util.wikiScript( 'index' );
function rawUrl( title ) {
return indexPhp + '?title=' + encodeURIComponent( title ) +
'&action=raw&ctype=text/javascript';
}
function rawCss( title ) {
var link = document.createElement( 'link' );
link.rel = 'stylesheet';
link.href = indexPhp + '?title=' + encodeURIComponent( title ) +
'&action=raw&ctype=text/css';
document.head.appendChild( link );
}
function loadScript( title ) {
return $.getScript( rawUrl( title ) );
}
mw.util.addCSS(
'.ui-dialog { max-width: 96vw !important; left: 2vw !important; }' +
'.morebits-dialog { max-width: 96vw !important; }' +
'.morebits-dialog-content { overflow-x: auto; }' +
'.select2-container { max-width: 90vw; }' +
'#p-cactions.twinkle-mobile-panel { position: fixed;' +
' top: 52px; left: 2vw; width: 96vw; max-height: 72vh;' +
' overflow-y: auto; z-index: 999; background: #fff;' +
' border: 1px solid #a2a9b1; border-radius: 4px;' +
' box-shadow: 0 4px 16px rgba(0,0,0,0.35); padding: 0 0 6px; }' +
'#p-cactions.twinkle-mobile-panel ul { list-style: none;' +
' margin: 0; padding: 0; }' +
'#p-cactions.twinkle-mobile-panel li a { display: block;' +
' padding: 12px 16px; color: #202122; text-decoration: none;' +
' font-size: 1em; border-top: 1px solid #eaecf0; }' +
'#p-cactions.twinkle-mobile-panel li a:active {' +
' background: #eaecf0; }' +
'.twinkle-panel-head { display: flex;' +
' justify-content: space-between; align-items: center;' +
' padding: 10px 16px; font-weight: bold; }' +
'.twinkle-panel-close { background: none; border: 0;' +
' font-size: 20px; line-height: 1; padding: 4px 8px;' +
' cursor: pointer; }'
);
rawCss( 'MediaWiki:Gadget-Twinkle.css' );
rawCss( 'MediaWiki:Gadget-morebits.css' );
rawCss( 'MediaWiki:Gadget-select2.min.css' );
var panel = null;
function togglePanel( show ) {
if ( !panel ) {
return;
}
panel.style.display = show ? 'block' : 'none';
}
function closeOverflow() {
var cb = document.getElementById(
'page-actions-overflow-checkbox' );
if ( cb ) {
cb.checked = false;
}
}
function createPortlet() {
if ( document.getElementById( 'p-cactions' ) ) {
panel = document.getElementById( 'p-cactions' );
return true;
}
// The floating panel IS the p-cactions portlet.
panel = document.createElement( 'div' );
panel.id = 'p-cactions';
panel.className = 'twinkle-mobile-panel';
panel.style.display = 'none';
var head = document.createElement( 'div' );
head.className = 'twinkle-panel-head';
var title = document.createElement( 'span' );
title.textContent = 'Twinkle';
var closeBtn = document.createElement( 'button' );
closeBtn.className = 'twinkle-panel-close';
closeBtn.textContent = '×';
closeBtn.addEventListener( 'click', function () {
togglePanel( false );
} );
head.appendChild( title );
head.appendChild( closeBtn );
panel.appendChild( head );
var list = document.createElement( 'ul' );
panel.appendChild( list );
document.body.appendChild( panel );
// Any tap on a module link closes the panel (dialog opens).
panel.addEventListener( 'click', function ( e ) {
if ( e.target.closest( 'li a' ) &&
!e.target.closest( '.twinkle-panel-head' ) ) {
togglePanel( false );
}
} );
// Entry inside the More (overflow) menu toggles the panel.
var overflow = document.querySelector( 'ul#p-tb' ) ||
document.querySelector( '.page-actions-overflow-list' );
if ( overflow ) {
var li = document.createElement( 'li' );
li.className = 'toggle-list-item';
var a = document.createElement( 'a' );
a.className = 'toggle-list-item__anchor';
a.href = '#';
var label = document.createElement( 'span' );
label.className = 'toggle-list-item__label';
label.textContent = 'Twinkle';
a.appendChild( label );
a.addEventListener( 'click', function ( e ) {
e.preventDefault();
closeOverflow();
togglePanel( true );
} );
li.appendChild( a );
overflow.appendChild( li );
} else {
// Fallback: floating TW button toggles the panel.
var btn = document.createElement( 'button' );
btn.textContent = 'TW';
btn.style.cssText = 'position:fixed;right:12px;' +
'bottom:64px;z-index:998;padding:10px 14px;' +
'border-radius:20px;background:#202122;color:#fff;' +
'border:0;';
btn.addEventListener( 'click', function () {
togglePanel( panel.style.display === 'none' );
} );
document.body.appendChild( btn );
}
return true;
}
function checkResult( tries ) {
var landed = document.querySelectorAll(
'#p-cactions li[id^="twinkle-"]' ).length;
if ( landed ) {
mw.notify( 'Twinkle is ready: open the More menu and tap ' +
'Twinkle (' + landed + ' options)', { type: 'info' } );
return;
}
if ( tries > 0 ) {
setTimeout( function () { checkResult( tries - 1 ); }, 2000 );
return;
}
mw.notify( 'Twinkle loaded but its links did not arrive (v5)',
{ type: 'error' } );
}
function start() {
createPortlet();
mw.loader.using( [
'mediawiki.util', 'mediawiki.api', 'mediawiki.storage',
'mediawiki.Title', 'mediawiki.user', 'jquery.ui'
] ).then( function () {
return loadScript( 'MediaWiki:Gadget-select2.min.js' );
} ).then( function () {
return loadScript( 'MediaWiki:Gadget-morebits.js' );
} ).then( function () {
return loadScript( 'MediaWiki:Gadget-Twinkle.js' );
} ).then( function () {
checkResult( 10 );
} ).catch( function ( err ) {
mw.notify( 'Twinkle mobile test load failed: ' + err,
{ type: 'error' } );
} );
}
if ( document.readyState === 'loading' ) {
document.addEventListener( 'DOMContentLoaded', start );
} else {
start();
}
}() );