Press n or j to go to the next uncovered block, b, p or k for the previous block.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 | 1x 6x 6x 6x 6x 6x 1x 1x 1x 1x 5x 5x 5x 5x 1x 1x 9024x 9024x 1504x 1504x 7520x 7605x 7602x 7517x 3x 3x 1x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 3x 1x 6x 1x 6x 1x | /*! * VisualEditor UserInterface Sequence class. * * @copyright See AUTHORS.txt */ /** * Key sequence. * * @class * * @constructor * @param {string} name Symbolic name * @param {string} commandName Command name this sequence executes * @param {string|Array|RegExp} data Data to match. String, linear data array, or regular expression. * When using a RegularExpression always match the end of the sequence with a '$' so that * only sequences next to the user's cursor match. * @param {number} [strip=0] Number of data elements to strip after execution * (from the right) * @param {Object} [config] [description] * @param {boolean} [config.setSelection=false] Whether to set the selection to the * range matching the sequence before executing the command. * @param {boolean} [config.delayed=false] Whether to wait for the user to stop typing matching content * before executing the command. When the sequence matches typed text, it will not be executed * immediately, but only after more non-matching text is added afterwards or the selection is * changed. This is useful for variable-length sequences (defined with RegExps). * @param {boolean} [config.checkOnPaste=false] Whether the sequence should also be matched after paste. * @param {boolean} [config.checkOnDelete=false] Whether the sequence should also be matched after delete. */ ve.ui.Sequence = function VeUiSequence( name, commandName, data, strip, config ) { this.name = name; this.commandName = commandName; this.data = data; this.strip = strip || 0; if ( typeof config === 'object' ) { // TODO: Add `config = config || {};` when variadic fallback is dropped. this.setSelection = !!config.setSelection; this.delayed = !!config.delayed; this.checkOnPaste = !!config.checkOnPaste; this.checkOnDelete = !!config.checkOnDelete; } else { // Backwards compatibility with variadic arguments this.setSelection = !!arguments[ 4 ]; this.delayed = !!arguments[ 5 ]; this.checkOnPaste = !!arguments[ 6 ]; this.checkOnDelete = !!arguments[ 7 ]; } }; /* Inheritance */ OO.initClass( ve.ui.Sequence ); /* Methods */ /** * Check if the sequence matches a given offset in the data * * @param {ve.dm.ElementLinearData} data String or linear data * @param {number} offset * @param {string} plaintext Plain text of data * @return {ve.Range|null} Range corresponding to the match, or else null */ ve.ui.Sequence.prototype.match = function ( data, offset, plaintext ) { let i, j = offset - 1; if ( this.data instanceof RegExp ) { i = plaintext.search( this.data ); return ( i < 0 ) ? null : new ve.Range( offset - plaintext.length + i, offset ); } for ( i = this.data.length - 1; i >= 0; i--, j-- ) { if ( typeof this.data[ i ] === 'string' ) { if ( this.data[ i ] !== data.getCharacterData( j ) ) { return null; } } else Iif ( !ve.compare( this.data[ i ], data.getData( j ), true ) ) { return null; } } return new ve.Range( offset - this.data.length, offset ); }; /** * Execute the command associated with the sequence * * @param {ve.ui.Surface} surface * @param {ve.Range} range Range to set * @return {boolean} The command executed */ ve.ui.Sequence.prototype.execute = function ( surface, range ) { const surfaceModel = surface.getModel(); Iif ( surface.getCommands().indexOf( this.getCommandName() ) === -1 ) { return false; } const command = surface.commandRegistry.lookup( this.getCommandName() ); Iif ( !command ) { return false; } let stripFragment; Eif ( this.strip ) { const stripRange = surfaceModel.getSelection().getRange(); stripFragment = surfaceModel.getLinearFragment( // noAutoSelect = true, excludeInsertions = true new ve.Range( stripRange.end, stripRange.end - this.strip ), true, true ); } surfaceModel.breakpoint(); // Use SurfaceFragment rather than Selection to automatically adjust the selection for any changes // (additions, removals) caused by executing the command const originalSelectionFragment = surfaceModel.getFragment(); Iif ( this.setSelection ) { surfaceModel.setLinearSelection( range ); } let args; // For sequences that trigger dialogs, pass an extra flag so the window knows // to un-strip the sequence if it is closed without action. See ve.ui.WindowAction. Iif ( command.getAction() === 'window' && command.getMethod() === 'open' ) { args = ve.copy( command.args ); args[ 1 ] = args[ 1 ] || {}; args[ 1 ].strippedSequence = !!this.strip; } Eif ( stripFragment ) { // Strip the typed text. This will be undone if the action triggered was // window/open and the window is dismissed stripFragment.removeContent(); } // `args` can be passed undefined, and the defaults will be used const executed = command.execute( surface, args, 'sequence' ); // Restore user's selection if: // * This sequence was not executed after all // * This sequence is delayed, so it only executes after the user changed the selection Iif ( !executed || this.delayed ) { originalSelectionFragment.select(); } Iif ( stripFragment && !executed ) { surfaceModel.undo(); // Prevent redoing (which would remove the typed text) surfaceModel.truncateUndoStack(); surfaceModel.emit( 'history' ); } return executed; }; /** * Get the symbolic name of the sequence * * @return {string} Symbolic name */ ve.ui.Sequence.prototype.getName = function () { return this.name; }; /** * Get the command name which the sequence will execute * * @return {string} Command name */ ve.ui.Sequence.prototype.getCommandName = function () { return this.commandName; }; /** * Get a representation of the sequence useful for display * * What this means depends a bit on how the sequence was defined: * - It strips out undisplayable things like the paragraph-start marker. * - Regexps are just returned as a toString of the regexp. * * @param {boolean} explode Whether to return the message split up into some * reasonable sequence of inputs required to trigger the sequence (regexps * in sequences will be considered a single "input" as a toString of * the regexp, because they're hard to display no matter what…) * @return {string} Message for display */ ve.ui.Sequence.prototype.getMessage = function ( explode ) { let data; if ( typeof this.data === 'string' ) { data = this.data.split( '' ); } else if ( this.data instanceof RegExp ) { data = [ this.data.toString() ]; } else { data = this.data.filter( ( key ) => !ve.isPlainObject( key ) ); } return explode ? data : data.join( '' ); }; |