Localisation updates from https://translatewiki.net.
[mediawiki.git] / resources / src / mediawiki.action.edit / stash.js
blobc292c04053c09cc7710aa35df80c22a6568b5e73
1 /*!
2  * Pre-emptive page parsing edits.
3  *
4  * See also PageEditStash in PHP.
5  */
6 $( () => {
7         const PRIORITY_LOW = 1;
8         const PRIORITY_HIGH = 2;
10         // Do not attempt to stash "new section" edits, because for those cases the ParserOutput
11         // varies on the edit summary field, and thus pre-parsing the page whilst that field is
12         // being typed in would be counter-productive. (The field is re-purposed for the new
13         // section's heading.)
14         const $form = $( '#editform' );
15         const section = $form.find( '[name=wpSection]' ).val();
16         if ( !$form.length || section === 'new' ) {
17                 return;
18         }
20         let lastText, lastSummary, lastTextHash;
21         let lastPriority = 0;
22         const $text = $form.find( '#wpTextbox1' );
23         const $summary = $form.find( '#wpSummary' );
24         const model = $form.find( '[name=model]' ).val();
25         const format = $form.find( '[name=format]' ).val();
26         const revId = $form.find( '[name=parentRevId]' ).val();
28         // Whether the body text content changed since the last stashEdit()
29         function isTextChanged() {
30                 return lastText !== $text.textSelection( 'getContents' );
31         }
33         // Whether the edit summary has changed since the last stashEdit()
34         function isSummaryChanged() {
35                 return lastSummary !== $summary.textSelection( 'getContents' );
36         }
38         // Send a request to stash the edit to the API.
39         // If a request is in progress, abort it since its payload is stale and the API
40         // may limit concurrent stash parses.
41         const api = new mw.Api();
42         let stashReq;
43         function stashEdit() {
44                 const textChanged = isTextChanged();
45                 const priority = textChanged ? PRIORITY_HIGH : PRIORITY_LOW;
47                 if ( stashReq ) {
48                         if ( lastPriority > priority ) {
49                                 // Stash request for summary change should wait on pending text change stash
50                                 stashReq.then( checkStash );
51                                 return;
52                         }
53                         stashReq.abort();
54                 }
56                 // Update the "last" tracking variables
57                 lastSummary = $summary.textSelection( 'getContents' );
58                 lastPriority = priority;
59                 if ( textChanged ) {
60                         lastText = $text.textSelection( 'getContents' );
61                         // Reset hash
62                         lastTextHash = null;
63                 }
65                 const params = {
66                         formatversion: 2,
67                         action: 'stashedit',
68                         title: mw.config.get( 'wgPageName' ),
69                         section: section,
70                         sectiontitle: '',
71                         summary: lastSummary,
72                         contentmodel: model,
73                         contentformat: format,
74                         baserevid: revId
75                 };
76                 if ( lastTextHash ) {
77                         params.stashedtexthash = lastTextHash;
78                 } else {
79                         params.text = lastText;
80                 }
82                 const req = api.postWithToken( 'csrf', params );
83                 stashReq = req;
84                 req.then( ( data ) => {
85                         if ( req === stashReq ) {
86                                 stashReq = null;
87                         }
88                         if ( data.stashedit && data.stashedit.texthash ) {
89                                 lastTextHash = data.stashedit.texthash;
90                         } else {
91                                 // Request failed or text hash expired;
92                                 // include the text in a future stash request.
93                                 lastTextHash = null;
94                         }
95                 } );
96         }
98         // Check whether text or summary have changed and call stashEdit()
99         function checkStash() {
100                 if ( !isTextChanged() && !isSummaryChanged() ) {
101                         return;
102                 }
104                 stashEdit();
105         }
107         let idleTimeout = 3000;
108         let timer;
109         function onKeyUp( e ) {
110                 // Ignore keystrokes that don't modify text, like cursor movements.
111                 // See <http://www.javascripter.net/faq/keycodes.htm> and
112                 // <http://www.quirksmode.org/js/keys.html>. We don't have to be exhaustive,
113                 // because the cost of misfiring is low.
114                 // * Key code 33-40: Page Up/Down, End, Home, arrow keys.
115                 // * Key code 16-18: Shift, Ctrl, Alt.
116                 if ( ( e.which >= 33 && e.which <= 40 ) || ( e.which >= 16 && e.which <= 18 ) ) {
117                         return;
118                 }
120                 clearTimeout( timer );
121                 timer = setTimeout( checkStash, idleTimeout );
122         }
124         function onSummaryFocus() {
125                 // Summary typing is usually near the end of the workflow and involves less pausing.
126                 // Re-stash more frequently in hopes of capturing the final summary before submission.
127                 idleTimeout = 1000;
128                 // Stash now since the text is likely the final version. The re-stashes based on the
129                 // summary are targeted at caching edit checks that need the final summary.
130                 checkStash();
131         }
133         function onTextFocus() {
134                 // User returned to the text field... reset stash rate to default
135                 idleTimeout = 3000;
136         }
138         $text.on( {
139                 keyup: onKeyUp,
140                 focus: onTextFocus,
141                 change: checkStash
142         } );
143         $summary.on( {
144                 keyup: onKeyUp,
145                 focus: onSummaryFocus,
146                 focusout: checkStash
147         } );
149         if (
150                 // Reverts may involve use (undo) links; stash as they review the diff.
151                 // Since the form has a pre-filled summary, stash the edit immediately.
152                 mw.util.getParamValue( 'undo' ) !== null ||
153                 // Pressing "show changes" and "preview" also signify that the user will
154                 // probably save the page soon
155                 [ 'preview', 'diff' ].indexOf( $form.find( '#mw-edit-mode' ).val() ) > -1
156         ) {
157                 checkStash();
158         }
159 } );