MarkTraceur has uploaded a new change for review.

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

Change subject: Refactor into a class, make editing easier
......................................................................

Refactor into a class, make editing easier

This was largely so we didn't have two separate code paths for editing
annotations (creation/editing existing), and now it's finally set. This
should make extending this code much easier.

Change-Id: If1386afb2a14882b9e8fd15e328fcaff953b3421
---
M resources/src/fileannotations.js
M resources/src/fileannotations.less
2 files changed, 268 insertions(+), 203 deletions(-)


  git pull 
ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/FileAnnotations 
refs/changes/96/300296/1

diff --git a/resources/src/fileannotations.js b/resources/src/fileannotations.js
index c6d9c66..2c3cfd4 100644
--- a/resources/src/fileannotations.js
+++ b/resources/src/fileannotations.js
@@ -1,19 +1,137 @@
 ( function ( $, mw ) {
-       var createButton, $annotationsContainer, $mainImage,
-               annotationsCache, offset, $annotationInfo,
-               api = new mw.Api(),
-               pageTitle = mw.Title.newFromText( mw.config.get( 'wgPageName' ) 
),
-               annotationsTitle = mw.Title.newFromText( 'File_Annotations:' + 
pageTitle.getMain() ),
+       var pageTitle = mw.Title.newFromText( mw.config.get( 'wgPageName' ) ),
                isFilePage = pageTitle.getNamespaceId() === 6,
                $fileLink = $( '#file' );
 
-       function getAnnotationsJSON( pageTitle ) {
-               return api.get( {
+       /**
+        * Class for rendering, editing, creating and deleting annotations on a 
file.
+        *
+        * @class mw.FileAnnotator
+        * @constructor
+        * @param {jQuery} $fileLink Look for '#file' on the file page.
+        * @param {mw.Title} fileTitle Title of the file.
+        */
+       function FileAnnotator( $fileLink, fileTitle ) {
+               var offset, $annotationInfo, createButton,
+                       annotator = this;
+
+               this.api = new mw.Api();
+
+               this.$fileLink = $fileLink;
+               this.fileTitle = fileTitle;
+               this.$img = $fileLink.find( 'img' );
+
+               $annotationInfo = $( '<div>' )
+                       .addClass( 'fileannotation-info' )
+                       .append(
+                               $( '<p>' ).text( mw.message( 
'file-has-annotations' ).text() )
+                       );
+
+               $fileLink.after( $annotationInfo );
+
+               this.$container = $( '<div>' )
+                       .addClass( 'annotation-wrapper' );
+
+               offset = this.$img.offset();
+
+               this.$container.css( {
+                       top: offset.top,
+                       left: offset.left,
+                       width: this.$img.width(),
+                       height: this.$img.height()
+               } );
+
+               $( 'body' ).append( this.$container );
+
+               this.annotationsTitle = mw.Title.newFromText( 
'File_Annotations:' + fileTitle.getMain() );
+
+               this.getAndRenderAnnotations();
+
+               this.getAnnotationsHTML().then( function ( data ) {
+                       var pageId = data.query.pageids[ 0 ],
+                               page = data.query.pages[ pageId ],
+                               imageInfo = page.imageinfo[ 0 ],
+                               fullw = imageInfo.width,
+                               fullh = imageInfo.height,
+                               imgw = annotator.$img.width(),
+                               imgh = annotator.$img.height(),
+                               adjustRatioX = imgw / fullw,
+                               adjustRatioY = imgh / fullh;
+
+                       // Make it possible to create new annotations 
graphically.
+                       createButton = new OO.ui.ButtonWidget( {
+                               label: mw.message( 'fileannotation-create' 
).text(),
+                               icon: 'add',
+                               flags: [ 'constructive' ]
+                       } );
+
+                       createButton.on( 'click', function () {
+                               if ( annotator.$container.hasClass( 
'click-to-create' ) ) {
+                                       // Don't turn it on twice!
+                                       return;
+                               }
+
+                               // Turn on click-to-initiate...
+                               annotator.$container
+                                       .addClass( 'click-to-create' );
+
+                               annotator.$container
+                                       .one( 'click', function ( e ) {
+                                               // Add outline and edit 
interface
+                                               var x = e.offsetX,
+                                                       y = e.offsetY,
+                                                       // We want the 
annotation to default to at least 40 pixels,
+                                                       // or 1/20th of the 
size of the image, unless the image is less than 40
+                                                       // pixels in which case 
we'll just select the whole thing.
+                                                       defaultHeight = 
Math.min( Math.max( 40, fullh / 20 ), fullh ),
+                                                       defaultWidth = 
Math.min( Math.max( 40, fullw / 20 ), fullw ),
+                                                       adjustedDefaultDim = 
Math.min(
+                                                               defaultHeight * 
adjustRatioY,
+                                                               defaultWidth * 
adjustRatioX
+                                                       );
+
+                                               
annotator.$container.removeClass( 'click-to-create' );
+
+                                               
annotator.createAnnotationEditor( x, y, adjustedDefaultDim, adjustedDefaultDim )
+                                                       .then( function ( newX, 
newY, newWidth, newHeight, newText ) {
+                                                               
annotator.getAnnotationsJSON().then( function ( annotations ) {
+                                                                       
annotations.annotations.push( {
+                                                                               
content: newText,
+                                                                               
x: newX / adjustRatioX,
+                                                                               
y: newY / adjustRatioY,
+                                                                               
width: newWidth / adjustRatioX,
+                                                                               
height: newHeight / adjustRatioY
+                                                                       } );
+
+                                                                       return 
annotator.saveAnnotations(
+                                                                               
annotations,
+                                                                               
'Added a file annotation from the file page, text: "' + newText + '"'
+                                                                       );
+                                                               } ).then( 
function () {
+                                                                       // 
Close interface, make the annotation official.
+                                                                       
annotator.annotationsCache = undefined;
+                                                                       
annotator.getAndRenderAnnotations();
+                                                               } );
+                                                       } );
+                                       } );
+                       } );
+
+                       $annotationInfo.append( createButton.$element );
+               } );
+       }
+
+       /**
+        * Get JSON data for the annotations on the page, suitable for editing.
+        *
+        * @return {jQuery.Promise}
+        */
+       FileAnnotator.prototype.getAnnotationsJSON = function () {
+               return this.api.get( {
                        action: 'query',
                        prop: 'revisions',
                        rvprop: 'content',
                        indexpageids: true,
-                       titles: pageTitle.getPrefixedDb()
+                       titles: this.annotationsTitle.getPrefixedDb()
                } ).then( function ( data ) {
                        var rv, text, annotations,
                                pages = data.query.pages,
@@ -34,12 +152,19 @@
 
                        return annotations;
                } );
-       }
+       };
 
-       function saveUpdatedAnnotations( annotations, pageTitle, summary ) {
-               return api.postWithToken( 'csrf', {
+       /**
+        * Save the annotations to the server.
+        *
+        * @param {Object} annotations A valid JavaScript object adhering to 
the annotations schema.
+        * @param {string} summary The edit summary.
+        * @return {jQuery.Promise}
+        */
+       FileAnnotator.prototype.saveAnnotations = function ( annotations, 
summary ) {
+               return this.api.postWithToken( 'csrf', {
                        action: 'edit',
-                       title: pageTitle.getPrefixedDb(),
+                       title: this.annotationsTitle.getPrefixedDb(),
                        text: JSON.stringify( annotations ),
                        summary: summary
                } );
@@ -51,29 +176,25 @@
         *
         * @return {jQuery.Promise}
         */
-       function getAnnotationsHTML( imageTitle ) {
-               if ( annotationsCache === undefined ) {
-                       if ( !isFilePage ) {
-                               annotationsCache = $.Deferred().reject( 'Not a 
file page, aborting request for annotations' );
-                       } else {
-                               annotationsCache = api.get( {
-                                       action: 'query',
-                                       indexpageids: true,
-                                       prop: [ 'fileannotations', 'imageinfo' 
],
-                                       titles: imageTitle.getPrefixedDb(),
-                                       faparse: true,
-                                       iiprop: 'size'
-                               } ).then( function ( data ) {
-                                       if ( data.error ) {
-                                               return $.Deferred().reject( 
data.error );
-                                       }
+       FileAnnotator.prototype.getAnnotationsHTML = function () {
+               if ( this.annotationsCache === undefined ) {
+                       this.annotationsCache = this.api.get( {
+                               action: 'query',
+                               indexpageids: true,
+                               prop: [ 'fileannotations', 'imageinfo' ],
+                               titles: this.fileTitle.getPrefixedDb(),
+                               faparse: true,
+                               iiprop: 'size'
+                       } ).then( function ( data ) {
+                               if ( data.error ) {
+                                       return $.Deferred().reject( data.error 
);
+                               }
 
-                                       return data;
-                               } );
-                       }
+                               return data;
+                       } );
                }
 
-               return annotationsCache;
+               return this.annotationsCache;
        }
 
        /**
@@ -81,9 +202,9 @@
         *
         * @param {jQuery} $container Where to put the editor interface.
         * @param {string} text The wikitext of the annotation.
-        * @return {jQuery.promise} Resolved with the new text if annotation is 
saved, rejected if annotation is discarded.
+        * @return {jQuery.Promise} Resolved with the new text if annotation is 
saved, rejected if annotation is discarded.
         */
-       function createAnnotationTextEditor( $container, text ) {
+       FileAnnotator.prototype.createAnnotationTextEditor = function ( 
$container, text ) {
                var deferred = $.Deferred(),
                        $annotationEditor = $( '<div>' )
                                .addClass( 'annotation-editor' ),
@@ -135,6 +256,78 @@
        }
 
        /**
+        * Create an editing interface for an annotation, including text editor
+        * and graphical location/size editor.
+        *
+        * @param {number} x
+        * @param {number} y
+        * @param {number} width
+        * @param {number} height
+        * @param {string} [text] If the annotation already exists, this is the 
wikitext.
+        * @param {jQuery} [$existing] If the annotation already exists, this 
is the rendered box.
+        * @return {jQuery.Promise}
+        */
+       FileAnnotator.prototype.createAnnotationEditor = function ( x, y, 
width, height, text, $existing ) {
+               var $box, $contain;
+
+               this.$container.addClass( 'editing-annotations' );
+
+               if ( $existing ) {
+                       $box = $existing;
+                       $box.addClass( 'editing-annotation' );
+                       $contain = $box.find( '.annotation-container' );
+               } else {
+                       $box = $( '<div>' )
+                               .addClass( 'new-annotation' )
+                               .css( {
+                                       top: y,
+                                       left: x,
+                                       width: width,
+                                       height: height
+                               } );
+
+                       this.$container.append( $box );
+
+                       // For a new annotation, the box is the container.
+                       $contain = $box;
+               }
+
+               $box.draggable( {
+                       containment: 'parent'
+               } );
+
+               $box.resizable( {
+                       containment: 'parent'
+               } );
+
+               return annotator.createAnnotationTextEditor( $contain, text 
).then( function ( newText ) {
+                       var newY = parseInt( $box.css( 'top' ), 10 ),
+                               newX = parseInt( $box.css( 'left' ), 10 ),
+                               newWidth = parseInt( $box.css( 'width' ), 10 ),
+                               newHeight = parseInt( $box.css( 'height' ), 10 
);
+
+                       return $.Deferred().resolve( newX, newY, newWidth, 
newHeight, newText );
+               }, function () {
+                       annotator.$container.removeClass( 'editing-annotations' 
);
+
+                       if ( $existing ) {
+                               $box.removeClass( 'editing-annotation' );
+                               $box.resizable( 'destroy' );
+                               $box.draggable( 'destroy' );
+
+                               $box.css( {
+                                       top: y,
+                                       left: x,
+                                       height: height,
+                                       width: width
+                               } );
+                       } else {
+                               $box.remove();
+                       }
+               } );
+       };
+
+       /**
         * Render an annotation, and the edit interface.
         *
         * @param {number} i Which number this annotation is in the list.
@@ -150,8 +343,9 @@
         * @param {number} adjustRatioY Same as above, but for the Y axis.
         * @return {jQuery} The annotation box to be added to the container.
         */
-       function renderAnnotation( i, annotation, imageInfo, adjustRatioX, 
adjustRatioY ) {
-               var $annotation = $( '<div>' )
+       FileAnnotator.prototype.renderAnnotation = function ( i, annotation, 
imageInfo, adjustRatioX, adjustRatioY ) {
+               var annotator = this,
+                       $annotation = $( '<div>' )
                                .addClass( 'file-annotation' )
                                .append( annotation.parsed ),
                        adjustedX = annotation.x * adjustRatioX,
@@ -195,59 +389,44 @@
                                currentWidth = $annotationBox.css( 'width' ),
                                currentHeight = $annotationBox.css( 'height' );
 
-                       // Create edit interface and link things up
-                       $annotationBox.addClass( 'editing-annotation' );
-                       $annotationsContainer.addClass( 'editing-annotations' );
-
-                       $annotationBox.draggable( {
-                               containment: 'parent'
-                       } );
-
-                       $annotationBox.resizable( {
-                               containment: 'parent'
-                       } );
-
-                       createAnnotationTextEditor( $annotationContain, 
annotation.text ).then( function ( newText ) {
-                               var newY = parseInt( $annotationBox.css( 'top' 
), 10 ),
-                                       newX = parseInt( $annotationBox.css( 
'left' ), 10 ),
-                                       newWidth = parseInt( 
$annotationBox.css( 'width' ), 10 ),
-                                       newHeight = parseInt( 
$annotationBox.css( 'height' ), 10 );
-
-                               getAnnotationsJSON( annotationsTitle ).then( 
function ( annotations ) {
+                       annotator.createAnnotationEditor(
+                               currentX,
+                               currentY,
+                               currentWidth,
+                               currentHeight,
+                               annotation.text,
+                               $annotationBox
+                       ).then( function ( newX, newY, newWidth, newHeight, 
newText ) {
+                               annotator.getAnnotationsJSON().then( function ( 
annotations ) {
                                        annotations.annotations[ i ].content = 
newText;
                                        annotations.annotations[ i ].x = newX / 
adjustRatioX;
                                        annotations.annotations[ i ].y = newY / 
adjustRatioY;
                                        annotations.annotations[ i ].width = 
newWidth / adjustRatioX;
                                        annotations.annotations[ i ].height = 
newHeight / adjustRatioY;
 
-                                       saveUpdatedAnnotations( annotations, 
annotationsTitle, 'Edited annotation on file page. New text: "' + newText + '"' 
).then( function () {
+                                       annotator.saveAnnotations(
+                                               annotations,
+                                               'Edited annotation on file 
page. New text: "' + newText + '"'
+                                       ).then( function () {
                                                // Close edit interface, make 
the annotation official.
-                                               annotationsCache = undefined;
-                                               getAndRenderAnnotations( 
pageTitle, $annotationsContainer, $mainImage );
+                                               annotator.annotationsCache = 
undefined;
+                                               
annotator.getAndRenderAnnotations();
                                        } );
-                               } );
-                       }, function () {
-                               $annotationBox.removeClass( 
'editing-annotation' );
-                               $annotationBox.resizable( 'destroy' );
-                               $annotationBox.draggable( 'destroy' );
-
-                               $annotationBox.css( {
-                                       top: currentY,
-                                       left: currentX,
-                                       height: currentHeight,
-                                       width: currentWidth
                                } );
                        } );
                } );
 
                deleteButton.on( 'click', function () {
                        // Delete the annotation and refresh.
-                       getAnnotationsJSON( annotationsTitle ).then( function ( 
annotations ) {
+                       annotator.getAnnotationsJSON().then( function ( 
annotations ) {
                                annotations.annotations.splice( i, 1 );
-                               saveUpdatedAnnotations( annotations, 
annotationsTitle, 'Deleted annotation on file page.' ).then( function () {
+                               annotator.saveAnnotations(
+                                       annotations,
+                                       'Deleted annotation on file page.'
+                               ).then( function () {
                                        // Close edit interface, make the 
annotation official.
-                                       annotationsCache = undefined;
-                                       getAndRenderAnnotations( pageTitle, 
$annotationsContainer, $mainImage );
+                                       annotator.annotationsCache = undefined;
+                                       annotator.getAndRenderAnnotations();
                                } );
                        } );
                } );
@@ -266,8 +445,13 @@
                return $annotationBox;
        }
 
-       function getAndRenderAnnotations( imageTitle, $container, $img ) {
-               getAnnotationsHTML( imageTitle )
+       /**
+        * Get the annotations, and render them on the image.
+        */
+       FileAnnotator.prototype.getAndRenderAnnotations = function () {
+               var annotator = this;
+
+               this.getAnnotationsHTML( this.fileTitle )
                        .then( function ( data ) {
                                var i,
                                        pageId = data.query.pageids[ 0 ],
@@ -276,145 +460,25 @@
                                        annotations = page.fileannotations[ 0 ],
                                        fullw = imageInfo.width,
                                        fullh = imageInfo.height,
-                                       imgw = $img.width(),
-                                       imgh = $img.height(),
+                                       imgw = annotator.$img.width(),
+                                       imgh = annotator.$img.height(),
                                        adjustRatioX = imgw / fullw,
                                        adjustRatioY = imgh / fullh;
 
                                // Clear any existing annotations so we start 
fresh.
-                               $container.empty();
+                               annotator.$container.empty();
 
                                for ( i = 0; i < annotations.length; i++ ) {
-                                       $container.append(
-                                               renderAnnotation( i, 
annotations[ i ], imageInfo, adjustRatioX, adjustRatioY )
+                                       annotator.$container.append(
+                                               annotator.renderAnnotation( i, 
annotations[ i ], imageInfo, adjustRatioX, adjustRatioY )
                                        );
                                }
                        } );
        }
 
        if ( isFilePage ) {
-               $mainImage = $fileLink.find( 'img' );
-
-               $annotationInfo = $( '<div>' )
-                       .addClass( 'fileannotation-info' )
-                       .append(
-                               $( '<p>' ).text( mw.message( 
'file-has-annotations' ).text() )
-                       );
-
-               $fileLink.after( $annotationInfo );
-
-               $annotationsContainer = $( '<div>' )
-                       .addClass( 'annotation-wrapper' );
-
-               offset = $mainImage.offset();
-
-               $annotationsContainer.css( {
-                       top: offset.top,
-                       left: offset.left,
-                       width: $mainImage.width(),
-                       height: $mainImage.height()
-               } );
-
-               $( 'body' ).append( $annotationsContainer );
-
-               getAndRenderAnnotations( pageTitle, $annotationsContainer, 
$mainImage );
-
-               getAnnotationsHTML( pageTitle )
-                       .then( function ( data ) {
-                               var pageId = data.query.pageids[ 0 ],
-                                       page = data.query.pages[ pageId ],
-                                       imageInfo = page.imageinfo[ 0 ],
-                                       fullw = imageInfo.width,
-                                       fullh = imageInfo.height,
-                                       imgw = $mainImage.width(),
-                                       imgh = $mainImage.height(),
-                                       adjustRatioX = imgw / fullw,
-                                       adjustRatioY = imgh / fullh;
-
-                               // Make it possible to create new annotations 
graphically.
-                               createButton = new OO.ui.ButtonWidget( {
-                                       label: mw.message( 
'fileannotation-create' ).text(),
-                                       icon: 'add',
-                                       flags: [ 'constructive' ]
-                               } );
-
-                               createButton.on( 'click', function () {
-                                       if ( $annotationsContainer.hasClass( 
'click-to-create' ) ) {
-                                               // Don't turn it on twice!
-                                               return;
-                                       }
-
-                                       // Turn on click-to-initiate...
-                                       $annotationsContainer
-                                               .addClass( 'click-to-create' );
-
-                                       $annotationsContainer
-                                               .one( 'click', function ( e ) {
-                                                       // Add outline and edit 
interface
-                                                       var x = e.offsetX,
-                                                               y = e.offsetY,
-                                                               // We want the 
annotation to default to at least 40 pixels,
-                                                               // or 1/20th of 
the size of the image, unless the image is less than 40
-                                                               // pixels in 
which case we'll just select the whole thing.
-                                                               defaultHeight = 
Math.min( Math.max( 40, fullh / 20 ), fullh ),
-                                                               defaultWidth = 
Math.min( Math.max( 40, fullw / 20 ), fullw ),
-                                                               
adjustedDefaultDim = Math.min(
-                                                                       
defaultHeight * adjustRatioY,
-                                                                       
defaultWidth * adjustRatioX
-                                                               ),
-
-                                                               $newBox = $( 
'<div>' )
-                                                                       
.addClass( 'new-annotation' )
-                                                                       .css( {
-                                                                               
top: y,
-                                                                               
left: x,
-                                                                               
width: adjustedDefaultDim,
-                                                                               
height: adjustedDefaultDim
-                                                                       } );
-
-                                                       $newBox.draggable( {
-                                                               containment: 
'parent'
-                                                       } );
-                                                       $newBox.resizable( {
-                                                               containment: 
'parent'
-                                                       } );
-
-                                                       
$annotationsContainer.append( $newBox );
-
-                                                       
$annotationsContainer.removeClass( 'click-to-create' );
-
-                                                       
createAnnotationTextEditor( $newBox )
-                                                               .fail( function 
() {
-                                                                       
$newBox.remove();
-                                                               } ).done( 
function ( newText ) {
-                                                                       var 
newY = parseInt( $newBox.css( 'top' ), 10 ),
-                                                                               
newX = parseInt( $newBox.css( 'left' ), 10 ),
-                                                                               
newWidth = parseInt( $newBox.css( 'width' ), 10 ),
-                                                                               
newHeight = parseInt( $newBox.css( 'height' ), 10 );
-
-                                                                       
getAnnotationsJSON( annotationsTitle ).then( function ( annotations ) {
-                                                                               
annotations.annotations.push( {
-                                                                               
        content: newText,
-                                                                               
        x: newX / adjustRatioX,
-                                                                               
        y: newY / adjustRatioY,
-                                                                               
        width: newWidth / adjustRatioX,
-                                                                               
        height: newHeight / adjustRatioY
-                                                                               
} );
-
-                                                                               
return saveUpdatedAnnotations(
-                                                                               
        annotations, annotationsTitle,
-                                                                               
        'Added a file annotation from the file page, text: "' + newText + '"'
-                                                                               
);
-                                                                       } 
).then( function () {
-                                                                               
// Close interface, make the annotation official.
-                                                                               
annotationsCache = undefined;
-                                                                               
getAndRenderAnnotations( pageTitle, $annotationsContainer, $mainImage );
-                                                                       } );
-                                                               } );
-                                               } );
-                               } );
-
-                               $annotationInfo.append( createButton.$element );
-                       } );
+               annotator = new FileAnnotator( $fileLink, pageTitle );
        }
+
+       mw.FileAnnotator = FileAnnotator;
 }( jQuery, mediaWiki ) );
diff --git a/resources/src/fileannotations.less 
b/resources/src/fileannotations.less
index 7521660..dba0884 100644
--- a/resources/src/fileannotations.less
+++ b/resources/src/fileannotations.less
@@ -19,6 +19,7 @@
                        border: 1px dotted green;
                        .annotation-container {
                                display: block;
+                               .file-annotation,
                                .annotation-edit-buttons {
                                        display: none;
                                }

-- 
To view, visit https://gerrit.wikimedia.org/r/300296
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings

Gerrit-MessageType: newchange
Gerrit-Change-Id: If1386afb2a14882b9e8fd15e328fcaff953b3421
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/FileAnnotations
Gerrit-Branch: master
Gerrit-Owner: MarkTraceur <[email protected]>

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

Reply via email to