Trevor Parscal has uploaded a new change for review.

  https://gerrit.wikimedia.org/r/71919


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

Change-Id: I1f7e9c13537105da7aa0351c9c92e8af5eb5a3f4
---
M VisualEditor.php
M demos/ve/index.php
M modules/ve-mw/test/index.php
M modules/ve/test/index.php
A modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js
M modules/ve/ui/inspectors/ve.ui.LinkInspector.js
6 files changed, 218 insertions(+), 163 deletions(-)


  git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/VisualEditor 
refs/changes/19/71919/1

diff --git a/VisualEditor.php b/VisualEditor.php
index 738a7f4..d63bc28 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -522,6 +522,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 d9863cc..1f9509f 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/test/index.php b/modules/ve/test/index.php
index 2c35588..f602f52 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..453af86
--- /dev/null
+++ b/modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js
@@ -0,0 +1,205 @@
+/*!
+ * 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
+ * @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
+ * @property {Function[]}
+ */
+ve.ui.AnnotationInspector.static.modelClasses = [ ve.dm.Annotation ];
+
+/* 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 );
+};
+
+/**
+ * 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,
+               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 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 4ac30f6..4151558 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,175 +61,25 @@
 };
 
 /**
- * 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
        setTimeout( ve.bind( function () {
                // Setup annotation
-               this.initialAnnotationHash = initialAnnotation && ve.getHash( 
initialAnnotation );
-               this.targetInput.setAnnotation( annotation );
+               this.targetInput.setAnnotation( this.initialAnnotation );
                this.targetInput.$input.focus().select();
        }, 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/71919
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: I1f7e9c13537105da7aa0351c9c92e8af5eb5a3f4
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Trevor Parscal <[email protected]>

_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits

Reply via email to