MediaWiki:Common.js: Difference between revisions
MediaWiki interface page
More actions
Git release b4adf72d71e2 |
Git release 7dd2928f7307 |
||
| (7 intermediate revisions by the same user not shown) | |||
| Line 393: | Line 393: | ||
setupSingleActiveToc(); | setupSingleActiveToc(); | ||
} ); | } ); | ||
} ); | |||
}() ); | |||
/* ===== VisualEditor foreground color tool ===== | |||
* Register a real VisualEditor annotation instead of trying to insert span | |||
* nodes through TransactionBuilder. This keeps the selection in the VE model, | |||
* renders the color immediately, and round-trips as | |||
* <span style="color: ...">...</span> through Parsoid. | |||
*/ | |||
( function () { | |||
'use strict'; | |||
var retryTimer = 0; | |||
var annotationName = 'textStyle/foregroundColor'; | |||
var palette = [ | |||
'#000000', '#666666', '#999999', '#cccccc', '#ffffff', | |||
'#e74c3c', '#e67e22', '#f1c40f', '#2ecc71', '#3498db', | |||
'#9b59b6', '#e84393', '#34b0b0', '#0984e3', '#00b894' | |||
]; | |||
function registerAnnotation() { | |||
if ( !ve.dm.modelRegistry.lookup( annotationName ) ) { | |||
ve.dm.ForegroundColorAnnotation = function VeDmForegroundColorAnnotation() { | |||
ve.dm.ForegroundColorAnnotation.super.apply( this, arguments ); | |||
}; | |||
OO.inheritClass( | |||
ve.dm.ForegroundColorAnnotation, | |||
ve.dm.TextStyleAnnotation | |||
); | |||
ve.dm.ForegroundColorAnnotation.static.name = annotationName; | |||
ve.dm.ForegroundColorAnnotation.static.matchTagNames = [ 'span' ]; | |||
ve.dm.ForegroundColorAnnotation.static.matchFunction = function ( domElement ) { | |||
return Boolean( domElement.style && domElement.style.color ); | |||
}; | |||
ve.dm.ForegroundColorAnnotation.static.toDataElement = function ( domElements ) { | |||
return { | |||
type: annotationName, | |||
attributes: { | |||
color: domElements[ 0 ].style.color | |||
} | |||
}; | |||
}; | |||
ve.dm.ForegroundColorAnnotation.static.toDomElements = function ( dataElement, doc ) { | |||
var span = doc.createElement( 'span' ); | |||
span.style.color = dataElement.attributes.color; | |||
return [ span ]; | |||
}; | |||
ve.dm.ForegroundColorAnnotation.prototype.getComparableObject = function () { | |||
return { | |||
type: annotationName, | |||
color: this.getAttribute( 'color' ) | |||
}; | |||
}; | |||
ve.dm.modelRegistry.register( ve.dm.ForegroundColorAnnotation ); | |||
} | |||
if ( !ve.ce.annotationFactory.lookup( annotationName ) ) { | |||
ve.ce.ForegroundColorAnnotation = function VeCeForegroundColorAnnotation() { | |||
ve.ce.ForegroundColorAnnotation.super.apply( this, arguments ); | |||
this.$element.css( 'color', this.model.getAttribute( 'color' ) ); | |||
}; | |||
OO.inheritClass( | |||
ve.ce.ForegroundColorAnnotation, | |||
ve.ce.TextStyleAnnotation | |||
); | |||
ve.ce.ForegroundColorAnnotation.static.name = annotationName; | |||
ve.ce.ForegroundColorAnnotation.static.tagName = 'span'; | |||
ve.ce.annotationFactory.register( ve.ce.ForegroundColorAnnotation ); | |||
} | |||
} | |||
function registerTool() { | |||
if ( ve.ui.toolFactory.lookup( 'foreground' ) ) { | |||
return; | |||
} | |||
function ForegroundColorTool() { | |||
ForegroundColorTool.super.apply( this, arguments ); | |||
this.$popup = null; | |||
} | |||
OO.inheritClass( ForegroundColorTool, ve.ui.Tool ); | |||
ForegroundColorTool.static.name = 'foreground'; | |||
ForegroundColorTool.static.group = 'textStyle'; | |||
ForegroundColorTool.static.icon = 'highlight'; | |||
ForegroundColorTool.static.title = 'Text color'; | |||
ForegroundColorTool.static.autoAdd = false; | |||
ForegroundColorTool.static.supportsPressEvents = true; | |||
ForegroundColorTool.prototype.applyColor = function ( surface, color ) { | |||
var surfaceModel = surface.getModel(); | |||
var fragment = surfaceModel.getFragment(); | |||
var selection = fragment.getSelection(); | |||
if ( selection.isCollapsed() ) { | |||
surface.getView().focus(); | |||
return; | |||
} | |||
fragment = fragment.trimLinearSelection(); | |||
fragment.annotateContent( 'clear', annotationName ); | |||
if ( color ) { | |||
fragment.annotateContent( | |||
'set', | |||
new ve.dm.ForegroundColorAnnotation( { | |||
type: annotationName, | |||
attributes: { color: color } | |||
} ) | |||
); | |||
} | |||
surface.getView().focus(); | |||
}; | |||
ForegroundColorTool.prototype.onSelect = function () { | |||
var tool = this; | |||
var surface = tool.toolbar.getSurface(); | |||
var offset; | |||
if ( !surface ) { | |||
return; | |||
} | |||
if ( tool.$popup ) { | |||
tool.$popup.remove(); | |||
tool.$popup = null; | |||
return; | |||
} | |||
tool.$popup = $( '<div>' ) | |||
.addClass( 'techdocs-ve-color-palette' ) | |||
.css( { | |||
position: 'absolute', | |||
background: '#fff', | |||
border: '1px solid #ccc', | |||
borderRadius: '6px', | |||
padding: '8px', | |||
display: 'grid', | |||
gridTemplateColumns: 'repeat(5, 1fr)', | |||
gap: '4px', | |||
zIndex: 10000, | |||
boxShadow: '0 2px 8px rgba(0,0,0,0.15)' | |||
} ); | |||
$( '<button>' ) | |||
.attr( { | |||
type: 'button', | |||
title: '默认颜色(跟随网页样式)', | |||
'aria-label': '默认颜色(跟随网页样式)' | |||
} ) | |||
.text( '默认颜色' ) | |||
.css( { | |||
gridColumn: '1 / -1', | |||
height: '26px', | |||
padding: '0 8px', | |||
background: '#fff', | |||
color: '#202122', | |||
cursor: 'pointer', | |||
border: '1px solid #a2a9b1', | |||
borderRadius: '3px', | |||
fontSize: '12px', | |||
lineHeight: '24px', | |||
textAlign: 'center' | |||
} ) | |||
.on( 'mousedown', function ( event ) { | |||
event.preventDefault(); | |||
event.stopPropagation(); | |||
tool.applyColor( surface, null ); | |||
tool.$popup.remove(); | |||
tool.$popup = null; | |||
} ) | |||
.appendTo( tool.$popup ); | |||
palette.forEach( function ( color ) { | |||
$( '<button>' ) | |||
.attr( { | |||
type: 'button', | |||
title: color, | |||
'aria-label': color | |||
} ) | |||
.css( { | |||
width: '22px', | |||
height: '22px', | |||
padding: 0, | |||
background: color, | |||
cursor: 'pointer', | |||
border: '1px solid #ddd', | |||
borderRadius: '3px' | |||
} ) | |||
.on( 'mousedown', function ( event ) { | |||
event.preventDefault(); | |||
event.stopPropagation(); | |||
tool.applyColor( surface, color ); | |||
tool.$popup.remove(); | |||
tool.$popup = null; | |||
} ) | |||
.appendTo( tool.$popup ); | |||
} ); | |||
offset = tool.$element.offset(); | |||
tool.$popup.css( { | |||
top: offset.top + tool.$element.outerHeight() + 4, | |||
left: offset.left | |||
} ); | |||
$( 'body' ).append( tool.$popup ); | |||
setTimeout( function () { | |||
$( document ).one( 'mousedown', function ( event ) { | |||
if ( | |||
tool.$popup && | |||
!$( event.target ).closest( tool.$popup ).length | |||
) { | |||
tool.$popup.remove(); | |||
tool.$popup = null; | |||
} | |||
} ); | |||
}, 50 ); | |||
}; | |||
ForegroundColorTool.prototype.onUpdateState = function () { | |||
this.setDisabled( false ); | |||
}; | |||
ve.ui.toolFactory.register( ForegroundColorTool ); | |||
} | |||
function initialize() { | |||
if ( | |||
typeof ve === 'undefined' || | |||
!ve.dm || | |||
!ve.dm.TextStyleAnnotation || | |||
!ve.ce || | |||
!ve.ce.TextStyleAnnotation || | |||
!ve.ui || | |||
!ve.ui.Tool || | |||
typeof OO === 'undefined' | |||
) { | |||
if ( !retryTimer ) { | |||
retryTimer = setTimeout( function () { | |||
retryTimer = 0; | |||
initialize(); | |||
}, 200 ); | |||
} | |||
return; | |||
} | |||
registerAnnotation(); | |||
registerTool(); | |||
} | |||
initialize(); | |||
mw.loader.using( 'ext.veforall.target' ).then( initialize, function () { | |||
if ( !retryTimer ) { | |||
retryTimer = setTimeout( initialize, 500 ); | |||
} | |||
} ); | } ); | ||
}() ); | }() ); | ||
Latest revision as of 21:50, 10 August 2026
( function () {
'use strict';
var ACTIVE_CLASS = 'citizen-toc-list-item--active';
var ACTIVE_TOP_CLASS = 'citizen-toc-level-1--active';
var LINK_SELECTOR = '.citizen-toc-link:not(.citizen-toc-top)';
var NAVIGATION_KEYS = [
'ArrowDown',
'ArrowUp',
'End',
'Home',
'PageDown',
'PageUp',
' '
];
function setupHomeCarousel() {
var carousel = document.querySelector( '.lcd-home-carousel' );
if ( !carousel || carousel.dataset.techdocsCarouselReady === '1' ) {
return;
}
var slides = Array.prototype.slice.call(
carousel.querySelectorAll( '.lcd-home-carousel__slide' )
);
if ( slides.length === 0 ) {
return;
}
carousel.dataset.techdocsCarouselReady = '1';
var interval = parseInt( carousel.dataset.interval, 10 );
if ( !Number.isFinite( interval ) || interval < 1000 ) {
interval = 4000;
}
var currentIndex = Math.max( 0, slides.findIndex( function ( slide ) {
return slide.classList.contains( 'lcd-home-carousel__slide--active' );
} ) );
var timerId = 0;
var dots = [];
var dotsContainer = document.createElement( 'div' );
dotsContainer.className = 'lcd-home-carousel__dots';
dotsContainer.setAttribute( 'role', 'group' );
dotsContainer.setAttribute( 'aria-label', '轮播进度' );
function showSlide( index ) {
currentIndex = ( index + slides.length ) % slides.length;
slides.forEach( function ( slide, slideIndex ) {
var isActive = slideIndex === currentIndex;
slide.classList.toggle(
'lcd-home-carousel__slide--active',
isActive
);
slide.setAttribute( 'aria-hidden', isActive ? 'false' : 'true' );
} );
dots.forEach( function ( dot, dotIndex ) {
if ( dotIndex === currentIndex ) {
dot.setAttribute( 'aria-current', 'true' );
} else {
dot.removeAttribute( 'aria-current' );
}
} );
}
function stopTimer() {
if ( timerId ) {
window.clearInterval( timerId );
timerId = 0;
}
}
function startTimer() {
stopTimer();
if ( slides.length > 1 && !document.hidden ) {
timerId = window.setInterval( function () {
showSlide( currentIndex + 1 );
}, interval );
}
}
slides.forEach( function ( slide, slideIndex ) {
var dot = document.createElement( 'button' );
dot.type = 'button';
dot.className = 'lcd-home-carousel__dot';
dot.setAttribute(
'aria-label',
'显示第 ' + ( slideIndex + 1 ) + ' 张轮播图片'
);
dot.addEventListener( 'click', function () {
showSlide( slideIndex );
startTimer();
} );
dots.push( dot );
dotsContainer.appendChild( dot );
} );
carousel.appendChild( dotsContainer );
showSlide( currentIndex );
startTimer();
document.addEventListener( 'visibilitychange', function () {
if ( document.hidden ) {
stopTimer();
} else {
startTimer();
}
} );
window.addEventListener( 'pagehide', stopTimer );
}
function setupUniqueProductTargets() {
var candidateFields = Array.prototype.slice.call(
document.querySelectorAll(
'input[name^="首页产品卡["][name$="[页面]"]'
)
);
var fields = candidateFields.filter( function ( field ) {
return field.name.indexOf( '[map_field]' ) === -1;
} );
var form = fields.length > 0 ? fields[ 0 ].closest( 'form' ) : null;
if ( !form || form.dataset.techdocsUniqueProductsReady === '1' ) {
return;
}
form.dataset.techdocsUniqueProductsReady = '1';
var message = document.createElement( 'div' );
message.className = 'errorbox';
message.hidden = true;
message.setAttribute( 'role', 'alert' );
form.insertBefore( message, form.firstChild );
form.addEventListener( 'input', function () {
message.hidden = true;
message.textContent = '';
} );
form.addEventListener( 'submit', function ( event ) {
var seen = Object.create( null );
var duplicate = null;
var currentFields = Array.prototype.filter.call(
form.querySelectorAll(
'input[name^="首页产品卡["][name$="[页面]"]'
),
function ( field ) {
return field.name.indexOf( '[map_field]' ) === -1;
}
);
currentFields.some( function ( field ) {
var value = field.value.trim();
if ( value && seen[ value ] ) {
duplicate = field;
return true;
}
if ( value ) {
seen[ value ] = true;
}
return false;
} );
if ( !duplicate ) {
return;
}
event.preventDefault();
event.stopImmediatePropagation();
message.textContent =
'同一产品页面不能被多张首页卡片重复使用,请为每张卡片选择独立产品。';
message.hidden = false;
duplicate.focus();
message.scrollIntoView( { block: 'center' } );
}, true );
}
function decodeFragment( hash ) {
if ( !hash || hash.charAt( 0 ) !== '#' ) {
return '';
}
try {
return decodeURIComponent( hash.slice( 1 ) );
} catch ( error ) {
return hash.slice( 1 );
}
}
function setupSingleActiveToc() {
var toc = document.querySelector( '.citizen-toc' );
var indicator = toc && toc.querySelector( '.citizen-toc-indicator' );
if ( !toc || !indicator || toc.dataset.techdocsSingleActiveToc === '1' ) {
return;
}
var entries = Array.prototype.map.call(
toc.querySelectorAll( LINK_SELECTOR ),
function ( link ) {
var target = document.getElementById( decodeFragment( link.hash ) );
var item = link.closest( '.citizen-toc-list-item' );
return target && item ? {
item: item,
link: link,
target: target
} : null;
}
).filter( Boolean );
if ( entries.length === 0 ) {
return;
}
toc.dataset.techdocsSingleActiveToc = '1';
var applying = false;
var frameId = 0;
var manualEntry = null;
function getActivationTop() {
var value = parseFloat(
window.getComputedStyle( document.documentElement ).scrollPaddingTop
);
return Number.isFinite( value ) ? value : 0;
}
function findEntryForHash() {
var id = decodeFragment( window.location.hash );
return entries.find( function ( entry ) {
return entry.target.id === id;
} ) || null;
}
function findEntryForScroll() {
var activationTop = getActivationTop();
var selected = entries[ 0 ];
entries.some( function ( entry ) {
if ( entry.target.getBoundingClientRect().top <= activationTop + 1 ) {
selected = entry;
return false;
}
return true;
} );
return selected;
}
function updateIndicator( entry ) {
var positioningParent = indicator.offsetParent || toc;
var parentRect = positioningParent.getBoundingClientRect();
var linkRect = entry.link.getBoundingClientRect();
var unitHeight = linkRect.height || entry.link.offsetHeight || 32;
var top = linkRect.top - parentRect.top + positioningParent.scrollTop;
indicator.style.setProperty( '--indicator-unit-height', unitHeight + 'px' );
indicator.style.setProperty( '--indicator-top', top + 'px' );
indicator.style.setProperty( '--indicator-scale', '1' );
}
function applyEntry( entry ) {
if ( !entry ) {
return;
}
applying = true;
var topItem = entry.item.closest( '.citizen-toc-level-1' );
entries.forEach( function ( candidate ) {
var isActive = candidate.item === entry.item;
candidate.item.classList.toggle( ACTIVE_CLASS, isActive );
candidate.item.classList.toggle(
ACTIVE_TOP_CLASS,
candidate.item === topItem
);
if ( isActive ) {
candidate.link.setAttribute( 'aria-current', 'location' );
} else {
candidate.link.removeAttribute( 'aria-current' );
}
} );
if ( topItem && !entries.some( function ( candidate ) {
return candidate.item === topItem;
} ) ) {
topItem.classList.add( ACTIVE_TOP_CLASS );
}
updateIndicator( entry );
applying = false;
}
function update() {
frameId = 0;
applyEntry( manualEntry || findEntryForScroll() );
}
function scheduleUpdate() {
if ( frameId === 0 ) {
frameId = window.requestAnimationFrame( update );
}
}
function releaseManualEntry() {
if ( manualEntry ) {
manualEntry = null;
scheduleUpdate();
}
}
toc.addEventListener( 'click', function ( event ) {
if (
event.defaultPrevented ||
event.button !== 0 ||
event.altKey ||
event.ctrlKey ||
event.metaKey ||
event.shiftKey
) {
return;
}
var link = event.target.closest( LINK_SELECTOR );
if ( !link || !toc.contains( link ) ) {
return;
}
var entry = entries.find( function ( candidate ) {
return candidate.link === link;
} );
if ( !entry ) {
return;
}
event.preventDefault();
event.stopImmediatePropagation();
manualEntry = entry;
applyEntry( entry );
var hash = link.getAttribute( 'href' );
if ( hash ) {
window.history.pushState( null, '', hash );
}
window.requestAnimationFrame( function () {
var targetTop = window.scrollY +
entry.target.getBoundingClientRect().top -
getActivationTop();
window.scrollTo( 0, Math.max( 0, targetTop ) );
} );
}, true );
window.addEventListener( 'scroll', scheduleUpdate, { passive: true } );
window.addEventListener( 'resize', scheduleUpdate );
window.addEventListener( 'wheel', releaseManualEntry, { passive: true } );
window.addEventListener( 'touchstart', releaseManualEntry, { passive: true } );
window.addEventListener( 'pointerdown', function ( event ) {
if ( !toc.contains( event.target ) ) {
releaseManualEntry();
}
}, true );
window.addEventListener( 'keydown', function ( event ) {
if ( NAVIGATION_KEYS.indexOf( event.key ) !== -1 ) {
releaseManualEntry();
}
} );
window.addEventListener( 'hashchange', function () {
manualEntry = findEntryForHash();
scheduleUpdate();
} );
var classObserver = new MutationObserver( function () {
if ( !applying ) {
scheduleUpdate();
}
} );
classObserver.observe( toc, {
attributes: true,
attributeFilter: [ 'class' ],
subtree: true
} );
scheduleUpdate();
}
mw.loader.using( 'skins.citizen.scripts' ).then( function () {
window.requestAnimationFrame( function () {
setupHomeCarousel();
setupUniqueProductTargets();
setupSingleActiveToc();
} );
} );
}() );
/* ===== VisualEditor foreground color tool =====
* Register a real VisualEditor annotation instead of trying to insert span
* nodes through TransactionBuilder. This keeps the selection in the VE model,
* renders the color immediately, and round-trips as
* <span style="color: ...">...</span> through Parsoid.
*/
( function () {
'use strict';
var retryTimer = 0;
var annotationName = 'textStyle/foregroundColor';
var palette = [
'#000000', '#666666', '#999999', '#cccccc', '#ffffff',
'#e74c3c', '#e67e22', '#f1c40f', '#2ecc71', '#3498db',
'#9b59b6', '#e84393', '#34b0b0', '#0984e3', '#00b894'
];
function registerAnnotation() {
if ( !ve.dm.modelRegistry.lookup( annotationName ) ) {
ve.dm.ForegroundColorAnnotation = function VeDmForegroundColorAnnotation() {
ve.dm.ForegroundColorAnnotation.super.apply( this, arguments );
};
OO.inheritClass(
ve.dm.ForegroundColorAnnotation,
ve.dm.TextStyleAnnotation
);
ve.dm.ForegroundColorAnnotation.static.name = annotationName;
ve.dm.ForegroundColorAnnotation.static.matchTagNames = [ 'span' ];
ve.dm.ForegroundColorAnnotation.static.matchFunction = function ( domElement ) {
return Boolean( domElement.style && domElement.style.color );
};
ve.dm.ForegroundColorAnnotation.static.toDataElement = function ( domElements ) {
return {
type: annotationName,
attributes: {
color: domElements[ 0 ].style.color
}
};
};
ve.dm.ForegroundColorAnnotation.static.toDomElements = function ( dataElement, doc ) {
var span = doc.createElement( 'span' );
span.style.color = dataElement.attributes.color;
return [ span ];
};
ve.dm.ForegroundColorAnnotation.prototype.getComparableObject = function () {
return {
type: annotationName,
color: this.getAttribute( 'color' )
};
};
ve.dm.modelRegistry.register( ve.dm.ForegroundColorAnnotation );
}
if ( !ve.ce.annotationFactory.lookup( annotationName ) ) {
ve.ce.ForegroundColorAnnotation = function VeCeForegroundColorAnnotation() {
ve.ce.ForegroundColorAnnotation.super.apply( this, arguments );
this.$element.css( 'color', this.model.getAttribute( 'color' ) );
};
OO.inheritClass(
ve.ce.ForegroundColorAnnotation,
ve.ce.TextStyleAnnotation
);
ve.ce.ForegroundColorAnnotation.static.name = annotationName;
ve.ce.ForegroundColorAnnotation.static.tagName = 'span';
ve.ce.annotationFactory.register( ve.ce.ForegroundColorAnnotation );
}
}
function registerTool() {
if ( ve.ui.toolFactory.lookup( 'foreground' ) ) {
return;
}
function ForegroundColorTool() {
ForegroundColorTool.super.apply( this, arguments );
this.$popup = null;
}
OO.inheritClass( ForegroundColorTool, ve.ui.Tool );
ForegroundColorTool.static.name = 'foreground';
ForegroundColorTool.static.group = 'textStyle';
ForegroundColorTool.static.icon = 'highlight';
ForegroundColorTool.static.title = 'Text color';
ForegroundColorTool.static.autoAdd = false;
ForegroundColorTool.static.supportsPressEvents = true;
ForegroundColorTool.prototype.applyColor = function ( surface, color ) {
var surfaceModel = surface.getModel();
var fragment = surfaceModel.getFragment();
var selection = fragment.getSelection();
if ( selection.isCollapsed() ) {
surface.getView().focus();
return;
}
fragment = fragment.trimLinearSelection();
fragment.annotateContent( 'clear', annotationName );
if ( color ) {
fragment.annotateContent(
'set',
new ve.dm.ForegroundColorAnnotation( {
type: annotationName,
attributes: { color: color }
} )
);
}
surface.getView().focus();
};
ForegroundColorTool.prototype.onSelect = function () {
var tool = this;
var surface = tool.toolbar.getSurface();
var offset;
if ( !surface ) {
return;
}
if ( tool.$popup ) {
tool.$popup.remove();
tool.$popup = null;
return;
}
tool.$popup = $( '<div>' )
.addClass( 'techdocs-ve-color-palette' )
.css( {
position: 'absolute',
background: '#fff',
border: '1px solid #ccc',
borderRadius: '6px',
padding: '8px',
display: 'grid',
gridTemplateColumns: 'repeat(5, 1fr)',
gap: '4px',
zIndex: 10000,
boxShadow: '0 2px 8px rgba(0,0,0,0.15)'
} );
$( '<button>' )
.attr( {
type: 'button',
title: '默认颜色(跟随网页样式)',
'aria-label': '默认颜色(跟随网页样式)'
} )
.text( '默认颜色' )
.css( {
gridColumn: '1 / -1',
height: '26px',
padding: '0 8px',
background: '#fff',
color: '#202122',
cursor: 'pointer',
border: '1px solid #a2a9b1',
borderRadius: '3px',
fontSize: '12px',
lineHeight: '24px',
textAlign: 'center'
} )
.on( 'mousedown', function ( event ) {
event.preventDefault();
event.stopPropagation();
tool.applyColor( surface, null );
tool.$popup.remove();
tool.$popup = null;
} )
.appendTo( tool.$popup );
palette.forEach( function ( color ) {
$( '<button>' )
.attr( {
type: 'button',
title: color,
'aria-label': color
} )
.css( {
width: '22px',
height: '22px',
padding: 0,
background: color,
cursor: 'pointer',
border: '1px solid #ddd',
borderRadius: '3px'
} )
.on( 'mousedown', function ( event ) {
event.preventDefault();
event.stopPropagation();
tool.applyColor( surface, color );
tool.$popup.remove();
tool.$popup = null;
} )
.appendTo( tool.$popup );
} );
offset = tool.$element.offset();
tool.$popup.css( {
top: offset.top + tool.$element.outerHeight() + 4,
left: offset.left
} );
$( 'body' ).append( tool.$popup );
setTimeout( function () {
$( document ).one( 'mousedown', function ( event ) {
if (
tool.$popup &&
!$( event.target ).closest( tool.$popup ).length
) {
tool.$popup.remove();
tool.$popup = null;
}
} );
}, 50 );
};
ForegroundColorTool.prototype.onUpdateState = function () {
this.setDisabled( false );
};
ve.ui.toolFactory.register( ForegroundColorTool );
}
function initialize() {
if (
typeof ve === 'undefined' ||
!ve.dm ||
!ve.dm.TextStyleAnnotation ||
!ve.ce ||
!ve.ce.TextStyleAnnotation ||
!ve.ui ||
!ve.ui.Tool ||
typeof OO === 'undefined'
) {
if ( !retryTimer ) {
retryTimer = setTimeout( function () {
retryTimer = 0;
initialize();
}, 200 );
}
return;
}
registerAnnotation();
registerTool();
}
initialize();
mw.loader.using( 'ext.veforall.target' ).then( initialize, function () {
if ( !retryTimer ) {
retryTimer = setTimeout( initialize, 500 );
}
} );
}() );