Utilisateur:Phe/Aide-LangConverter.js
Note : après avoir enregistré vos modifications, il se peut que vous deviez forcer le rechargement complet du cache de votre navigateur pour voir les changements.
- Firefox / Safari : Maintenez la touche Maj (Shift) en cliquant sur le bouton Actualiser ou pressez Ctrl-F5 ou Ctrl-R (⌘-R sur un Mac) ;
- Google Chrome : Appuyez sur Ctrl-Maj-R (⌘-Shift-R sur un Mac) ;
- Internet Explorer : Maintenez la touche Ctrl en cliquant sur le bouton Actualiser ou pressez Ctrl-F5 ;
- Opera : Allez dans Menu → Settings (Opera → Préférences sur un Mac) et ensuite à Confidentialité & sécurité → Effacer les données d'exploration → Images et fichiers en cache.
/**
* LangConverter-Helper.js
*
* Auteur : Phe
*
* The ui is a jquery dialog containing one tab per variant, tabs contain
* three list (ul) sortable enabled between list. User build data to generate
* the template by drag&drop'ing the item to the right list.
*
* The list in the center of the dialog contains suggestion, they come from other
* local dict or from a spell checking of the page contents html. Right list
* contains the list used to generate the template, this list is pre-filled
* with the actual content of the local dict which match the html text of
* the current page (useless local dict entry are silently ignored). Left
* list acts as a blacklist, all entry dropped in this list will be ignored
* in any later call to this script on any page (the ignore list is global).
* (Poorly implemented on the server side atm) Blacklist is per wiki, not per
* lang variant.
*
*
* cookie used : 'lc_ui_setting', json stringified data of the dialog size.
*
* TODO:
*
* Dropping back to the candidate container does not put it in
* in the right place, annoying for spelling suggestion as it split
* the group in multiple sub-group.
*
* Merge with LanguageConverter.
*
* string localisation.
*
* search FIXME in the code.
*
* Add transparency to the dialog so the text under the dialog is visible.
*
* double-click to move from/to central list/right list, double-click to move from left to central list.
*
* auto update cache on server side, can be done by sending data to the server ? but we don't know the new rev id.
*
* add an edit field to allow to add dict entry not provide through the central list.
*
* find all occurrence of a word when clicking a word, but ... conflict a bit with double click ?
*
* vertical disposition of the ui ?
*
* Sort list.
*
* write docs.
*/
/**
* Setup the Language Converter global:
*/
if ( window.LanguageConverter === undefined ) {
window.LanguageConverter = {};
}
/**
* The global Language Converter object
*/
( function ( mw, $, lc ) {
'use strict';
/**** Customization ****/
// Same as lc.variant_list but exclude the original variant, these names are used
// as #id tab suffix, they need to be the same name as server variant name.
// See https://github.com/phil-el/phetools/blob/master/modernization/modernization.py
// variable dict_config['xxx']['variant'] for the supported lang and variant.
lc.variant_name = [ 'FR' ];
// Tab name, always needed but hidden in the dialog if there is only one variant.
lc.variant_tab_name = { 'FR' : 'Français moderne' };
// template name to generate
lc.template_modernize = 'modernisation';
// Each template variant is expanded only if the dict for this variant is empty. For pt.ws
// something ala, the key must match a lc.variant_name.
// lc.template_variant = { 'PT' : '\n|pt-PT=\n@@PT@@\n</div>', 'BR' : '.....' }
lc.template_variant = { 'FR' : '|\n@@FR@@' };
// a regex to match the modernization template, text matched, if any, will be removed from the page
// and replaced by the template build with the above setting.
lc.template_regex = /{{\s*[mM]odernisation[\s\S]*?}}/m;
/**** End of customization ****/
// return the first elt class name matching regexp or null if none.
lc.get_class_name = function (elt, regex) {
var result = null;
var class_list = $(elt).attr("class").split(/\s+/);
$.each(class_list, function(index, item) {
if (regex.test(item)) {
result = item;
return false;
}
});
return result;
};
lc.write_page = function (pagename, text, comment) {
var api = new mw.Api();
return api.postWithEditToken( {
action : 'edit',
text : text,
comment : comment,
title : pagename,
} );
};
lc.load_ui_setting = function (name) {
var result = { width : 300, height : 480 };
var cookie_value = $.cookie('lc_ui_setting');
if (cookie_value) {
var value = JSON.parse(cookie_value);
result = $.extend({}, result, value);
}
return result;
};
lc.save_ui_setting = function (event, ui) {
var value = { width : $( "#lc-dialog" ).dialog( "option", "width" ),
height : $( "#lc-dialog" ).dialog( "option", "height" ) };
var serialized = JSON.stringify(value);
$.cookie('lc_ui_setting', serialized, { path : '/wiki/', expires : 180 } );
};
lc.save_result = function (page_text) {
if (lc.blacklist.length) {
$.getJSON( 'https://tools.wmflabs.org/phetools/modernization_cgi.py', {
cmd: 'blacklist',
blacklist: JSON.parse(lc.blacklist),
lang: mw.config.get('wgContentLanguage')
} ).done( function ( data ) {
mw.log('Blacklist request answser: ' + JSON.parse(data));
} );
}
var template_text = '{{' + lc.template_modernize;
for (var i in lc.variant_name) {
var variant_text = '';
for (var j in lc.template_content[lc.variant_name[i]]) {
variant_text += '* ' + lc.template_content[lc.variant_name[i]][j] + '\n';
}
if (variant_text) {
variant_text = lc.template_variant[lc.variant_name[i]].replace('@@' + lc.variant_name[i] + '@@', variant_text);
template_text += variant_text;
}
}
template_text += '}}';
var match = lc.template_regex.exec(page_text);
if (match) {
page_text = page_text.replace(match, template_text);
} else {
page_text = page_text + '\n' + template_text;
}
var $promise = lc.write_page(mw.config.get('wgPageName'), page_text, 'mise à jour du modèle modernisation');
$.when($promise.done()).then(function () { window.location = window.location; } );
};
lc.change_page = function (pagename) {
$.ajax({
url: mw.util.wikiScript( 'api' ),
dataType: 'json',
data: {
'format': 'json',
'action': 'query',
'titles': pagename,
'prop': 'revisions',
'rvprop': 'content',
'indexpageids': '1'
},
success : function (res) {
if (res.query && res.query.pages && res.query.pageids && res.query.pageids.length) {
var pages = res.query.pages;
var pageids = res.query.pageids ;
if ( pages[ pageids[0] ].pageid ) {
var page_text = pages[ pageids[0] ].revisions[0]['*'];
lc.save_result(page_text);
}
}
}
});
};
lc.on_dialog_ok = function(event, ui) {
lc.blacklist = [];
$('#lc-sortable-blacklist li').each(function () {
lc.blacklist.push($(this).text());
});
lc.template_content = {};
for (var i in lc.variant_name) {
lc.template_content[lc.variant_name[i]] = [];
$('#lc-tabs-' + lc.variant_name[i] + ' #lc-sortable-modernize li').each(function () {
lc.template_content[lc.variant_name[i]].push($(this).text());
}); // FIXME: warning don't make functions within a loop
}
var text = lc.change_page(mw.config.get('wgPageName'));
$("#lc-dialog").dialog("close");
};
lc.on_create_dialog = function(event, ui) {
$(event.target).parent().css( { position : 'fixed' } );
};
// The dialog is opened after the server call is done as we need the data
// to fill the dialog box.
lc.open_dialog = function() {
$.getJSON( 'https://tools.wmflabs.org/phetools/modernization_cgi.py', {
cmd: 'suggest',
title: mw.config.get('wgPageName'),
lang: mw.config.get('wgContentLanguage')
} ).done( function ( data ) {
lc.setup_dialog(data);
} );
};
lc.list_from_array = function (arr) {
var html = '';
for (var i in arr) {
html += '<li>' + arr[i][0] + ' : ' + arr[i][1] + '</li>\n';
}
return html;
};
lc.list_from_suggest = function (arr) {
var html = '';
for (var i in arr) {
// group_name is a class name used to hide/unhide all other element except the one dropped.
var group_name = 'lc-group-suggest-' + i;
//$('<style type="text/css"></style>')
// .html(".ui-selecting { background: silver; }\n.ui-selected { background: gray; }")
// .appendTo("head");
for (var j in arr[i][1]) {
var style = '';
/*
if (j === 0) {
style += 'style="padding-top:0.15em;"';
} else if (j == arr[i][1].length - 1) {
style += 'style="padding-bottom:0.15em;"';
}
*/
html += '<li class="' + group_name + '" ' + style + '>' + arr[i][0] + ' : ' + arr[i][1][j] + '</li>\n';
}
}
return html;
};
lc.resize_ul = function () {
// Hack $('#ui-dialog-titlebar').height() and $('#ui-dialog-buttonpane').height() return 0, so hard code a guessed value.
var max_height = $('#lc-dialog').height() - 48; /*( $('#ui-dialog-titlebar').height() + $('#ui-dialog-buttonpane').height() ); Broken return 0 */
$('#lc-sortable-blacklist, #lc-sortable-candidate, #lc-sortable-modernize').height(max_height);
};
lc.setup_dialog = function (data) {
for (var key in data) {
var local_dict_used = data[key].local_dict_used;
var html = lc.list_from_array(local_dict_used);
$('#lc-tabs-' + key + ' #lc-sortable-modernize').html(html);
var suggest_local_dict = data[key].suggest_local_dict;
html = lc.list_from_array(suggest_local_dict);
var speller_suggest = data[key].speller_suggest;
html += lc.list_from_suggest(speller_suggest);
$('#lc-tabs-' + key + ' #lc-sortable-candidate').html(html);
}
var buttons = [
{
text: "Ok",
click: function() { lc.on_dialog_ok(); }
},
{
text: "Annuler",
click: function() { $(this).dialog("close"); }
}
];
var defaults = lc.load_ui_setting();
$("#lc-dialog").dialog({
create: lc.on_create_dialog,
close : lc.save_ui_setting,
resizeStop: function(event, ui) {
lc.resize_ul();
//$(event.target).parent().css('position', 'fixed');
//$(dlg).dialog('option','position', 'right');
},
buttons : buttons,
position : 'right',
height : defaults.height,
width : defaults.width,
minHeight: 180,
maxHeight : 640 /* Why a max? */
});
/* FIXME: must be unbinded when closing the dialog or must be setup in setup() */
$(window).resize(function() {
$("#lc-dialog").dialog('option', 'position', 'right');
});
$('.lc-sortable').hide();
$('.lc-sortable').sortable({
connectWith: '.lc-sortable',
remove: function (event, ui) {
var class_name = lc.get_class_name(ui.item, /^lc-group-suggest-[\d]+$/);
/* FIXME: do we need something like this in some case, drop to blacklist hide all
but dropping to candidate must hide only for the current tab not for the inactive tab
var $tabs = $('#lc-tabs').tabs();
// Jquery >= 1.9, 'selected' rather than 'active' for < 1.9
var active = $tabs.tabs('option', 'active');
var active_tab_id = $('div[id^="lc-tabs-"]')[active].getAttribute('id');
if (this === $('#' + active_tab_id + ' #lc-sortable-candidate')[0]) {
$('.' + class_name).show();
} else {
$('.' + class_name).hide();
}
*/
// See http://stackoverflow.com/questions/9440664/jquery-ui-sortable-drag-initiation-is-slow-when-container-has-hidden-items
if (ui.item[0].parentNode.id == 'lc-sortable-candidate') {
$('.' + class_name).removeClass('hidden');
} else {
$('.' + class_name).addClass('hidden');
}
$(ui.item).removeClass('hidden');
},
});
$('.lc-sortable').show();
lc.resize_ul();
};
lc.init_and_open = function() {
if (!$('#lc-dialog').length) {
$('<style type="text/css"></style>')
.html(".hidden { height:0; overflow:hidden;margin-bottom:0; }")
.appendTo("head");
// jquery remove the display:none when opening the dialog, adding it here is needed to avoid
// to see part of the dialog on the page between creation and opening.
$('#content').append('<div id="lc-dialog" class="help-lang-converter" title="Aide à la modernisation" style="display:none;"></div>');
// html struct
// div dialog
// div > ul blacklist at left
// div tabs at right
// for each tabs
// div > ul candidate
// div > ul modernize
var inner_tab = '<div style="text-align:center;display:block;float:left;width:48%;">Candidat :<ul id="lc-sortable-candidate" style="text-align:left;min-height:32px;overflow-y:scroll;" class="lc-sortable"></ul></div><div style="text-align:center;display:block;float:right;width:48%;">Modernise :<ul id="lc-sortable-modernize" class="lc-sortable" style="text-align:left;min-height:32px;overflow-y:scroll;"></ul></div>';
var tabs_list_html = '';
for (var i in lc.variant_name) {
tabs_list_html += '<li><a href="#lc-tabs-' + lc.variant_name[i] + '">' + lc.variant_tab_name[lc.variant_name[i]] + '</a></li>\n';
}
// padding-top:1em; is a kludge to top-align this container with the contents of the tabs container
var html = '<div style="text-align:center;display:block;float:left;width:30%;padding-top:1em;">Suppression :<ul style="text-align:left;min-height:32px;overflow-y:scroll;" id="lc-sortable-blacklist" class="lc-sortable"></ul></div><div id="lc-tabs">\n<ul>\n' + tabs_list_html + '</ul>\n';
for (var j in lc.variant_name) {
html += '<div id="lc-tabs-' + lc.variant_name[i] + '" style="display:block;float:right;width:60%">' + inner_tab + '</div></div>\n';
}
html += '</div>';
$('#lc-dialog').html(html);
// We always build and activate tabs even if there is only one tab, in this case
// we hide the tab, it simplify the used selector as they don't depend on the
// number of variant.
if (lc.variant_name.length == 1) {
// pointeless to show the tab if there is only one variant.
$('#lc-tabs > ul').attr('style', 'display:none');
$('#lc-tabs').css('border', '0px');
}
$('#lc-tabs').tabs();
}
lc.open_dialog();
};
lc.init = function() {
// FIXME: remove this condition when integrating to LanguageConverter or use the same condition as lc but with an implicit selection_mode == OR
// as we want to allow to work on a page w/o a modernization template.
if (mw.config.get('wgNamespaceNumber') === 0 && (mw.config.get('wgAction') === 'view' || mw.config.get('wgAction') === 'history')) {
mw.util.addPortletLink(
'p-cactions',
null,
'Modernisation',
'ca-dict-helper',
'Open modernization dict helper'
);
} else {
return;
}
$('li#ca-dict-helper a').click(function() {
lc.init_and_open();
});
};
$.when(
mw.loader.using( [ 'mediawiki.api', 'mediawiki.util', 'jquery.ui', 'jquery.ui', 'ext.gadget.modernisation' /*, 'jquery.ui' */ ] ),
$.ready
).then( function () {
lc.init();
});
}( mediaWiki, jQuery, window.LanguageConverter ) );