%PDF- %PDF-
Direktori : /www/varak.net/wiki.varak.net/extensions/VisualEditor/lib/ve/src/ui/actions/ |
Current File : /www/varak.net/wiki.varak.net/extensions/VisualEditor/lib/ve/src/ui/actions/ve.ui.LinkAction.js |
/*! * VisualEditor UserInterface LinkAction class. * * @copyright 2011-2016 VisualEditor Team and others; see http://ve.mit-license.org */ /** * Link action. * This action transforms or inspects links (or potential links). * * @class * @extends ve.ui.Action * @constructor * @param {ve.ui.Surface} surface Surface to act on */ ve.ui.LinkAction = function VeUiLinkAction() { // Parent constructor ve.ui.LinkAction.super.apply( this, arguments ); }; /* Inheritance */ OO.inheritClass( ve.ui.LinkAction, ve.ui.Action ); /* Static Properties */ ve.ui.LinkAction.static.name = 'link'; /** * RegExp matching an autolink + trailing space. * @property {RegExp} * @private */ ve.ui.LinkAction.static.autolinkRegExp = null; // Initialized below. /** * List of allowed methods for the action. * * @static * @property */ ve.ui.LinkAction.static.methods = [ 'autolinkUrl' ]; /* Methods */ /** * Autolink the selected URL (which may have trailing whitespace). * * @method * @return {boolean} * True if the selection is a valid URL and the autolink action was * executed; otherwise false. */ ve.ui.LinkAction.prototype.autolinkUrl = function () { return this.autolink( function ( linktext ) { // Make sure we still have a real URL after trail removal, and not // a bare protocol (or no protocol at all, if we stripped the last // colon from the protocol) return ve.ui.LinkAction.static.autolinkRegExp.test( linktext + ' ' ); } ); }; /** * Autolink the selection, which may have trailing whitespace. * * @method * @private * @param {Function} validateFunc * A function used to validate the given linktext. * @param {string} validateFunc.linktext * Linktext with trailing whitespace and punctuation stripped. * @param {boolean} validateFunc.return * True iff the given linktext is valid. If false, no linking will be done. * @param {Function} [txFunc] * An optional function to create a transaction to perform the autolink. * If not provided, a transaction will be created which applies the * annotations returned by {@link ve.ui.LinkAction#getLinkAnnotation}. * @param {ve.dm.Document} txFunc.documentModel * The document model to modify. * @param {ve.Range} txFunc.range * The range to autolink. * @param {string} txFunc.linktext * The text string to autolink. * @param {ve.dm.Transaction} txFunc.return * The transaction to perform the autolink operation. * @return {boolean} Selection was valid and link action was executed. */ ve.ui.LinkAction.prototype.autolink = function ( validateFunc, txFunc ) { var range, rangeEnd, linktext, i, surfaceModel = this.surface.getModel(), documentModel = surfaceModel.getDocument(), selection = surfaceModel.getSelection(); function isLinkAnnotation( annotation ) { return /^link/.test( annotation.name ); } if ( !( selection instanceof ve.dm.LinearSelection ) ) { return false; } range = selection.getRange(); rangeEnd = range.end; linktext = documentModel.data.getText( true, range ); // Eliminate trailing whitespace. linktext = linktext.replace( /\s+$/, '' ); // Eliminate trailing punctuation. linktext = linktext.replace( this.getTrailingPunctuation( linktext ), '' ); // Validate the stripped text. if ( !validateFunc( linktext ) ) { // Don't autolink this. return false; } // Shrink range to match new linktext. range = range.truncate( linktext.length ); // Check that none of the range has an existing link annotation. // Otherwise we could autolink an internal link, which would be ungood. for ( i = range.start; i < range.end; i++ ) { if ( documentModel.data.getAnnotationsFromOffset( i ).containsMatching( isLinkAnnotation ) ) { // Don't autolink this. return false; } } // Make sure `undo` doesn't expose the selected linktext. surfaceModel.setLinearSelection( new ve.Range( rangeEnd ) ); // Annotate the (previous) range. if ( txFunc ) { // TODO: Change this API so that 'txFunc' is given a surface fragment // as an argument, and uses the fragment to directly edit the document. surfaceModel.change( txFunc( documentModel, range, linktext ) ); } else { surfaceModel.getLinearFragment( range, true ).annotateContent( 'set', this.getLinkAnnotation( linktext ) ); } return true; }; /** * Return an appropriate "trailing punctuation" set, which will * get stripped from possible autolinks. * * @param {string} candidate * The candidate text. Some users may not wish to include closing * brackets/braces/parentheses in the stripped character class if an * opening bracket/brace/parenthesis in present in the candidate link * text. * @return {RegExp} * A regular expression matching trailing punctuation which will be * stripped from an autolink. */ ve.ui.LinkAction.prototype.getTrailingPunctuation = function ( candidate ) { /* jshint unused: false */ return /[,;.:!?)\]\}"'”’»]+$/; }; /** * Return an appropriate annotation for the given link text. * * @method * @param {string} linktext The link text to annotate. * @return {ve.dm.LinkAnnotation} The annotation to use. */ ve.ui.LinkAction.prototype.getLinkAnnotation = function ( linktext ) { return new ve.dm.LinkAnnotation( { type: 'link', attributes: { href: linktext } } ); }; /* Registration */ ve.ui.actionFactory.register( ve.ui.LinkAction ); // Delayed initialization (wait until ve.init.platform exists) ve.init.Platform.static.initializedPromise.then( function () { ve.ui.LinkAction.static.autolinkRegExp = new RegExp( '\\b' + ve.init.platform.getUnanchoredExternalLinkUrlProtocolsRegExp().source + '\\S+(\\s|\\n+)$', 'i' ); ve.ui.sequenceRegistry.register( new ve.ui.Sequence( 'autolinkUrl', 'autolinkUrl', ve.ui.LinkAction.static.autolinkRegExp, 0, true ) ); } );