Skip to content

Commit

Permalink
support new headers (T13555)
Browse files Browse the repository at this point in the history
Still TODO: Refactor all uses of `ContributionSurveyHeading`
to use WikiHeading instead of HTMLHeadingElement. This will
avoid unnecessary repeated calls of normalizeWikiHeading().
  • Loading branch information
ChlodAlejandro committed Jun 7, 2024
1 parent 4dc21f6 commit c7d9e5f
Show file tree
Hide file tree
Showing 15 changed files with 354 additions and 221 deletions.
16 changes: 12 additions & 4 deletions src/modules/ia/models/CopyrightProblemsListing.ts
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ import decorateEditSummary from '../../../wiki/util/decorateEditSummary';
import MwApi from '../../../MwApi';
import changeTag from '../../../config/changeTag';
import warn from '../../../util/warn';
import normalizeWikiHeading from '../../../wiki/util/normalizeWikiHeading';

export interface SerializedCopyrightProblemsListingData {
basic: boolean;
Expand Down Expand Up @@ -113,17 +114,24 @@ export default class CopyrightProblemsListing {
el.parentElement.tagName === 'LI' ? el.parentElement.parentElement : el.parentElement
).previousElementSibling;

while ( previousPivot != null && previousPivot.tagName !== 'H4' ) {
let heading;
// Search for a level 4 heading backwards.
while (
previousPivot != null &&
// Set the ceiling to be immediately above for efficiency.
( heading = normalizeWikiHeading( previousPivot, previousPivot.parentElement ) )
?.level !== 4
) {
previousPivot = previousPivot.previousElementSibling;
}

if ( previousPivot == null ) {
return false;
}

if ( previousPivot.querySelector( '.mw-headline' ) != null ) {
// At this point, previousPivot is likely a MediaWiki level 4 heading.
const h4Anchor = previousPivot.querySelector( '.mw-headline a' );
// At this point, previousPivot is likely a MediaWiki level 4 heading.
const h4Anchor = heading.h.querySelector( 'a' );
if ( h4Anchor ) {
listingPage = pagelinkToTitle( h4Anchor as HTMLAnchorElement );

// Identify if the page is a proper listing page (within the root page's
Expand Down
71 changes: 34 additions & 37 deletions src/modules/ia/models/CopyrightProblemsSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ import equalTitle from '../../../util/equalTitle';
import swapElements from '../../../util/swapElements';
import NewCopyrightProblemsListing from '../ui/NewCopyrightProblemsListing';
import normalizeTitle from '../../../wiki/util/normalizeTitle';
import normalizeWikiHeading from '../../../wiki/util/normalizeWikiHeading';

/**
* A CopyrightProblemsPage that represents a page that currently exists on a document.
Expand Down Expand Up @@ -116,11 +117,14 @@ export default class CopyrightProblemsSession extends CopyrightProblemsPage {
}

/**
*
* Adds a panel containing the "new listing" buttons (single and multiple)
* and the panel container (when filing a multiple-page listing) to the proper
* location: either at the end of the copyright problems section or replacing
* the redlink to the blank copyright problems page.
*/
addNewListingsPanel(): void {
document.querySelectorAll(
'.mw-headline > a, a.external, a.redlink'
'.mw-headline a, .mw-heading a, a.external, a.redlink'
).forEach( ( el ) => {
const href = el.getAttribute( 'href' );
const url = new URL( href, window.location.href );
Expand All @@ -133,61 +137,54 @@ export default class CopyrightProblemsSession extends CopyrightProblemsPage {
CopyrightProblemsPage.getCurrentListingPage().getPrefixedText()
)
) {
// Crawl backwards, avoiding common inline elements, to see if this is a standalone
// line within the rendered text.
let currentPivot: Element = el.parentElement;

while (
currentPivot !== null &&
[ 'I', 'B', 'SPAN', 'EM', 'STRONG' ].indexOf( currentPivot.tagName ) !== -1
) {
currentPivot = currentPivot.parentElement;
}

// By this point, current pivot will be a <div>, <p>, or other usable element.
if (
!el.parentElement.classList.contains( 'mw-headline' ) &&
( currentPivot == null ||
currentPivot.children.length > 1 )
) {
return;
} else if ( el.parentElement.classList.contains( 'mw-headline' ) ) {
// "Edit source" button of an existing section heading.
let headingBottom = el.parentElement.parentElement.nextElementSibling;
let pos: InsertPosition = 'beforebegin';
if ( el.classList.contains( 'external' ) || el.classList.contains( 'redlink' ) ) {
// Keep crawling up and find the parent of this element that is directly
// below the parser root or the current section.
let currentPivot = el;
while (
headingBottom != null &&
!/^H[123456]$/.test( headingBottom.tagName )
currentPivot != null &&
!currentPivot.classList.contains( 'mw-parser-output' ) &&
[ 'A', 'I', 'B', 'SPAN', 'EM', 'STRONG' ]
.indexOf( currentPivot.tagName ) !== -1
) {
headingBottom = headingBottom.nextElementSibling;
currentPivot = currentPivot.parentElement;
}

if ( headingBottom == null ) {
headingBottom = el.parentElement.parentElement.parentElement;
pos = 'beforeend';
// We're now at the <p> or <div> or whatever.
// Check if it only has one child (the tree that contains this element)
// and if so, replace the links.

if ( currentPivot.children.length > 1 ) {
return;
}

// Add below today's section header.
mw.loader.using( [
'oojs-ui-core',
'oojs-ui.styles.icons-interactions',
'mediawiki.widgets',
'mediawiki.widgets.TitlesMultiselectWidget'
], () => {
// H4
headingBottom.insertAdjacentElement(
pos,
NewCopyrightProblemsListing()
);
swapElements( currentPivot, NewCopyrightProblemsListing() );
} );
} else {
// This is in a heading. Let's place it after the section heading.
const heading = normalizeWikiHeading( el );

if ( heading.root.classList.contains( 'dp-ia-upgraded' ) ) {
return;
}
heading.root.classList.add( 'dp-ia-upgraded' );

mw.loader.using( [
'oojs-ui-core',
'oojs-ui.styles.icons-interactions',
'mediawiki.widgets',
'mediawiki.widgets.TitlesMultiselectWidget'
], () => {
swapElements( el, NewCopyrightProblemsListing() );
heading.root.insertAdjacentElement(
'afterend',
NewCopyrightProblemsListing()
);
} );
}
}
Expand Down
56 changes: 26 additions & 30 deletions src/session/DeputyRootSession.ts
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,6 @@ import DeputyCasePage, { ContributionSurveyHeading } from '../wiki/DeputyCasePag
import DeputyCCISessionStartLink from '../ui/root/DeputyCCISessionStartLink';
import removeElement from '../util/removeElement';
import unwrapWidget from '../util/unwrapWidget';
import sectionHeadingName from '../wiki/util/sectionHeadingName';
import {
DeputyMessageEvent,
DeputySessionRequestMessage,
Expand All @@ -13,9 +12,9 @@ import DeputyContributionSurveySection from '../ui/root/DeputyContributionSurvey
import { SessionInformation } from './DeputySession';
import { ArrayOrNot } from '../types';
import DeputyMessageWidget from '../ui/shared/DeputyMessageWidget';
import sectionHeadingId from '../wiki/util/sectionHeadingId';
import last from '../util/last';
import findNextSiblingElement from '../util/findNextSiblingElement';
import normalizeWikiHeading from '../wiki/util/normalizeWikiHeading';

/**
* The DeputyRootSession. Instantiated only when:
Expand Down Expand Up @@ -43,9 +42,10 @@ export default class DeputyRootSession {

casePage.findContributionSurveyHeadings()
.forEach( ( heading: ContributionSurveyHeading ) => {
const link = DeputyCCISessionStartLink( heading, casePage );
const normalizedHeading = normalizeWikiHeading( heading );
const link = DeputyCCISessionStartLink( normalizedHeading, casePage );
startLink.push( link as HTMLElement );
heading.appendChild( link );
normalizedHeading.root.appendChild( link );
} );

window.deputy.comms.addEventListener( 'sessionStarted', () => {
Expand All @@ -68,7 +68,7 @@ export default class DeputyRootSession {
await mw.loader.using(
[ 'oojs-ui-core', 'oojs-ui.styles.icons-content' ],
() => {
const firstHeading = casePage.findFirstContributionSurveyHeading();
const firstHeading = casePage.findFirstContributionSurveyHeadingElement();
if ( firstHeading ) {
const stopButton = new OO.ui.ButtonWidget( {
label: mw.msg( 'deputy.session.otherActive.button' ),
Expand Down Expand Up @@ -108,9 +108,9 @@ export default class DeputyRootSession {
window.deputy.session.init();
} );

casePage.normalizeSectionHeading(
normalizeWikiHeading(
firstHeading
).insertAdjacentElement(
).root.insertAdjacentElement(
'beforebegin',
unwrapWidget( messageBox )
);
Expand All @@ -136,8 +136,8 @@ export default class DeputyRootSession {
const lastActiveSection =
DeputyRootSession.findFirstLastActiveSection( casePage );
const firstSection =
casePage.normalizeSectionHeading(
casePage.findFirstContributionSurveyHeading()
normalizeWikiHeading(
casePage.findFirstContributionSurveyHeadingElement()
);

// Insert element directly into widget (not as text, or else event
Expand Down Expand Up @@ -165,10 +165,10 @@ export default class DeputyRootSession {
'deputy.session.continue.help' :
'deputy.session.continue.help.fromStart',
lastActiveSection ?
sectionHeadingName( lastActiveSection ) :
normalizeWikiHeading( lastActiveSection ).title :
casePage.lastActiveSections[ 0 ]
.replace( /_/g, ' ' ),
sectionHeadingName( firstSection )
firstSection.title
),
actions: [ continueButton ],
closable: true
Expand All @@ -183,7 +183,7 @@ export default class DeputyRootSession {
DeputyRootSession.continueSession( casePage );
} else {
DeputyRootSession.continueSession( casePage, [
sectionHeadingId( firstSection )
firstSection.id
] );
}
window.deputy.comms.removeEventListener(
Expand All @@ -192,7 +192,7 @@ export default class DeputyRootSession {
);
} );

firstSection.insertAdjacentElement(
firstSection.root.insertAdjacentElement(
'beforebegin',
unwrapWidget( messageBox )
);
Expand Down Expand Up @@ -221,7 +221,7 @@ export default class DeputyRootSession {
[ 'oojs-ui-core', 'oojs-ui.styles.icons-content' ],
() => {
const firstHeading =
casePage.findFirstContributionSurveyHeading();
casePage.findFirstContributionSurveyHeadingElement();
if ( firstHeading ) {
const messageBox = DeputyMessageWidget( {
classes: [
Expand All @@ -232,9 +232,9 @@ export default class DeputyRootSession {
message: mw.msg( 'deputy.session.tabActive.help' ),
closable: true
} );
casePage.normalizeSectionHeading(
normalizeWikiHeading(
firstHeading
).insertAdjacentElement(
).root.insertAdjacentElement(
'beforebegin',
unwrapWidget( messageBox )
);
Expand Down Expand Up @@ -264,7 +264,7 @@ export default class DeputyRootSession {
const csHeadings = casePage.findContributionSurveyHeadings();
for ( const lastActiveSection of casePage.lastActiveSections ) {
for ( const heading of csHeadings ) {
if ( sectionHeadingId( heading ) === lastActiveSection ) {
if ( normalizeWikiHeading( heading ).id === lastActiveSection ) {
return heading;
}
}
Expand All @@ -284,7 +284,7 @@ export default class DeputyRootSession {
_casePage?: DeputyCasePage
): Promise<void> {
const sectionIds = ( Array.isArray( section ) ? section : [ section ] ).map(
( _section ) => sectionHeadingId( _section )
( _section ) => normalizeWikiHeading( _section ).id
);
// Save session to storage
const casePage = _casePage ?? await DeputyCasePage.build();
Expand Down Expand Up @@ -438,7 +438,7 @@ export default class DeputyRootSession {

const activeSectionPromises = [];
for ( const heading of this.casePage.findContributionSurveyHeadings() ) {
const headingId = sectionHeadingId( heading );
const headingId = normalizeWikiHeading( heading ).id;

if ( this.session.caseSections.indexOf( headingId ) !== -1 ) {
activeSectionPromises.push(
Expand Down Expand Up @@ -509,8 +509,8 @@ export default class DeputyRootSession {
* @param heading
*/
addSectionOverlay( casePage: DeputyCasePage, heading: ContributionSurveyHeading ): void {
const normalizedHeading = casePage.normalizeSectionHeading( heading );
const section = casePage.getContributionSurveySection( normalizedHeading );
const normalizedHeading = normalizeWikiHeading( heading ).root;
const section = casePage.getContributionSurveySection( normalizedHeading as HTMLElement );
const list = section.find(
( v ) => v instanceof HTMLElement && v.tagName === 'UL'
) as HTMLUListElement;
Expand Down Expand Up @@ -582,7 +582,7 @@ export default class DeputyRootSession {
return false;
}

const sectionId = sectionHeadingId( heading );
const sectionId = normalizeWikiHeading( heading ).id;
this.sections.push( el );
const lastActiveSession = this.session.caseSections.indexOf( sectionId );
if ( lastActiveSession === -1 ) {
Expand All @@ -591,11 +591,7 @@ export default class DeputyRootSession {
}
await casePage.addActiveSection( sectionId );

if ( heading.parentElement.classList.contains( 'mw-heading' ) ) {
heading.parentElement.insertAdjacentElement( 'afterend', el.render() );
} else {
heading.insertAdjacentElement( 'afterend', el.render() );
}
normalizeWikiHeading( heading ).root.insertAdjacentElement( 'afterend', el.render() );
await el.loadData();
mw.hook( 'deputy.load.cci.session' ).fire();

Expand Down Expand Up @@ -628,9 +624,9 @@ export default class DeputyRootSession {
const casePage = e0 instanceof DeputyContributionSurveySection ?
e0.casePage : e0;
const heading = e0 instanceof DeputyContributionSurveySection ?
e0.heading : e1;
e0.heading : normalizeWikiHeading( e1 );

const sectionId = sectionHeadingId( heading );
const sectionId = heading.id;
const sectionListIndex = this.sections.indexOf( el );
if ( el != null && sectionListIndex !== -1 ) {
this.sections.splice( sectionListIndex, 1 );
Expand All @@ -647,7 +643,7 @@ export default class DeputyRootSession {
} else {
await DeputyRootSession.setSession( this.session );
await casePage.removeActiveSection( sectionId );
this.addSectionOverlay( casePage, heading );
this.addSectionOverlay( casePage, heading.h );
}
}
}
Expand Down
10 changes: 5 additions & 5 deletions src/ui/root/DeputyCCISessionStartLink.tsx
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
import { h } from 'tsx-dom';
import DeputyCasePage, { ContributionSurveyHeading } from '../../wiki/DeputyCasePage';
import sectionHeadingId from '../../wiki/util/sectionHeadingId';
import DeputyCasePage from '../../wiki/DeputyCasePage';
import { WikiHeading } from '../../wiki/util/normalizeWikiHeading';

/**
* The CCI session start link. Starts a CCI session when pressed.
Expand All @@ -10,14 +10,14 @@ import sectionHeadingId from '../../wiki/util/sectionHeadingId';
* @return The link element to be displayed
*/
export default function (
heading: ContributionSurveyHeading,
heading: WikiHeading,
casePage?: DeputyCasePage
): JSX.Element {
return <span class="deputy dp-sessionStarter">
<span class="dp-sessionStarter-bracket">[</span>
<a onClick={ async () => {
if ( casePage && casePage.lastActiveSections.length > 0 ) {
const headingId = sectionHeadingId( heading );
const headingId = heading.id;
if ( window.deputy.config.cci.openOldOnContinue.get() ) {
if ( casePage.lastActiveSections.indexOf( headingId ) === -1 ) {
await casePage.addActiveSection( headingId );
Expand All @@ -29,7 +29,7 @@ export default function (
);
}
} else {
await window.deputy.session.DeputyRootSession.startSession( heading );
await window.deputy.session.DeputyRootSession.startSession( heading.h );
}
} }>{
mw.message(
Expand Down
Loading

0 comments on commit c7d9e5f

Please sign in to comment.