]> scripts.mit.edu Git - autoinstallsdev/mediawiki.git/blob - extensions/Cite/modules/ve-cite/ve.ui.MWCitationDialog.js
MediaWiki 1.30.2
[autoinstallsdev/mediawiki.git] / extensions / Cite / modules / ve-cite / ve.ui.MWCitationDialog.js
1 /*
2  * VisualEditor user interface MWCitationDialog class.
3  *
4  * @copyright 2011-2017 Cite VisualEditor Team and others; see AUTHORS.txt
5  * @license The MIT License (MIT); see LICENSE.txt
6  */
7
8 /**
9  * Dialog for inserting and editing MediaWiki citations.
10  *
11  * @class
12  * @extends ve.ui.MWTemplateDialog
13  *
14  * @constructor
15  * @param {Object} [config] Configuration options
16  */
17 ve.ui.MWCitationDialog = function VeUiMWCitationDialog( config ) {
18         // Parent constructor
19         ve.ui.MWCitationDialog.super.call( this, config );
20
21         // Properties
22         this.referenceModel = null;
23         this.referenceNode = null;
24         this.inDialog = '';
25 };
26
27 /* Inheritance */
28
29 OO.inheritClass( ve.ui.MWCitationDialog, ve.ui.MWTemplateDialog );
30
31 /* Static Properties */
32
33 ve.ui.MWCitationDialog.static.name = 'citation';
34
35 /* Methods */
36
37 /**
38  * Get the reference node to be edited.
39  *
40  * @return {ve.dm.MWReferenceNode|null} Reference node to be edited, null if none exists
41  */
42 ve.ui.MWCitationDialog.prototype.getReferenceNode = function () {
43         var selectedNode = this.getFragment().getSelectedNode();
44
45         if ( selectedNode instanceof ve.dm.MWReferenceNode ) {
46                 return selectedNode;
47         }
48
49         return null;
50 };
51
52 /**
53  * @inheritdoc
54  */
55 ve.ui.MWCitationDialog.prototype.getSelectedNode = function () {
56         var branches, leaves, transclusionNode,
57                 referenceNode = this.getReferenceNode();
58
59         if ( referenceNode ) {
60                 branches = referenceNode.getInternalItem().getChildren();
61                 leaves = branches &&
62                         branches.length === 1 &&
63                         branches[ 0 ].canContainContent() &&
64                         branches[ 0 ].getChildren();
65                 transclusionNode = leaves &&
66                         leaves.length === 1 &&
67                         leaves[ 0 ] instanceof ve.dm.MWTransclusionNode &&
68                         leaves[ 0 ];
69         }
70
71         return transclusionNode || null;
72 };
73
74 /**
75  * @inheritdoc
76  */
77 ve.ui.MWCitationDialog.prototype.initialize = function ( data ) {
78         // Parent method
79         ve.ui.MWCitationDialog.super.prototype.initialize.call( this, data );
80
81         // HACK: Use the same styling as single-mode transclusion dialog - this should be generalized
82         this.$content.addClass( 've-ui-mwTransclusionDialog-single' );
83 };
84
85 /**
86  * @inheritdoc
87  */
88 ve.ui.MWCitationDialog.prototype.getSetupProcess = function ( data ) {
89         return ve.ui.MWCitationDialog.super.prototype.getSetupProcess.call( this, data )
90                 .next( function () {
91                         data = data || {};
92                         this.inDialog = data.inDialog;
93
94                         // Initialization
95                         if ( this.selectedNode ) {
96                                 this.referenceNode = this.getReferenceNode();
97                                 if ( this.referenceNode ) {
98                                         this.referenceModel = ve.dm.MWReferenceModel.static.newFromReferenceNode(
99                                                 this.referenceNode
100                                         );
101                                 }
102                         }
103                         this.actions.forEach( { actions: 'insert' }, function ( action ) {
104                                 action.setLabel( ve.msg( 'visualeditor-dialog-action-insert' ) );
105                         } );
106                 }, this );
107 };
108
109 ve.ui.MWCitationDialog.prototype.onTransclusionReady = function () {
110         // Parent method
111         ve.ui.MWCitationDialog.super.prototype.onTransclusionReady.call( this );
112
113         if ( !this.hasUsefulParameter() ) {
114                 this.actions.setAbilities( { apply: false, insert: false } );
115         }
116 };
117
118 /**
119  * @inheritdoc
120  */
121 ve.ui.MWCitationDialog.prototype.setPageByName = function ( param ) {
122         var hasUsefulParameter = this.hasUsefulParameter();
123
124         // Parent method
125         ve.ui.MWCitationDialog.super.prototype.setPageByName.call( this, param );
126
127         this.actions.setAbilities( { apply: hasUsefulParameter, insert: hasUsefulParameter } );
128 };
129
130 /**
131  * @inheritdoc
132  */
133 ve.ui.MWCitationDialog.prototype.onAddParameterBeforeLoad = function ( page ) {
134         var dialog = this,
135                 hasUsefulParameter = this.hasUsefulParameter();
136
137         page.preLoad = true;
138         page.valueInput.on( 'change', function () {
139                 dialog.actions.setAbilities( { apply: hasUsefulParameter, insert: hasUsefulParameter } );
140         } );
141 };
142
143 /**
144  * Works out whether there are any set parameters that aren't just placeholders
145  *
146  * @return {boolean}
147  */
148 ve.ui.MWCitationDialog.prototype.hasUsefulParameter = function () {
149         var foundUseful = false;
150         $.each( this.bookletLayout.pages, function () {
151                 if (
152                         this instanceof ve.ui.MWParameterPage &&
153                         ( !this.preLoad || this.valueInput.getValue() !== '' )
154                 ) {
155                         foundUseful = true;
156                         return false;
157                 }
158         } );
159         return foundUseful;
160 };
161
162 /**
163  * @inheritdoc
164  */
165 ve.ui.MWCitationDialog.prototype.getActionProcess = function ( action ) {
166         var dialog = this;
167         if (
168                 this.inDialog !== 'reference' &&
169                 ( action === 'apply' || action === 'insert' )
170         ) {
171                 return new OO.ui.Process( function () {
172                         var deferred = $.Deferred();
173                         dialog.checkRequiredParameters().done( function () {
174                                 var item,
175                                         surfaceModel = dialog.getFragment().getSurface(),
176                                         doc = surfaceModel.getDocument(),
177                                         internalList = doc.getInternalList(),
178                                         obj = dialog.transclusionModel.getPlainObject();
179
180                                 if ( !dialog.referenceModel ) {
181                                         // Collapse returns a new fragment, so update dialog.fragment
182                                         dialog.fragment = dialog.getFragment().collapseToEnd();
183                                         dialog.referenceModel = new ve.dm.MWReferenceModel( doc );
184                                         dialog.referenceModel.insertInternalItem( surfaceModel );
185                                         dialog.referenceModel.insertReferenceNode( dialog.getFragment() );
186                                 }
187
188                                 item = dialog.referenceModel.findInternalItem( surfaceModel );
189                                 if ( item ) {
190                                         if ( dialog.selectedNode ) {
191                                                 dialog.transclusionModel.updateTransclusionNode(
192                                                         surfaceModel, dialog.selectedNode
193                                                 );
194                                         } else if ( obj !== null ) {
195                                                 dialog.transclusionModel.insertTransclusionNode(
196                                                         // HACK: This is trying to place the cursor inside the first content branch
197                                                         // node but this theoretically not a safe assumption - in practice, the
198                                                         // citation dialog will only reach this code if we are inserting (not
199                                                         // updating) a transclusion, so the referenceModel will have already
200                                                         // initialized the internal node with a paragraph - getting the range of the
201                                                         // item covers the entire paragraph so we have to get the range of it's
202                                                         // first (and empty) child
203                                                         dialog.getFragment().clone(
204                                                                 new ve.dm.LinearSelection( doc, item.getChildren()[ 0 ].getRange() )
205                                                         ),
206                                                         'inline'
207                                                 );
208                                         }
209                                 }
210
211                                 // HACK: Scorch the earth - this is only needed because without it, the references list
212                                 // won't re-render properly, and can be removed once someone fixes that
213                                 dialog.referenceModel.setDocument(
214                                         doc.cloneFromRange(
215                                                 internalList.getItemNode( dialog.referenceModel.getListIndex() ).getRange()
216                                         )
217                                 );
218                                 dialog.referenceModel.updateInternalItem( surfaceModel );
219
220                                 dialog.close( { action: action } );
221                         } ).always( deferred.resolve );
222
223                         return deferred;
224                 } );
225         }
226
227         // Parent method
228         return ve.ui.MWCitationDialog.super.prototype.getActionProcess.call( this, action );
229 };
230
231 /**
232  * @inheritdoc
233  */
234 ve.ui.MWCitationDialog.prototype.getTeardownProcess = function ( data ) {
235         return ve.ui.MWCitationDialog.super.prototype.getTeardownProcess.call( this, data )
236                 .first( function () {
237                         // Cleanup
238                         this.referenceModel = null;
239                         this.referenceNode = null;
240                 }, this );
241 };