jenkins-bot has submitted this change and it was merged. Change subject: Pull a bunch of code into separate classes ......................................................................
Pull a bunch of code into separate classes This was necessary to make error messages make any kind of sense. Hopefully nobody wanted to base code on the previous HEAD, because this basically breaks any possibility for rebasing. Change-Id: Iebd437708e5fcfc6c1bb125b2c5825af3f9e3556 --- M extension.json A resources/src/FileAnnotation.js A resources/src/FileAnnotationEditor.js M resources/src/FileAnnotator.js 4 files changed, 523 insertions(+), 277 deletions(-) Approvals: Bartosz Dziewoński: Looks good to me, approved jenkins-bot: Verified diff --git a/extension.json b/extension.json index 0e703bf..96cba07 100644 --- a/extension.json +++ b/extension.json @@ -56,6 +56,7 @@ "resources/src/FileAnnotator.less" ], "dependencies": [ + "ext.fileannotations.FileAnnotation", "mediawiki.Title", "jquery.ui.draggable", "jquery.ui.resizable", @@ -69,6 +70,29 @@ "fileannotations-delete", "fileannotations-commons-see-more" ] + }, + "ext.fileannotations.FileAnnotation": { + "scripts": [ + "resources/src/FileAnnotation.js" + ], + "styles": [ + ], + "dependencies": [ + "ext.fileannotations.FileAnnotationEditor", + "oojs-ui" + ] + }, + "ext.fileannotations.FileAnnotationEditor": { + "scripts": [ + "resources/src/FileAnnotationEditor.js" + ], + "styles": [ + ], + "dependencies": [ + "jquery.ui.draggable", + "jquery.ui.resizable", + "oojs-ui" + ] } }, "ResourceFileModulePaths": { diff --git a/resources/src/FileAnnotation.js b/resources/src/FileAnnotation.js new file mode 100644 index 0000000..790495f --- /dev/null +++ b/resources/src/FileAnnotation.js @@ -0,0 +1,261 @@ +( function ( mw, $, OO ) { + /** + * Single annotation's interface. + * + * @class mw.FileAnnotation + * @mixins OO.EventEmitter + * @constructor + * @param {Object} config + * @cfg {Object} annotation Information including x, y, width, height, index, etc. + * @cfg {Object} file Information including title, sizes, etc. + * @cfg {Object} display Information about the current display of the file - height, width. + * @cfg {jQuery} $container If this is a new annotation, this is where the edit interface is put. + * @cfg {boolean} editing Whether editing is enabled. + */ + function FileAnnotation( config ) { + OO.EventEmitter.call( this ); + + this.api = config.api; + + this.index = config.annotation.index; + + this.x = config.annotation.x; + this.y = config.annotation.y; + this.width = config.annotation.width; + this.height = config.annotation.height; + + this.text = config.annotation.text; + this.parsed = config.annotation.parsed; + + this.fileTitle = config.file.title; + this.annotationsTitle = mw.Title.newFromText( 'File annotations:' + this.fileTitle.getMain() ); + this.fileWidth = config.file.width; + this.fileHeight = config.file.height; + + this.displayWidth = config.display.width; + this.displayHeight = config.display.height; + + this.adjustRatioX = this.displayWidth / this.fileWidth; + this.adjustRatioY = this.displayHeight / this.fileHeight; + + this.adjustedX = this.x * this.adjustRatioX; + this.adjustedY = this.y * this.adjustRatioY; + this.adjustedWidth = this.width * this.adjustRatioX; + this.adjustedHeight = this.height * this.adjustRatioY; + + this.editing = config.editing; + + if ( this.text && this.parsed ) { + this.$annotation = $( '<div>' ) + .addClass( 'file-annotation' ) + .append( this.parsed ); + + this.$annotation.find( '.commons-category-annotation .commons-see-more' ) + .msg( 'fileannotations-commons-see-more' ); + + this.$contain = $( '<div>' ) + .addClass( 'annotation-container' ); + + this.$box = $( '<div>' ) + .addClass( 'annotation-box' ) + .append( this.$contain ) + .css( { + top: this.adjustedY, + left: this.adjustedX, + width: this.adjustedWidth, + height: this.adjustedHeight + } ); + + this.$contain.css( { + top: this.adjustedHeight - 10, + left: this.adjustedWidth - 10 + } ); + + this.$contain.append( this.$annotation ); + + if ( config.editing ) { + this.addEditInterface(); + } + } else { + // New annotation. Create the edit interface immediately. + this.$container = config.$container; + this.createEditor(); + } + } + + OO.mixinClass( FileAnnotation, OO.EventEmitter ); + + /** + * Adds an "edit" and "delete" button to the annotation for inline + * edits. + */ + FileAnnotation.prototype.addEditInterface = function () { + var annotation = this; + + this.editButton = new OO.ui.ButtonWidget( { + label: mw.message( 'fileannotations-edit' ).text(), + flags: [ 'progressive' ] + } ); + + this.deleteButton = new OO.ui.ButtonWidget( { + label: mw.message( 'fileannotations-delete' ).text(), + flags: [ 'destructive' ] + } ); + + this.modifyButtons = new OO.ui.ButtonGroupWidget( { + items: [ this.editButton, this.deleteButton ] + } ); + + this.buttonsField = new OO.ui.FieldLayout( this.modifyButtons, { + classes: [ 'annotation-edit-buttons' ], + align: 'right' + } ); + + this.editButton.on( 'click', function () { + annotation.createEditor(); + } ); + + this.deleteButton.on( 'click', function () { + annotation.deleteAnnotation().then( function () { + annotation.emit( 'refresh-all' ); + } ); + } ); + + this.$contain.append( this.buttonsField.$element ); + }; + + /** + * Creates the annotation editor interface. + */ + FileAnnotation.prototype.createEditor = function () { + var annotation = this; + + this.emit( 'start-edit' ); + + this.editInterface = new mw.FileAnnotationEditor( { + annotation: { + text: this.text, + x: this.x, + y: this.y, + width: this.width, + height: this.height + }, + + $existing: this.$box, + $container: this.$container + } ); + + this.editInterface.on( 'save', function ( newAnn ) { + // Need to adapt some of the values, because the editor doesn't know + // about the original picture size. + newAnn.x = newAnn.x / annotation.adjustRatioX; + newAnn.y = newAnn.y / annotation.adjustRatioY; + newAnn.width = newAnn.width / annotation.adjustRatioX; + newAnn.height = newAnn.height / annotation.adjustRatioY; + + annotation.saveChanges( newAnn ).then( function () { + annotation.emit( 'refresh-all' ); + } ); + } ); + + this.editInterface.on( 'cancel-edit', function () { + annotation.emit( 'cancel-edit' ); + } ); + }; + + /** + * Get JSON data for the annotations on the page, suitable for editing. + * + * @return {jQuery.Promise} + */ + FileAnnotation.prototype.getPageJSON = function () { + return this.api.get( { + action: 'query', + prop: 'revisions', + rvprop: 'content', + formatversion: 2, + format: 'json', + titles: this.annotationsTitle.getPrefixedText() + } ).then( function ( data ) { + var rv, text, annotations, + pages = data.query.pages, + page = pages[ 0 ], + revisions = page.revisions; + + if ( revisions ) { + rv = revisions[ 0 ]; + text = rv.content; + annotations = JSON.parse( text ); + } else { + // Fake it, give the rest of the code an empty list + annotations = { + annotations: [] + }; + } + + return annotations; + } ); + }; + + /** + * 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} + */ + FileAnnotation.prototype.saveText = function ( annotations, summary ) { + return this.api.postWithToken( 'csrf', { + action: 'edit', + title: this.annotationsTitle.getPrefixedText(), + text: JSON.stringify( annotations ), + summary: summary + } ); + }; + + FileAnnotation.prototype.saveChanges = function ( newAnn ) { + var annotation = this; + + return this.getPageJSON().then( function ( annotations ) { + var summary, + newAnnotation = { + content: newAnn.text, + x: newAnn.x, + y: newAnn.y, + width: newAnn.width, + height: newAnn.height + }; + + if ( annotation.index ) { + annotations.annotations[ annotation.index ] = newAnnotation; + summary = 'Edited annotation on file page. New text: "' + newAnn.text + '"'; + } else { + annotations.annotations.push( newAnnotation ); + summary = 'Added annotation on file page. Text: "' + newAnn.text + '"'; + } + + return annotation.saveText( + annotations, + summary + ); + } ); + }; + + /** + * Deletes the annotation and saves. + */ + FileAnnotation.prototype.deleteAnnotation = function () { + var annotation = this; + + return this.getPageJSON().then( function ( annotations ) { + annotations.annotations.splice( annotation.index, 1 ); + + return annotation.saveText( + annotations, + 'Deleted annotation on file page.' + ); + } ); + }; + + mw.FileAnnotation = FileAnnotation; +}( mediaWiki, jQuery, OO ) ); diff --git a/resources/src/FileAnnotationEditor.js b/resources/src/FileAnnotationEditor.js new file mode 100644 index 0000000..4a161dd --- /dev/null +++ b/resources/src/FileAnnotationEditor.js @@ -0,0 +1,151 @@ +( function ( mw, $, OO ) { + /** + * Editing interface for a single annotation. + * + * @class mw.FileAnnotationEditor + * @mixins OO.EventEmitter + * @constructor + * @param {Object} config + * @cfg {Object} annotation Including x, y, width, height, and text. + * @cfg {jQuery} $existing The existing annotation box, if any. + * @cfg {jQuery} $container If this is a new annotation, the container to put it in. + */ + function FileAnnotationEditor( config ) { + var $box, $contain, + editor = this; + + OO.EventEmitter.call( this ); + + if ( config.$existing ) { + $box = config.$existing; + $box.addClass( 'editing-annotation' ); + $contain = $box.find( '.annotation-container' ); + } else { + $box = $( '<div>' ) + .addClass( 'new-annotation' ) + .css( { + top: config.annotation.y, + left: config.annotation.x, + width: config.annotation.width, + height: config.annotation.height + } ); + + // For a new annotation, the box is the container. + $contain = $box; + + config.$container.append( $box ); + } + + this.$box = $box; + this.$contain = $contain; + + $box.draggable( { + containment: 'parent' + } ); + + $box.resizable( { + containment: 'parent' + } ); + + this.createTextEditor( $contain, config.annotation.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 ); + + editor.emit( 'save', { + x: newX, + y: newY, + width: newWidth, + height: newHeight, + text: newText + } ); + }, function () { + editor.emit( 'cancel-edit' ); + + if ( config.$existing ) { + $box.removeClass( 'editing-annotation' ); + $box.resizable( 'destroy' ); + $box.draggable( 'destroy' ); + + $box.css( { + top: config.y, + left: config.x, + height: config.height, + width: config.width + } ); + } else { + $box.remove(); + } + } ); + } + + OO.mixinClass( FileAnnotationEditor, OO.EventEmitter ); + + /** + * Creates an interface for editing an annotation. + * + * @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. + */ + FileAnnotationEditor.prototype.createTextEditor = function ( $container, text ) { + var deferred = $.Deferred(), + editor = this; + + this.$editor = $( '<div>' ) + .addClass( 'annotation-editor' ); + + this.textWidget = new OO.ui.TextInputWidget( { + multiline: true + } ); + + this.saveButton = new OO.ui.ButtonWidget( { + label: mw.message( 'fileannotations-save' ).text(), + icon: 'check', + flags: [ 'constructive', 'primary' ] + } ); + + this.cancelButton = new OO.ui.ButtonWidget( { + label: mw.message( 'fileannotations-cancel' ).text(), + icon: 'cancel', + flags: [ 'safe' ] + } ); + + this.buttons = new OO.ui.ButtonGroupWidget( { + items: [ this.cancelButton, this.saveButton ] + } ); + + this.buttonsField = new OO.ui.FieldLayout( this.buttons, { + align: 'right' + } ); + + if ( text ) { + this.textWidget.setValue( text ); + } + + this.$editor.append( + this.textWidget.$element, + this.buttonsField.$element + ); + + $container.append( this.$editor ); + + this.$editor.css( { + left: '-' + ( this.$editor.outerWidth() + 15 ) + 'px' + } ); + + this.cancelButton.once( 'click', function () { + editor.$editor.remove(); + deferred.reject(); + } ); + + this.saveButton.once( 'click', function () { + deferred.resolve( editor.textWidget.getValue() ); + } ); + + return deferred.promise(); + }; + + mw.FileAnnotationEditor = FileAnnotationEditor; +}( mediaWiki, jQuery, OO ) ); diff --git a/resources/src/FileAnnotator.js b/resources/src/FileAnnotator.js index b471ae3..519cb09 100644 --- a/resources/src/FileAnnotator.js +++ b/resources/src/FileAnnotator.js @@ -15,6 +15,9 @@ this.api = new mw.Api(); + this.editInterfaces = 0; + this.annotations = []; + this.$fileLink = config.$infoContainer; this.fileTitle = config.title; this.$img = this.$fileLink.find( 'img' ); @@ -96,31 +99,47 @@ adjustedDefaultDim = Math.min( defaultHeight * adjustRatioY, defaultWidth * adjustRatioX - ); + ), + newAnnotation = new mw.FileAnnotation( { + api: annotator.api, + $container: annotator.$container, + + annotation: { + x: x, + y: y, + width: adjustedDefaultDim, + height: adjustedDefaultDim + }, + + file: { + title: annotator.fileTitle, + width: fullw, + height: fullh + }, + + display: { + width: imgw, + height: imgh + } + } ); + + newAnnotation.on( 'refresh-all', function () { + annotator.annotationsCache = undefined; + annotator.getAndRenderAnnotations(); + } ); + + newAnnotation.on( 'start-edit', function () { + annotator.editInterfaces++; + annotator.$container.addClass( 'editing-annotations' ); + } ); + + newAnnotation.on( 'cancel-edit', function () { + if ( --annotator.editInterfaces === 0 ) { + annotator.$container.addClass( 'editing-annotations' ); + } + } ); 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(); - } ); - } ); // Dont want to click and open the image e.preventDefault(); @@ -211,261 +230,55 @@ }; /** - * Creates an interface for editing an annotation. - * - * @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. - */ - FileAnnotator.prototype.createAnnotationTextEditor = function ( $container, text ) { - var deferred = $.Deferred(), - $annotationEditor = $( '<div>' ) - .addClass( 'annotation-editor' ), - annotationText = new OO.ui.TextInputWidget( { - multiline: true - } ), - annotationSave = new OO.ui.ButtonWidget( { - label: mw.message( 'fileannotations-save' ).text(), - icon: 'check', - flags: [ 'constructive', 'primary' ] - } ), - annotationCancel = new OO.ui.ButtonWidget( { - label: mw.message( 'fileannotations-cancel' ).text(), - icon: 'cancel', - flags: [ 'safe' ] - } ), - annotationButtons = new OO.ui.ButtonGroupWidget( { - items: [ annotationCancel, annotationSave ] - } ), - buttonsField = new OO.ui.FieldLayout( annotationButtons, { - align: 'right' - } ); - - if ( text ) { - annotationText.setValue( text ); - } - - $annotationEditor.append( - annotationText.$element, - buttonsField.$element - ); - - $container.append( $annotationEditor ); - - $annotationEditor.css( { - left: '-' + ( $annotationEditor.outerWidth() + 15 ) + 'px' - } ); - - annotationCancel.once( 'click', function () { - $annotationEditor.remove(); - deferred.reject(); - } ); - - annotationSave.once( 'click', function () { - deferred.resolve( annotationText.getValue() ); - } ); - - return deferred.promise(); - }; - - /** - * 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, - annotator = this; - - 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. - * @param {Object} annotation - * @param {string} annotation.parsed The HTML value of the annotation. - * @param {string} annotation.content The wikitext of the annotation. - * @param {number} annotation.x The X coordinate for the annotation's location on the image. - * @param {number} annotation.y The Y coordinate. - * @param {number} annotation.width The width of the annotation box. - * @param {number} annotation.height The height of the annotation box. + * @param {Object} annotationInfo + * @param {string} annotationInfo.parsed The HTML value of the annotation. + * @param {string} annotationInfo.content The wikitext of the annotation. + * @param {number} annotationInfo.x The X coordinate for the annotation's location on the image. + * @param {number} annotationInfo.y The Y coordinate. + * @param {number} annotationInfo.width The width of the annotation box. + * @param {number} annotationInfo.height The height of the annotation box. + * @param {number} annotationInfo.index Which number this annotation is in the list. * @param {Object} imageInfo See MW API documentation. - * @param {number} adjustRatioX By how much the thumbnail of the image is distorted from the full image size. - * @param {number} adjustRatioY Same as above, but for the Y axis. * @return {jQuery} The annotation box to be added to the container. */ - FileAnnotator.prototype.renderAnnotation = function ( i, annotation, imageInfo, adjustRatioX, adjustRatioY ) { - var editButton, deleteButton, modifyButtons, buttonsField, - annotator = this, - $annotation = $( '<div>' ) - .addClass( 'file-annotation' ) - .append( annotation.parsed ), - adjustedX = annotation.x * adjustRatioX, - adjustedY = annotation.y * adjustRatioY, - adjustedWidth = annotation.width * adjustRatioX, - adjustedHeight = annotation.height * adjustRatioY, - - $annotationBox = $( '<div>' ) - .addClass( 'annotation-box' ) - .css( { - top: adjustedY, - left: adjustedX, - width: adjustedWidth, - height: adjustedHeight - } ), - $annotationContain = $( '<div>' ) - .addClass( 'annotation-container' ); - - $annotationContain.append( - $annotation - ); - - $( '.commons-category-annotation .commons-see-more' ) - .msg( 'fileannotations-commons-see-more' ); - - if ( this.editing ) { - editButton = new OO.ui.ButtonWidget( { - label: mw.message( 'fileannotations-edit' ).text(), - flags: [ 'progressive' ] + FileAnnotator.prototype.renderAnnotation = function ( annotationInfo, imageInfo ) { + var annotator = this, + annotation = new mw.FileAnnotation( { + editing: this.editing, + api: this.api, + annotation: annotationInfo, + file: { + title: this.fileTitle, + width: imageInfo.width, + height: imageInfo.height + }, + display: { + width: this.$img.width(), + height: this.$img.height() + } } ); - deleteButton = new OO.ui.ButtonWidget( { - label: mw.message( 'fileannotations-delete' ).text(), - flags: [ 'destructive' ] - } ); - - modifyButtons = new OO.ui.ButtonGroupWidget( { - items: [ editButton, deleteButton ] - } ); - - buttonsField = new OO.ui.FieldLayout( modifyButtons, { - classes: [ 'annotation-edit-buttons' ], - align: 'right' - } ); - - editButton.on( 'click', function () { - var currentX = $annotationBox.css( 'left' ), - currentY = $annotationBox.css( 'top' ), - currentWidth = $annotationBox.css( 'width' ), - currentHeight = $annotationBox.css( 'height' ); - - 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; - - annotator.saveAnnotations( - annotations, - 'Edited annotation on file page. New text: "' + newText + '"' - ).then( function () { - // Close edit interface, make the annotation official. - annotator.annotationsCache = undefined; - annotator.getAndRenderAnnotations(); - } ); - } ); - } ); - } ); - - deleteButton.on( 'click', function () { - // Delete the annotation and refresh. - annotator.getAnnotationsJSON().then( function ( annotations ) { - annotations.annotations.splice( i, 1 ); - annotator.saveAnnotations( - annotations, - 'Deleted annotation on file page.' - ).then( function () { - // Close edit interface, make the annotation official. - annotator.annotationsCache = undefined; - annotator.getAndRenderAnnotations(); - } ); - } ); - } ); - - $annotationContain.append( - buttonsField.$element - ); - } - - $annotationBox.append( $annotationContain ); - $annotationContain.css( { - top: adjustedHeight - 10, - left: adjustedWidth - 10 + annotation.on( 'refresh-all', function () { + annotator.annotationsCache = undefined; + annotator.getAndRenderAnnotations(); } ); - return $annotationBox; + annotation.on( 'start-edit', function () { + annotator.editInterfaces++; + annotator.$container.addClass( 'editing-annotations' ); + } ); + + annotation.on( 'cancel-edit', function () { + if ( --annotator.editInterfaces === 0 ) { + annotator.$container.addClass( 'editing-annotations' ); + } + } ); + + this.annotations.push( annotation ); + + return annotation.$box; }; /** @@ -476,18 +289,14 @@ FileAnnotator.prototype.getAndRenderAnnotations = function () { var annotator = this; + this.annotations = []; + return this.getAnnotationsHTML( this.fileTitle ) .then( function ( data ) { var i, page = data.query.pages[ 0 ], imageInfo = page.imageinfo[ 0 ], - annotations = page.fileannotations[ 0 ], - fullw = imageInfo.width, - fullh = imageInfo.height, - imgw = annotator.$img.width(), - imgh = annotator.$img.height(), - adjustRatioX = imgw / fullw, - adjustRatioY = imgh / fullh; + annotations = page.fileannotations[ 0 ]; // Clear any existing annotations so we start fresh. annotator.$container.empty(); @@ -499,8 +308,9 @@ ); for ( i = 0; i < annotations.length; i++ ) { + annotations[ i ].index = i; annotator.$container.append( - annotator.renderAnnotation( i, annotations[ i ], imageInfo, adjustRatioX, adjustRatioY ) + annotator.renderAnnotation( annotations[ i ], imageInfo ) ); } -- To view, visit https://gerrit.wikimedia.org/r/311616 To unsubscribe, visit https://gerrit.wikimedia.org/r/settings Gerrit-MessageType: merged Gerrit-Change-Id: Iebd437708e5fcfc6c1bb125b2c5825af3f9e3556 Gerrit-PatchSet: 6 Gerrit-Project: mediawiki/extensions/FileAnnotations Gerrit-Branch: master Gerrit-Owner: MarkTraceur <mholmqu...@wikimedia.org> Gerrit-Reviewer: Bartosz Dziewoński <matma....@gmail.com> Gerrit-Reviewer: jenkins-bot <> _______________________________________________ MediaWiki-commits mailing list MediaWiki-commits@lists.wikimedia.org https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits