MediaWiki:Gadget-ImageAnnotator.js: Difference between revisions
Content deleted Content added
Stricten a few comparisions |
More code cleanup; remove unused variables, use mw.config.get |
||
Line 3:
/*
ImageAnnotator v3.0.0
Requires an environment running MediaWiki 1.23 or later.
Image annotations. Draw rectangles onto image thumbnail displayed on image description
Line 21 ⟶ 23:
See http://commons.wikimedia.org/wiki/Help:Gadget-ImageAnnotator for documentation.
*/
/*jshint undef:true, unused:true, browser:true, eqnull:true, laxbreak:true, laxcomma:true */▼
/*global prompt */ // discouraged browser globals
/*global wgServer, wgScript, wgScriptPath, wgArticlePath, wgContentLanguage */ // legacy config site globals
/*global wgUserGroups, wgNamespaceNumber, wgRestrictionEdit */ // legacy config page globals
/*global mw, $ */
/*global LAPI, Buttons, Tooltip, Tooltips, TextCleaner, UIElements */ // imported scripts
/*global ImageAnnotator:true, ImageAnnotator_disable:false */ // this script
▲// Global: importScript, importScriptURI (wikibits.js)
if (typeof ImageAnnotator === 'undefined') {
▲/*jshint eqnull:true, laxbreak:true, laxcomma:true */
▲if (typeof ImageAnnotator === 'undefined') { // Guard against multiple inclusions
importScript('MediaWiki:LAPI.js');
Line 35 ⟶ 40:
importScript('MediaWiki:UIElements.js');
var conf = mw.config.get([
'skin',
'stylepath',
'wgNamespaceIds',
'wgCurRevisionId',
'wgTitle',
'wgArticleId',
'wgUserLanguage'
]);
var ImageAnnotator_config = null;
var ImageAnnotation = function () {
this.initialize.apply(this, arguments); }; ImageAnnotation.compare = function (a, b) {
var result = b.area() - a.area();
if (result !== 0) return result;
return a.model.id - b.model.id;
};
ImageAnnotation.prototype = {
view: null,
▲ view : null, // Rectangle to be displayed on image: a div with pos and size
// Tooltip to display the annotation // Content of the tooltip // Reference to the viewer this note belongs to viewer: null,
initialize
var is_new = false;
var view_w = 0, view_h = 0, view_x = 0, view_y = 0;
Line 73 ⟶ 91:
var html = IA.getRawItem('content_' + id, viewer.scope);
if (x === null || y === null || w === null || h === null || html === null)
throw new Error
if (x < 0 || x >= viewer.full_img.width || y < 0 || y >= viewer.full_img.height)
throw new Error
if ( x + w > viewer.full_img.width + 10
|| y + h > viewer.full_img.height + 10
Line 170 ⟶ 188:
},
setTooltip
if (this.tooltip || !this.view) return; // Already set, or corrupt
// Note: on IE, don't have tooltips appear automatically. IE doesn't do it right for transparent
// targets and we have to show and hide them ourselves through a mousemove listener in the viewer
// anyway. The occasional event that IE sends to the tooltip may then lead to ugly flickering.
this.tooltip = new Tooltip(
, { activate : (LAPI.DOM.is_ie ? Tooltip.NONE : Tooltip.HOVER)▼
,open_delay : 0▼
hide_delay:
onclose: (function (tooltip, evt) { } if (this.viewer.tip == tooltip) this.viewer.tip =
▲ // Hide all boxes if we're outside the image. Relies on hide checking the
▲ // coordinates! (Otherwise, we'd always hide...)
▲ if (evt) this.viewer.hide(evt);
▲ }).bind(this)
this.view.style.border = '1px solid ' +
} catch (ex)
this.view.style.border = '1px solid ' + }▼
this.viewer.tip =
▲ , IA.tooltip_styles
▲ );
},
display
if (!this.content) {
this.content = LAPI.make('div');
Line 223 ⟶ 242:
this.content.appendChild(LAPI.make('div', null, { clear: 'both' }));
if (this.viewer.may_edit) {
this.content.button_section = LAPI.make(
this.content.appendChild(this.content.button_section);
this.content.button_section.appendChild(LAPI.DOM.makeLink(
▲ );
if (ImageAnnotator_config.mayDelete()) {
this.content.button_section.appendChild(document.createTextNode('\xa0'));
this.content.button_section.appendChild(LAPI.DOM.makeLink(
▲ )
▲ );
}
}
Line 256 ⟶ 272:
},
edit
if (IA.canEdit()) IA.editor.editNote(this);
if (evt) return LAPI.Evt.kill(evt);
Line 262 ⟶ 278:
},
remove_event
if (IA.canEdit()) this.remove();
return LAPI.Evt.kill(evt);
},
remove
if (!this.content) { // New note: just destroy it.
this.destroy();
Line 296 ⟶ 312:
if (this.tooltip) this.tooltip.size_change();
LAPI.Ajax.editPage(
conf.wgPageName
, function (doc, editForm, failureFunc, revision_id) {
try {
if (revision_id && revision_id != conf.wgCurRevisionId)
throw new Error
var textbox = editForm.wpTextbox1;
if (!textbox) throw new Error
var pagetext = textbox.value.replace(/\r\n/g, '\n');
// Normalize different end-of-line handling. Opera and IE may use \r\n, whereas other
Line 338 ⟶ 354:
);
} catch (ex) {
failure
return;
}
Line 345 ⟶ 361:
editForm
, function (request) {
if (edit_page.isFake &&
edit_page.dispose();
var revision_id = LAPI.WP.revisionFromHtml(request.responseText);
if (!revision_id) {
failureFunc
return;
}
conf.wgCurRevisionId = revision_id; // Bump revision id!!
LAPI.Ajax.removeSpinner(spinnerId);
if (self.tooltip) self.tooltip.size_change();
Line 358 ⟶ 374:
}
, function (request, ex) {
if (edit_page.isFake &&
edit_page.dispose();
failureFunc
}
);
}
, function (
// Failure. What now? TODO: Implement some kind of user feedback.
LAPI.Ajax.removeSpinner(spinnerId);
Line 488 ⟶ 504:
this.visible = false;
LAPI.Evt.listenTo(this, this.tooltip.popup, IA.mouse_in,
function (
Array.forEach(IA.viewers, (function (viewer) {
if (viewer != this.viewer && viewer.visible) viewer.hide();
Line 515 ⟶ 531:
// Existing note, and we don't have the wikitext yet: go get it
var self = this;
LAPI.Ajax.apiGet('query',
}
}
// TODO: What upon a failure?▼
self.open_editor(same_note, cover);▼
▲ }
▲ , function (request) {
// TODO: What upon a failure?▼
self.open_editor(same_note, cover);▼
}
function () {
}
);
} else {
Line 691 ⟶ 707:
this.editor.enable(0); // Disable all buttons
this.saving = true;
LAPI.Ajax.editPage(conf.wgPageName,
▲ wgPageName
▲ , function (doc, editForm, failureFunc, revision_id) {
try {
if (revision_id && revision_id != conf.wgCurRevisionId)
// Page was edited since the user loaded it.
throw new Error('#Page version (revision ID) mismatch: edit conflict.');
Line 756 ⟶ 771:
}
} catch (ex) {
failureFunc
return;
}
var edit_page = doc;
LAPI.Ajax.submitEdit(editForm, function (request) {
▲ , function (request) {
// After a successful submit.
if (edit_page.isFake && (typeof edit_page.dispose === 'function'))
Line 775 ⟶ 788:
if (doc.isFake && (typeof doc.dispose === 'function')) doc.dispose();
failureFunc
(request, new Error
return;
}
Line 782 ⟶ 795:
if (doc.isFake && (typeof doc.dispose === 'function')) doc.dispose();
failureFunc
(request, new Error
return;
}
conf.wgCurRevisionId = revision_id; // Bump revision id!!
self.note.model.html = LAPI.DOM.importNode(document, html, true);
if (doc.isFake && (typeof doc.dispose === 'function')) doc.dispose();
Line 812 ⟶ 825:
IA.is_editing = false;
self.editor.setText(data); // In case the same note is re-opened: start new undo cycle
edit_page.dispose();
);
self.editor.busy(false);
self.saving = false;
Line 833 ⟶ 846:
if (lk && lk.length && lk[0].firstChild.nodeName.toLowerCase() === 'a') {
lk = lk[0].firstChild;
lk.href = wgServer + wgArticlePath.replace('$1', encodeURIComponent(conf.wgPageName)) + '?action=edit';
}
if (ex) {
Line 851 ⟶ 864:
self.editor.textarea.style.backgroundColor = '#EEEEEE';
self.editor.enable(LAPI.Edit.CANCEL); // Disable all other buttons
);
},
onpreview : function (
if (this.tooltip) this.tooltip.size_change();
},
Line 1,215 ⟶ 1,228:
},
show : function (
if (this.visible || this.icon) return;
this.toggle(IA.is_adding || IA.is_editing);
Line 1,303 ⟶ 1,316:
},
check_hide
if (this.icon) return true;
if (this.visible)
Line 1,310 ⟶ 1,323:
},
register
this.annotations[this.annotations.length] = new_note;
if (new_note.model.id > 0) {
Line 1,319 ⟶ 1,332:
},
deregister
Array.remove(this.annotations, note);
if (note.model.id == this.max_id) this.max_id--;
Line 1,325 ⟶ 1,338:
},
setDefaultMsg
if (this.annotations && this.annotations.length && this.msg) {
LAPI.DOM.removeChildren(this.msg);
Line 1,451 ⟶ 1,464:
// We'll include self.haveAjax later on once more, to catch the !ajaxQueried case.
self.may_edit = wgNamespaceNumber >= 0 && conf.wgArticleId > 0 && self.haveAjax && config.editingEnabled();
function namespaceCheck (list) {
if (!list || !$.isArray(list)) return false;
for (var i = 0; i < list.length; i++) {
if (conf.wgNamespaceIds
&& typeof list[i] === 'string'
&& (list[i] === '*'
|| conf.wgNamespaceIds[list[i].toLowerCase().replace(/ /g, '_')] === wgNamespaceNumber
)
)
Line 1,715 ⟶ 1,728:
var img = null;
if (scope == document) {
img = LAPI.WP.getPreviewImage(conf.wgTitle);
// TIFFs may be multi-paged: allow only for single-page TIFFs
if ( document.pageselector ) img = null;
Line 1,736 ⟶ 1,749:
var name = null;
if (scope == document) {
name = conf.wgPageName;
} else {
name = LAPI.WP.pageFromLink(img.parentNode);
Line 1,865 ⟶ 1,878:
}
var
while (to_do > 0) {
params = build_titles (start, Math.min(50, to_do), url_limit);
Line 2,035 ⟶ 2,049:
result = self.repo[id];
} else {
result = UIElements.getEntry(id, self.repo, conf.wgUserLanguage, null);
add_plea = !result;
if (!result) result = UIElements.getEntry(id, self.repo);
Line 2,066 ⟶ 2,080:
wgServer + wgScript + '?title=MediaWiki_talk:ImageAnnotatorTexts'
+ '&action=edit§ion=new&withJS=MediaWiki:ImageAnnotatorTranslator.js'
+ '&language=' + conf.wgUserLanguage
, translate
, (typeof translate === 'string' ? translate : LAPI.DOM.getInnerText(translate).trim())
Line 2,107 ⟶ 2,121:
var ui_page = '{{MediaWiki:ImageAnnotatorTexts'
+ (conf.wgUserLanguage != wgContentLanguage ? '|lang=' + conf.wgUserLanguage : '')
+ '|live=1}}';
Line 2,205 ⟶ 2,219:
else
img_page_name = '';
self.may_edit = (img_page_name.replace(/ /g, '_') == conf.wgTitle.replace(/ /g, '_'));
}
Line 2,270 ⟶ 2,284:
}
function pause (
LAPI.Evt.remove(document, 'mousemove', track, true);
if (!LAPI.Browser.is_ie && typeof document.captureEvents === 'function')
Line 2,277 ⟶ 2,291:
}
function resume (
// captureEvents is actually deprecated, but I haven't succeeded to make this work with
// addEventListener only.
Line 2,368 ⟶ 2,382:
}
function add_new (
if (!self.canEdit()) return;
Line 2,640 ⟶ 2,654:
function make_script_calls (list, api) {
var template = api + '?action=parse&pst&text=&prop=text&format=json'
+ '&maxage=1800&smaxage=1800&uselang=' + conf.wgUserLanguage //see bugzilla 22764
+ '&callback=ImageAnnotator.script_callbacks[].callback';
if (template.startsWith('//')) template = document.___location.protocol + template; // Avoid protocol-relative URIs (IE7 bug)
Line 2,738 ⟶ 2,752:
var zoom_width = Math.floor(self.viewers[0].thumb.width * self.zoom_factor);
var zoom_height = Math.floor(self.viewers[0].thumb.height * self.zoom_factor);
▲ var zoom_src = null;
// For SVGs, always use a scaled PNG for the zoom.
if (zoom_width > 0.9 * self.viewers[0].full_img.width && src.search(/\.svg\.png$/i) < 0) {
Line 3,099 ⟶ 3,112:
}
}; // end IA (private)
// Public interface
window.ImageAnnotator = {
install: function (config) {
mw.loader.using(['mediawiki.util'], function () {
IA.install(config);
});
}
};
|