jenkins-bot has submitted this change and it was merged.
Change subject: Make link inspector re-usable by splitting it up
......................................................................
Make link inspector re-usable by splitting it up
Objective:
* Make the majority of link inspector, which is generic to any annotation,
usable for other annotation inspectors
This was merged earlier (f7107fa20dc0) but broke master, so it was
reverted (092fa74deef). This commit also incorporates 5dcf5d1c49082d.
Change-Id: Ib9190dee66ce064d69962f9c4c5b3a710be8ad07
---
M VisualEditor.php
M demos/ve/index.php
M modules/ve-mw/test/index.php
M modules/ve-mw/ui/inspectors/ve.ui.MWLinkInspector.js
M modules/ve/test/index.php
A modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js
M modules/ve/ui/inspectors/ve.ui.LinkInspector.js
7 files changed, 218 insertions(+), 164 deletions(-)
Approvals:
Catrope: Looks good to me, approved
jenkins-bot: Verified
diff --git a/VisualEditor.php b/VisualEditor.php
index ed239a6..d4011a5 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -534,6 +534,7 @@
've/ui/tools/dropdowns/ve.ui.FormatDropdownTool.js',
've-mw/ui/tools/dropdowns/ve.ui.MWFormatDropdownTool.js',
+ 've/ui/inspectors/ve.ui.AnnotationInspector.js',
've/ui/inspectors/ve.ui.LinkInspector.js',
've-mw/ui/inspectors/ve.ui.MWLinkInspector.js',
),
diff --git a/demos/ve/index.php b/demos/ve/index.php
index 85f023a..bb86b79 100644
--- a/demos/ve/index.php
+++ b/demos/ve/index.php
@@ -280,6 +280,7 @@
<script
src="../../modules/ve/ui/tools/buttons/ve.ui.RedoButtonTool.js"></script>
<script
src="../../modules/ve/ui/tools/buttons/ve.ui.UndoButtonTool.js"></script>
<script
src="../../modules/ve/ui/tools/dropdowns/ve.ui.FormatDropdownTool.js"></script>
+ <script
src="../../modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js"></script>
<script
src="../../modules/ve/ui/inspectors/ve.ui.LinkInspector.js"></script>
<!-- demo -->
diff --git a/modules/ve-mw/test/index.php b/modules/ve-mw/test/index.php
index 4d7f0c47..c30f562 100644
--- a/modules/ve-mw/test/index.php
+++ b/modules/ve-mw/test/index.php
@@ -280,6 +280,7 @@
<script
src="../../ve-mw/ui/tools/buttons/ve.ui.MWTransclusionButtonTool.js"></script>
<script
src="../../ve/ui/tools/dropdowns/ve.ui.FormatDropdownTool.js"></script>
<script
src="../../ve-mw/ui/tools/dropdowns/ve.ui.MWFormatDropdownTool.js"></script>
+ <script
src="../../ve/ui/inspectors/ve.ui.AnnotationInspector.js"></script>
<script
src="../../ve/ui/inspectors/ve.ui.LinkInspector.js"></script>
<script
src="../../ve-mw/ui/inspectors/ve.ui.MWLinkInspector.js"></script>
<!-- ext.visualEditor.experimental -->
diff --git a/modules/ve-mw/ui/inspectors/ve.ui.MWLinkInspector.js
b/modules/ve-mw/ui/inspectors/ve.ui.MWLinkInspector.js
index 8c9f524..945b347 100644
--- a/modules/ve-mw/ui/inspectors/ve.ui.MWLinkInspector.js
+++ b/modules/ve-mw/ui/inspectors/ve.ui.MWLinkInspector.js
@@ -45,7 +45,7 @@
* @param {string} target Link target
* @returns {ve.dm.MWInternalLinkAnnotation|ve.dm.MWExternalLinkAnnotation}
*/
-ve.ui.MWLinkInspector.prototype.getAnnotationFromTarget = function ( target ) {
+ve.ui.MWLinkInspector.prototype.getAnnotationFromText = function ( target ) {
var title;
// Figure out if this is an internal or external link
diff --git a/modules/ve/test/index.php b/modules/ve/test/index.php
index 9dbbaa2..5e5bfea 100644
--- a/modules/ve/test/index.php
+++ b/modules/ve/test/index.php
@@ -233,6 +233,7 @@
<script
src="../../ve/ui/tools/buttons/ve.ui.RedoButtonTool.js"></script>
<script
src="../../ve/ui/tools/buttons/ve.ui.UndoButtonTool.js"></script>
<script
src="../../ve/ui/tools/dropdowns/ve.ui.FormatDropdownTool.js"></script>
+ <script
src="../../ve/ui/inspectors/ve.ui.AnnotationInspector.js"></script>
<script
src="../../ve/ui/inspectors/ve.ui.LinkInspector.js"></script>
<!-- Load plugins for test framework -->
diff --git a/modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js
b/modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js
new file mode 100644
index 0000000..6ee0dc6
--- /dev/null
+++ b/modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js
@@ -0,0 +1,204 @@
+/*!
+ * VisualEditor UserInterface AnnotationInspector class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * Annotation inspector.
+ *
+ * @class
+ * @abstract
+ * @extends ve.ui.Inspector
+ *
+ * @constructor
+ * @param {ve.ui.Surface} surface
+ * @param {Object} [config] Config options
+ */
+ve.ui.AnnotationInspector = function VeUiAnnotationInspector( surface, config
) {
+ // Parent constructor
+ ve.ui.Inspector.call( this, surface, config );
+
+ // Properties
+ this.initialAnnotation = null;
+ this.initialAnnotationHash = null;
+ this.isNewAnnotation = false;
+};
+
+/* Inheritance */
+
+ve.inheritClass( ve.ui.AnnotationInspector, ve.ui.Inspector );
+
+/**
+ * Annotation models this inspector can edit.
+ *
+ * @static
+ * @inheritable
+ * @property {Function[]}
+ */
+ve.ui.AnnotationInspector.static.modelClasses = [];
+
+/* Methods */
+
+/**
+ * Handle the inspector being setup.
+ *
+ * There are 4 scenarios:
+ * - Zero-length selection not near a word -> no change, text will be inserted
on close
+ * - Zero-length selection inside or adjacent to a word -> expand selection to
cover word
+ * - Selection covering non-annotated text -> trim selection to remove
leading/trailing whitespace
+ * - Selection covering annotated text -> expand selection to cover annotation
+ *
+ * @method
+ */
+ve.ui.AnnotationInspector.prototype.onSetup = function () {
+ var expandedFragment, trimmedFragment, truncatedFragment,
+ fragment = this.surface.getModel().getFragment( null, true ),
+ annotation = this.getMatchingAnnotations( fragment, true ).get(
0 );
+
+ // Parent method
+ ve.ui.Inspector.prototype.onSetup.call( this );
+
+ // Initialize range
+ if ( !annotation ) {
+ if ( fragment.getRange().isCollapsed() ) {
+ // Expand to nearest word
+ expandedFragment = fragment.expandRange( 'word' );
+ fragment = expandedFragment;
+ } else {
+ // Trim whitespace
+ trimmedFragment = fragment.trimRange();
+ fragment = trimmedFragment;
+ }
+ if ( !fragment.getRange().isCollapsed() ) {
+ // Create annotation from selection
+ truncatedFragment = fragment.truncateRange( 255 );
+ fragment = truncatedFragment;
+ annotation = this.getAnnotationFromText(
fragment.getText() );
+ fragment.annotateContent( 'set', annotation );
+ this.isNewAnnotation = true;
+ }
+ } else {
+ // Expand range to cover annotation
+ expandedFragment = fragment.expandRange( 'annotation',
annotation );
+ fragment = expandedFragment;
+ }
+
+ // Update selection
+ fragment.select();
+};
+
+/**
+ * Handle the inspector being opened.
+ */
+ve.ui.AnnotationInspector.prototype.onOpen = function () {
+ var fragment = this.surface.getModel().getFragment( null, true ),
+ // Note that we don't set the 'all' flag here so that any
+ // non-annotated content is annotated on close
+ initialAnnotation = this.getMatchingAnnotations( fragment
).get( 0 );
+
+ // Parent method
+ ve.ui.Inspector.prototype.onOpen.call( this );
+
+ // Initialization
+ this.initialAnnotation = initialAnnotation;
+ this.initialAnnotationHash = initialAnnotation ? ve.getHash(
initialAnnotation ) : null;
+};
+
+/**
+ * Handle the inspector being closed.
+ *
+ * @param {string} action Action that caused the window to be closed
+ */
+ve.ui.AnnotationInspector.prototype.onClose = function ( action ) {
+ // Parent method
+ ve.ui.Inspector.prototype.onClose.call( this, action );
+
+ var i, len, annotations, selection,
+ insert = false,
+ undo = false,
+ clear = false,
+ set = false,
+ target = this.targetInput.getValue(),
+ annotation = this.targetInput.getAnnotation(),
+ remove = action === 'remove' && !!annotation,
+ fragment = this.surface.getModel().getFragment(
this.initialSelection, false );
+
+ if ( remove ) {
+ clear = true;
+ } else {
+ if ( this.initialSelection.isCollapsed() ) {
+ insert = true;
+ }
+ if ( ve.getHash( annotation ) !== this.initialAnnotationHash ) {
+ if ( this.isNewAnnotation ) {
+ undo = true;
+ } else {
+ clear = true;
+ }
+ set = true;
+ }
+ }
+ if ( insert ) {
+ fragment.insertContent( target, false );
+
+ // Move cursor to the end of the inserted content, even if back
button is used
+ this.previousSelection = new ve.Range(
this.initialSelection.start + target.length );
+ }
+ if ( undo ) {
+ // Go back to before we added an annotation
+ this.surface.execute( 'history', 'undo' );
+ }
+ if ( clear ) {
+ // Clear all existing annotations
+ annotations = this.getMatchingAnnotations( fragment, true
).get();
+ for ( i = 0, len = annotations.length; i < len; i++ ) {
+ fragment.annotateContent( 'clear', annotations[i] );
+ }
+ }
+ if ( set ) {
+ // Apply new annotation
+ fragment.annotateContent( 'set', annotation );
+ }
+ if ( action === 'back' ) {
+ selection = this.previousSelection;
+ }
+ // Selection changes may have occured in the insertion and annotation
hullabaloo - restore it
+ this.surface.execute(
+ 'content', 'select', selection || new ve.Range(
fragment.getRange().end )
+ );
+ // Reset state
+ this.isNewAnnotation = false;
+};
+
+/**
+ * Get an annotation object from text.
+ *
+ * @method
+ * @abstract
+ * @param {string} text Content text
+ * @returns {ve.dm.Annotation}
+ * @throws {Error} If not overriden in a subclass
+ */
+ve.ui.AnnotationInspector.prototype.getAnnotationFromText = function () {
+ throw new Error(
+ 've.ui.AnnotationInspector.getAnnotationFromText not
implemented in subclass'
+ );
+};
+
+/**
+ * Get matching annotations within a fragment.
+ *
+ * @method
+ * @param {ve.dm.SurfaceFragment} fragment Fragment to get matching
annotations within
+ * @param {boolean} [all] Get annotations which only cover some of the fragment
+ * @returns {ve.dm.AnnotationSet} Matching annotations
+ */
+ve.ui.AnnotationInspector.prototype.getMatchingAnnotations = function (
fragment, all ) {
+ var modelClasses = this.constructor.static.modelClasses;
+
+ return fragment.getAnnotations( all ).filter( function ( annnotation ) {
+ return ve.isInstanceOfAny( annnotation, modelClasses );
+ } );
+};
diff --git a/modules/ve/ui/inspectors/ve.ui.LinkInspector.js
b/modules/ve/ui/inspectors/ve.ui.LinkInspector.js
index ef28386..6c8298c 100644
--- a/modules/ve/ui/inspectors/ve.ui.LinkInspector.js
+++ b/modules/ve/ui/inspectors/ve.ui.LinkInspector.js
@@ -9,7 +9,7 @@
* Link inspector.
*
* @class
- * @extends ve.ui.Inspector
+ * @extends ve.ui.AnnotationInspector
*
* @constructor
* @param {ve.ui.Surface} surface
@@ -17,16 +17,12 @@
*/
ve.ui.LinkInspector = function VeUiLinkInspector( surface, config ) {
// Parent constructor
- ve.ui.Inspector.call( this, surface, config );
-
- // Properties
- this.initialAnnotationHash = null;
- this.isNewAnnotation = false;
+ ve.ui.AnnotationInspector.call( this, surface, config );
};
/* Inheritance */
-ve.inheritClass( ve.ui.LinkInspector, ve.ui.Inspector );
+ve.inheritClass( ve.ui.LinkInspector, ve.ui.AnnotationInspector );
/* Static properties */
@@ -53,7 +49,7 @@
*/
ve.ui.LinkInspector.prototype.initialize = function () {
// Parent method
- ve.ui.Inspector.prototype.initialize.call( this );
+ ve.ui.AnnotationInspector.prototype.initialize.call( this );
// Properties
this.targetInput = new this.constructor.static.linkTargetInputWidget( {
@@ -65,66 +61,11 @@
};
/**
- * Handle the inspector being setup.
- *
- * There are 4 scenarios:
- * * Zero-length selection not near a word -> no change, text will be
inserted on close
- * * Zero-length selection inside or adjacent to a word -> expand
selection to cover word
- * * Selection covering non-link text -> trim selection to remove
leading/trailing whitespace
- * * Selection covering link text -> expand selection to cover link
- *
- * @method
- */
-ve.ui.LinkInspector.prototype.onSetup = function () {
- var expandedFragment, trimmedFragment, truncatedFragment,
- fragment = this.surface.getModel().getFragment( null, true ),
- annotation = this.getMatchingAnnotations( fragment, true ).get(
0 );
-
- // Parent method
- ve.ui.Inspector.prototype.onSetup.call( this );
-
- // Initialize range
- if ( !annotation ) {
- if ( fragment.getRange().isCollapsed() ) {
- // Expand to nearest word
- expandedFragment = fragment.expandRange( 'word' );
- fragment = expandedFragment;
- } else {
- // Trim whitespace
- trimmedFragment = fragment.trimRange();
- fragment = trimmedFragment;
- }
- if ( !fragment.getRange().isCollapsed() ) {
- // Create annotation from selection
- truncatedFragment = fragment.truncateRange( 255 );
- fragment = truncatedFragment;
- annotation = this.getAnnotationFromTarget(
fragment.getText() );
- fragment.annotateContent( 'set', annotation );
- this.isNewAnnotation = true;
- }
- } else {
- // Expand range to cover annotation
- expandedFragment = fragment.expandRange( 'annotation',
annotation );
- fragment = expandedFragment;
- }
-
- // Update selection
- fragment.select();
-};
-
-/**
* Handle the inspector being opened.
*/
ve.ui.LinkInspector.prototype.onOpen = function () {
- var fragment = this.surface.getModel().getFragment( null, true ),
- annotation = this.getMatchingAnnotations( fragment, true ).get(
0 ),
- // Note that we don't set the 'all' flag here so that any
- // non-annotated content is annotated on close
- initialAnnotation = this.getMatchingAnnotations( fragment
).get( 0 );
-
-
// Parent method
- ve.ui.Inspector.prototype.onOpen.call( this );
+ ve.ui.AnnotationInspector.prototype.onOpen.call( this );
// Wait for animation to complete
this.surface.disable();
@@ -132,112 +73,17 @@
// Note: Focus input prior to setting target annotation
this.targetInput.$input.focus();
// Setup annotation
- this.initialAnnotationHash = initialAnnotation && ve.getHash(
initialAnnotation );
- this.targetInput.setAnnotation( annotation );
+ this.targetInput.setAnnotation( this.initialAnnotation );
this.targetInput.$input.select();
this.surface.enable();
}, this ), 200 );
};
/**
- * Handle the inspector being closed.
- *
- * @param {string} action Action that caused the window to be closed
+ * @inheritdoc
*/
-ve.ui.LinkInspector.prototype.onClose = function ( action ) {
- // Parent method
- ve.ui.Inspector.prototype.onClose.call( this, action );
-
- var i, len, annotations, selection,
- insert = false,
- undo = false,
- clear = false,
- set = false,
- remove = action === 'remove',
- target = this.targetInput.getValue(),
- annotation = this.targetInput.getAnnotation(),
- fragment = this.surface.getModel().getFragment(
this.initialSelection, false );
- // Undefined annotation causes removal
- if ( !annotation ) {
- remove = true;
- }
- if ( remove ) {
- clear = true;
- } else {
- if ( this.initialSelection.isCollapsed() ) {
- insert = true;
- }
- if ( ve.getHash( annotation ) !== this.initialAnnotationHash ) {
- if ( this.isNewAnnotation ) {
- undo = true;
- } else {
- clear = true;
- }
- set = true;
- }
- }
- if ( insert ) {
- fragment.insertContent( target, false );
-
- // Move cursor to the end of the inserted content, even if back
button is used
- this.previousSelection = new ve.Range(
this.initialSelection.start + target.length );
- }
- if ( undo ) {
- // Go back to before we added an annotation
- this.surface.execute( 'history', 'undo' );
- }
- if ( clear ) {
- // Clear all existing annotations
- annotations = this.getMatchingAnnotations( fragment, true
).get();
- for ( i = 0, len = annotations.length; i < len; i++ ) {
- fragment.annotateContent( 'clear', annotations[i] );
- }
- }
- if ( set ) {
- // Apply new annotation
- fragment.annotateContent( 'set', annotation );
- }
- if ( action === 'back' ) {
- selection = this.previousSelection;
- }
- // Selection changes may have occured in the insertion and annotation
hullabaloo - restore it
- this.surface.execute(
- 'content', 'select', selection || new ve.Range(
fragment.getRange().end )
- );
- // Reset state
- this.isNewAnnotation = false;
-};
-
-/**
- * Get an annotation object from a target.
- *
- * @method
- * @param {string} target Link target
- * @returns {ve.dm.LinkAnnotation}
- */
-ve.ui.LinkInspector.prototype.getAnnotationFromTarget = function ( target ) {
- return new ve.dm.LinkAnnotation( {
- 'type': 'link',
- 'attributes': {
- 'href': target
- }
- } );
-};
-
-/**
- * Get matching annotations within a fragment.
- *
- * @method
- * @param {ve.dm.SurfaceFragment} fragment Fragment to get matching
annotations within
- * @param {boolean} [all] Get annotations which only cover some of the fragment
- * @returns {ve.dm.AnnotationSet} Matching annotations
- */
-ve.ui.LinkInspector.prototype.getMatchingAnnotations = function ( fragment,
all ) {
- var modelClasses = this.constructor.static.modelClasses;
-
- return fragment.getAnnotations( all ).filter( function ( annnotation ) {
- return ve.isInstanceOfAny( annnotation, modelClasses );
- } );
+ve.ui.LinkInspector.prototype.getAnnotationFromText = function ( text ) {
+ return new ve.dm.LinkAnnotation( { 'type': 'link', 'attributes': {
'href': text } } );
};
/* Registration */
--
To view, visit https://gerrit.wikimedia.org/r/71958
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: Ib9190dee66ce064d69962f9c4c5b3a710be8ad07
Gerrit-PatchSet: 13
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Catrope <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Mooeypoo <[email protected]>
Gerrit-Reviewer: Trevor Parscal <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits