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