11import ParsoidDocument from '@chlodalejandro/parsoid' ;
22import last from '../../../util/last' ;
3+ import AttributionNotice from './AttributionNotice' ;
4+ import WikiAttributionNotices from './WikiAttributionNotices' ;
35import CopiedTemplate from './CopiedTemplate' ;
46
57/**
68 * An event dispatched when a template inside a `CopiedTemplateEditorDialog` is inserted.
79 */
810export class TemplateInsertEvent extends Event {
911
10- template : CopiedTemplate ;
12+ template : AttributionNotice ;
1113
1214 /**
1315 * @param template The template that was inserted
1416 * @param eventInitDict
1517 */
16- constructor ( template : CopiedTemplate , eventInitDict ?: EventInit ) {
18+ constructor ( template : AttributionNotice , eventInitDict ?: EventInit ) {
1719 super ( 'templateInsert' , eventInitDict ) ;
1820 this . template = template ;
1921 }
@@ -64,25 +66,15 @@ export default class CTEParsoidDocument extends ParsoidDocument {
6466 '<html><body><section data-mw-section-id="0"></section></body></html>' ;
6567
6668 /**
67- * Aliases of the {{copied}} template. This must be in lowercase and all
68- * spaces must be replaced with underscores.
69+ * A map of all Parsoid HTML elements and their attribution notices. When notices are
70+ * detected, they are added here. ParsoidTemplateTransclusionNode is not used here
71+ * since they are regenerated every time `findTemplate` is called.
6972 */
70- static readonly copiedTemplateAliases = < const > [
71- 'copied' ,
72- 'copied_from' ,
73- 'copywithin'
74- ] ;
75-
76- /**
77- * A list of {{copied}} notices in the document.
78- *
79- * @type {CopiedTemplate[] }
80- */
81- copiedNotices : CopiedTemplate [ ] ;
73+ notices : Map < HTMLElement , AttributionNotice > = new Map ( ) ;
8274 /**
8375 * The original number of {{copied}} notices in the document.
8476 */
85- originalNoticeCount : number ;
77+ originalCount : number = null ;
8678
8779 /**
8880 * Creates a new CTE-specific ParsoidDocument. This extends from the existing
@@ -100,8 +92,8 @@ export default class CTEParsoidDocument extends ParsoidDocument {
10092 return ;
10193 }
10294
103- this . findCopiedNotices ( ) ;
104- this . originalNoticeCount = this . copiedNotices . length ;
95+ const notices = this . findCopiedNotices ( ) ;
96+ this . originalCount = notices . length ;
10597 } ) ;
10698 }
10799
@@ -110,52 +102,53 @@ export default class CTEParsoidDocument extends ParsoidDocument {
110102 */
111103 reset ( ) {
112104 super . reset ( ) ;
113- this . originalNoticeCount = undefined ;
114- this . copiedNotices = undefined ;
105+ this . originalCount = undefined ;
106+ this . notices . clear ( ) ;
115107 }
116108
117109 /**
118- * Finds this document's {{copied}} notices.
110+ * Finds all content attribution notices in the talk page. This includes {{copied}},
111+ * {{merged to}}, {{merged from}}, etc.
112+ *
113+ * @return An array of AttributionNotice objects.
119114 */
120- findCopiedNotices ( ) {
121- if ( ! this . copiedNotices ) {
122- this . copiedNotices = [ ] ;
123- }
124-
125- const newCopiedNotices : CopiedTemplate [ ] = [ ] ;
115+ findNotices ( ) : AttributionNotice [ ] {
126116 this . buildIndex ( ) ;
117+ // Used instead of `this.notices.values()` to exclude nodes that are no longer on the DOM.
118+ const notices : AttributionNotice [ ] = [ ] ;
127119
128- for ( const templateElement of this . findTemplate (
129- new RegExp (
130- CTEParsoidDocument . copiedTemplateAliases . map (
131- ( v ) => `(${ mw . util . escapeRegExp ( v ) } )`
132- ) . join ( '|' ) ,
133- 'gi'
134- )
135- ) ) {
136- // This is a copied template.
137- const existing = this . copiedNotices . find (
138- ( v ) => v . element === templateElement . originalElement
139- ) ;
140- if ( existing ) {
141- // Record exists, reuse that same object (prevents memory leaks).
142- newCopiedNotices . push ( existing ) ;
143- } else {
144- // Not yet in the existing array, create a new object.
145- const notice = new CopiedTemplate (
146- CTEParsoidTransclusionTemplateNode . upgradeNode ( templateElement , this )
147- ) ;
148- newCopiedNotices . push (
149- notice
120+ for (
121+ const node of this . findTemplate ( WikiAttributionNotices . templateAliasRegExp )
122+ ) {
123+ if ( ! this . notices . has ( node . originalElement ) ) {
124+ // Notice not yet cached, but this is an attribution notice.
125+ // Now to determine what type.
126+ const type = WikiAttributionNotices . getTemplateNoticeType (
127+ node . getTarget ( ) . href
150128 ) ;
151- notice . addEventListener ( 'destroy' , ( ) => {
152- const i = this . copiedNotices . indexOf ( notice ) ;
153- this . copiedNotices . splice ( i , 1 ) ;
154- } ) ;
129+
130+ const noticeInstance = new (
131+ WikiAttributionNotices . attributionNoticeClasses [ type ]
132+ ) ( CTEParsoidTransclusionTemplateNode . upgradeNode ( node , this ) ) ;
133+ this . notices . set ( node . originalElement , noticeInstance ) ;
155134 }
135+
136+ notices . push ( this . notices . get ( node . originalElement ) ) ;
156137 }
157138
158- this . copiedNotices = newCopiedNotices ;
139+ return notices ;
140+ }
141+
142+ /**
143+ * Finds this document's {{copied}} notices.
144+ *
145+ * @return An array of all CopiedTemplate objects found
146+ */
147+ findCopiedNotices ( ) : CopiedTemplate [ ] {
148+ return this . findNotices ( ) . filter (
149+ ( notice ) => notice instanceof
150+ WikiAttributionNotices . attributionNoticeClasses . copied
151+ ) as CopiedTemplate [ ] ;
159152 }
160153
161154 /**
@@ -237,9 +230,7 @@ export default class CTEParsoidDocument extends ParsoidDocument {
237230 // Insert.
238231 element . insertAdjacentElement ( position , template ) ;
239232 this . findCopiedNotices ( ) ;
240- const templateObject = this . copiedNotices . find (
241- ( v ) => v . element === template
242- ) ;
233+ const templateObject = this . notices . get ( template ) ;
243234 this . dispatchEvent ( new TemplateInsertEvent ( templateObject ) ) ;
244235 }
245236}
0 commit comments