jenkins-bot has submitted this change and it was merged.
Change subject: Insert special character tool
......................................................................
Insert special character tool
A tool to add special characters and diacritics to text.
Also added a new button type ve.ui.GroupButtonWidget that includes a
group of PushButtonWidget objects and returna the individual button's
value upon click
Wikis can edit <visualeditor-specialcharinspector-characterlist-insert>,
a JSON string, to include their own desird special characters to insert
through the tool.
Bug: 50296
Change-Id: I26d1f437feef1c8b61ed3be5f74ef524b33baf49
---
M VisualEditor.i18n.php
M VisualEditor.php
M demos/ve/index.php
M modules/ve/init/ve.init.Target.js
M modules/ve/test/index.php
A modules/ve/ui/inspectors/ve.ui.SpecialCharacterInspector.js
A modules/ve/ui/styles/images/spinner.gif
M modules/ve/ui/styles/ve.ui.Inspector.css
M modules/ve/ui/styles/ve.ui.Widget.css
M modules/ve/ui/tools/ve.ui.InspectorTool.js
A modules/ve/ui/widgets/ve.ui.GroupButtonWidget.js
11 files changed, 391 insertions(+), 3 deletions(-)
Approvals:
Catrope: Looks good to me, approved
jenkins-bot: Verified
diff --git a/VisualEditor.i18n.php b/VisualEditor.i18n.php
index b2c2cea..605fe30 100644
--- a/VisualEditor.i18n.php
+++ b/VisualEditor.i18n.php
@@ -155,6 +155,55 @@
'visualeditor-linkinspector-title' => 'Hyperlink',
'visualeditor-listbutton-bullet-tooltip' => 'Bullet list',
'visualeditor-listbutton-number-tooltip' => 'Numbered list',
+ 'visualeditor-specialcharacter-button-tooltip' => 'Special character',
+ 'visualeditor-specialcharacterinspector-title' => 'Special character',
+ 'visualeditor-specialcharinspector-characterlist-insert' => '{
+ "symbols": {
+ "−": "−",
+ "—": "—",
+ "°": "°",
+ "″": "″",
+ "′": "′",
+ "←": "←",
+ "→": "→",
+ "·": "·",
+ "§": "§"
+ },
+ "accents": {
+ "à": "à",
+ "á": "á",
+ "â": "â",
+ "ä": "ä",
+ "ç": "ç",
+ "è": "è",
+ "é": "é",
+ "ê": "ê",
+ "ë": "ë",
+ "ì": "ì",
+ "í": "í",
+ "î": "î",
+ "ï": "ï",
+ "ò": "ò",
+ "ó": "ó",
+ "ô": "ô",
+ "ö": "ö",
+ "ø": "ø",
+ "ù": "ù",
+ "ú": "ú",
+ "û": "û",
+ "ü": "ü"
+ },
+ "math": {
+ "−": "−",
+ "×": "×",
+ "÷": "÷",
+ "≈": "≈",
+ "≠": "≠",
+ "≤": "≤",
+ "≥": "≥",
+ "±": "±"
+ }
+}',
'visualeditor-loadwarning' => 'Error loading data from server: $1.
Would you like to retry?',
'visualeditor-loadwarning-token' => 'Error loading edit token from
server: $1. Would you like to retry?',
'visualeditor-mainnamespacepagelink' => 'Project:Main namespace',
@@ -555,6 +604,9 @@
{{Identical|Hyperlink}}',
'visualeditor-listbutton-bullet-tooltip' => 'Tooltip text for the
bullet list button',
'visualeditor-listbutton-number-tooltip' => 'Tooltip text for the
numbered list button',
+ 'visualeditor-specialcharacter-button-tooltip' => 'Tooltip text for the
insert character button',
+ 'visualeditor-specialcharacterinspector-title' => 'Used as title for
special character inspector',
+ 'visualeditor-specialcharinspector-characterlist-insert' => 'This is a
JSON string defining the special characters that can be inserted using the
special character insertion tool. Please make sure it is a valid JSON string.',
'visualeditor-loadwarning' => 'Text (JavaScript confirm()) shown when
the editor fails to load properly.
Parameters:
diff --git a/VisualEditor.php b/VisualEditor.php
index a1e389f..c26ad52 100644
--- a/VisualEditor.php
+++ b/VisualEditor.php
@@ -511,6 +511,9 @@
've/ui/inspectors/ve.ui.LinkInspector.js',
've-mw/ui/inspectors/ve.ui.MWLinkInspector.js',
've-mw/ui/inspectors/ve.ui.MWExtensionInspector.js',
+
+ 've/ui/widgets/ve.ui.GroupButtonWidget.js',
+ 've/ui/inspectors/ve.ui.SpecialCharacterInspector.js',
),
'styles' => array(
// ce
@@ -667,6 +670,9 @@
'visualeditor-savedialog-warning-dirty',
'visualeditor-saveerror',
'visualeditor-serializeerror',
+ 'visualeditor-specialcharacter-button-tooltip',
+ 'visualeditor-specialcharacterinspector-title',
+
'visualeditor-specialcharinspector-characterlist-insert',
'visualeditor-toolbar-cancel',
'visualeditor-toolbar-savedialog',
'visualeditor-version-label',
diff --git a/demos/ve/index.php b/demos/ve/index.php
index 60dabfe..982972c 100644
--- a/demos/ve/index.php
+++ b/demos/ve/index.php
@@ -235,8 +235,9 @@
<script
src="../../modules/ve/ui/actions/ve.ui.IndentationAction.js"></script>
<script
src="../../modules/ve/ui/actions/ve.ui.InspectorAction.js"></script>
<script
src="../../modules/ve/ui/actions/ve.ui.ListAction.js"></script>
- <script
src="../../modules/ve/ui/widgets/ve.ui.SurfaceWidget.js"></script>
+ <script
src="../../modules/ve/ui/widgets/ve.ui.GroupButtonWidget.js"></script>
<script
src="../../modules/ve/ui/widgets/ve.ui.LinkTargetInputWidget.js"></script>
+ <script
src="../../modules/ve/ui/widgets/ve.ui.SurfaceWidget.js"></script>
<script
src="../../modules/ve/ui/tools/ve.ui.AnnotationTool.js"></script>
<script
src="../../modules/ve/ui/tools/ve.ui.ClearAnnotationTool.js"></script>
<script
src="../../modules/ve/ui/tools/ve.ui.DialogTool.js"></script>
@@ -247,6 +248,7 @@
<script
src="../../modules/ve/ui/tools/ve.ui.ListTool.js"></script>
<script
src="../../modules/ve/ui/inspectors/ve.ui.AnnotationInspector.js"></script>
<script
src="../../modules/ve/ui/inspectors/ve.ui.LinkInspector.js"></script>
+ <script
src="../../modules/ve/ui/inspectors/ve.ui.SpecialCharacterInspector.js"></script>
<!-- jquery.uls.data -->
<script
src="../../modules/jquery.uls/src/jquery.uls.data.js"></script>
<script
src="../../modules/jquery.uls/src/jquery.uls.data.utils.js"></script>
diff --git a/modules/ve/init/ve.init.Target.js
b/modules/ve/init/ve.init.Target.js
index abc7f9f..73c5cb7 100644
--- a/modules/ve/init/ve.init.Target.js
+++ b/modules/ve/init/ve.init.Target.js
@@ -39,7 +39,8 @@
},
{ 'include': [ 'bold', 'italic', 'link', 'clear' ] },
{ 'include': [ 'number', 'bullet', 'outdent', 'indent' ] },
- { 'include': '*' }
+ { 'include': '*', 'demote': [ 'specialcharacter' ] }
+
];
ve.init.Target.static.surfaceCommands = [
diff --git a/modules/ve/test/index.php b/modules/ve/test/index.php
index 5e69417..bc2a511 100644
--- a/modules/ve/test/index.php
+++ b/modules/ve/test/index.php
@@ -188,8 +188,9 @@
<script
src="../../ve/ui/actions/ve.ui.IndentationAction.js"></script>
<script
src="../../ve/ui/actions/ve.ui.InspectorAction.js"></script>
<script src="../../ve/ui/actions/ve.ui.ListAction.js"></script>
- <script
src="../../ve/ui/widgets/ve.ui.SurfaceWidget.js"></script>
+ <script
src="../../ve/ui/widgets/ve.ui.GroupButtonWidget.js"></script>
<script
src="../../ve/ui/widgets/ve.ui.LinkTargetInputWidget.js"></script>
+ <script
src="../../ve/ui/widgets/ve.ui.SurfaceWidget.js"></script>
<script
src="../../ve/ui/tools/ve.ui.AnnotationTool.js"></script>
<script
src="../../ve/ui/tools/ve.ui.ClearAnnotationTool.js"></script>
<script src="../../ve/ui/tools/ve.ui.DialogTool.js"></script>
@@ -200,6 +201,7 @@
<script src="../../ve/ui/tools/ve.ui.ListTool.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/ui/inspectors/ve.ui.SpecialCharacterInspector.js"></script>
<!-- jquery.uls.data -->
<script src="../../jquery.uls/src/jquery.uls.data.js"></script>
<script
src="../../jquery.uls/src/jquery.uls.data.utils.js"></script>
diff --git a/modules/ve/ui/inspectors/ve.ui.SpecialCharacterInspector.js
b/modules/ve/ui/inspectors/ve.ui.SpecialCharacterInspector.js
new file mode 100644
index 0000000..81c6870
--- /dev/null
+++ b/modules/ve/ui/inspectors/ve.ui.SpecialCharacterInspector.js
@@ -0,0 +1,232 @@
+/*!
+ * VisualEditor UserInterface SpecialCharacterInspector class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * Special character inspector.
+ *
+ * @class
+ * @extends ve.ui.Inspector
+ *
+ * @constructor
+ * @param {ve.ui.WindowSet} windowSet Window set this inspector is part of
+ * @param {Object} [config] Configuration options
+ */
+ve.ui.SpecialCharacterInspector = function VeUiSpecialCharacterInspector(
windowSet, config ) {
+
+ // Parent constructor
+ ve.ui.Inspector.call( this, windowSet, config );
+
+ this.characters = null;
+ this.$buttonDomList = null;
+ this.initialSelection = null;
+ this.addedChar = null;
+ this.categories = null;
+
+ // Fallback character list in case no list is found anywhere
+ this.minimalCharacterList =
+ {
+ 'accents': {
+ 'à': 'à',
+ 'á': 'á',
+ 'â': 'â',
+ 'ä': 'ä',
+ 'ç': 'ç',
+ 'è': 'è',
+ 'é': 'é',
+ 'ê': 'ê',
+ 'ë': 'ë',
+ 'ì': 'ì',
+ 'í': 'í',
+ 'î': 'î',
+ 'ï': 'ï',
+ 'ò': 'ò',
+ 'ó': 'ó',
+ 'ô': 'ô',
+ 'ö': 'ö',
+ 'ø': 'ø',
+ 'ù': 'ù',
+ 'ú': 'ú',
+ 'û': 'û',
+ 'ü': 'ü'
+ },
+ 'symbols': {
+ '−': '−',
+ '—': '—',
+ '°': '°',
+ '″': '″',
+ '′': '′',
+ '←': '←',
+ '→': '→',
+ '·': '·',
+ '§': '§'
+ }
+ };
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ui.SpecialCharacterInspector, ve.ui.Inspector );
+
+/* Static properties */
+
+ve.ui.SpecialCharacterInspector.static.name = 'specialcharacter';
+
+ve.ui.SpecialCharacterInspector.static.icon = 'specialcharacter';
+
+ve.ui.SpecialCharacterInspector.static.titleMessage =
'visualeditor-specialcharacterinspector-title';
+
+ve.ui.SpecialCharacterInspector.static.removeable = false;
+
+/* Methods */
+
+/**
+ * Handle frame ready events.
+ *
+ * @method
+ */
+ve.ui.SpecialCharacterInspector.prototype.initialize = function () {
+ // Parent method
+ ve.ui.Inspector.prototype.initialize.call( this );
+
+ this.$spinner = this.$( '<div>' ).addClass( 've-specialchar-spinner' );
+ this.$form.append( this.$spinner );
+};
+
+/**
+ * Handle the inspector being setup.
+ *
+ * @method
+ * @param {Object} [data] Inspector opening data
+ */
+ve.ui.SpecialCharacterInspector.prototype.setup = function ( data ) {
+ // Parent method
+ ve.ui.Inspector.prototype.setup.call( this, data );
+
+ // Preserve initial selection so we can collapse cursor position
+ // after we're done adding
+ this.initialSelection = this.surface.getModel().getSelection();
+
+ this.getCharList().done( ve.bind( function() {
+ // Now we can rebuild our button list
+ // We only want to rebuild the list if we don't already have it
+ if ( !this.$buttonDomList ) {
+ // Start with the spinner showing
+ this.$spinner.show();
+ this.buildButtonList().done( ve.bind( function() {
+ // Append the new button list
+ this.$form.append( this.$buttonDomList );
+ // Done, hide the spinner
+ this.$spinner.hide();
+
+ }, this ) );
+ }
+ }, this ) );
+
+};
+
+/**
+ * Get the special character list object
+ * This can also be an AJAX call with default fallback
+ *
+ * @returns {jQuery.Promise}
+ */
+ve.ui.SpecialCharacterInspector.prototype.getCharList = function () {
+ var charslist, charobj,
+ deferred = $.Deferred();
+
+ // Don't request the character list again if we already have it
+ if ( !this.characters ) {
+
+ // Get the character list
+ charslist = ve.msg(
'visualeditor-specialcharinspector-characterlist-insert' );
+ try {
+ charobj = $.parseJSON( charslist );
+ } catch ( err ) {
+ // There was no character list found, or the character
list message is
+ // invalid json string. Force a fallback to the minimal
character list
+ charobj = this.minimalCharacterList;
+ ve.log( 've.ui.SpecialCharacterInspector: Could not
parse the Special Character list; using default.');
+ ve.log( err.message );
+ } finally {
+ this.characters = charobj;
+ deferred.resolve();
+ }
+ }
+
+ return deferred.promise();
+};
+
+/**
+ * Builds the button DOM list based on the character list
+ *
+ * @returns {jQuery.Promise}
+ */
+ve.ui.SpecialCharacterInspector.prototype.buildButtonList = function () {
+ var category, categoryButtons,
+ deferred = $.Deferred(),
+ $widgetOutput = this.$( '<div>' ).addClass(
've-specialchar-list' );
+
+ if ( !this.characters ) {
+ deferred.reject();
+ }
+
+ for ( category in this.characters ) {
+ categoryButtons = new ve.ui.GroupButtonWidget( {
+ 'groupName': category,
+ 'group': this.characters[category],
+ 'aggregations': { 'click': 'click' }
+ } );
+
+ categoryButtons.connect( this, { 'click': 'onSpecialCharAdd' }
);
+
+ $widgetOutput
+ .append( this.$( '<h2>').text( category ) )
+ .append( categoryButtons.$element );
+ }
+
+ this.$buttonDomList = $widgetOutput;
+ deferred.resolve();
+ return deferred.promise();
+};
+
+/**
+ * Handle the click event on the button groups. The value of the selection
will be inserted
+ * into the text
+ *
+ * @param {OO.ui.PushButtonWidget} button The value attached to the clicked
button
+ */
+ve.ui.SpecialCharacterInspector.prototype.onSpecialCharAdd = function ( button
) {
+ var fragment = this.surface.getModel().getFragment( null, true ),
+ value = button.returnValue;
+
+ // Insert the character
+ if ( value !== undefined ) {
+ // get the insertion value (it could be in any category)
+ this.addedChar = value;
+ fragment.insertContent( value, false );
+ }
+};
+
+/**
+ * @inheritdoc
+ */
+ve.ui.SpecialCharacterInspector.prototype.teardown = function ( data ) {
+ var selection;
+ // Collapse selection after the inserted content
+ if ( this.addedChar ) {
+ selection = new ve.Range( this.initialSelection.start +
this.addedChar.length );
+ this.surface.execute( 'content', 'select', selection );
+ }
+ // reset
+ this.addedChar = null;
+ // Parent method
+ ve.ui.Inspector.prototype.teardown.call( this, data );
+};
+
+/* Registration */
+
+ve.ui.inspectorFactory.register( ve.ui.SpecialCharacterInspector );
diff --git a/modules/ve/ui/styles/images/spinner.gif
b/modules/ve/ui/styles/images/spinner.gif
new file mode 100644
index 0000000..c478f8f
--- /dev/null
+++ b/modules/ve/ui/styles/images/spinner.gif
Binary files differ
diff --git a/modules/ve/ui/styles/ve.ui.Inspector.css
b/modules/ve/ui/styles/ve.ui.Inspector.css
index 05a9db0..2cbe046 100644
--- a/modules/ve/ui/styles/ve.ui.Inspector.css
+++ b/modules/ve/ui/styles/ve.ui.Inspector.css
@@ -41,3 +41,20 @@
padding: 0;
white-space: nowrap;
}
+
+/* ve.ui.SpecialCharacterInspector.js */
+
+.ve-specialchar-spinner {
+ /* There might be a better place for a spinner? */
+ /* @embed */
+ background-image: url(images/spinner.gif);
+ width: 31px;
+ height: 31px;
+ margin-left: auto;
+ margin-right: auto;
+}
+
+.ve-specialchar-list h2 {
+ font-size: 1em;
+ text-transform: capitalize;
+}
diff --git a/modules/ve/ui/styles/ve.ui.Widget.css
b/modules/ve/ui/styles/ve.ui.Widget.css
index ec9e878..c4d5bf2 100644
--- a/modules/ve/ui/styles/ve.ui.Widget.css
+++ b/modules/ve/ui/styles/ve.ui.Widget.css
@@ -108,3 +108,9 @@
border-bottom-left-radius: 0;
border-bottom-width: 0;
}
+
+/* ve.ui.GroupButtonWidget.js */
+
+.ve-ui-groupButtonWidget {
+ white-space: normal;
+}
diff --git a/modules/ve/ui/tools/ve.ui.InspectorTool.js
b/modules/ve/ui/tools/ve.ui.InspectorTool.js
index c6a3c2b..533a5d3 100644
--- a/modules/ve/ui/tools/ve.ui.InspectorTool.js
+++ b/modules/ve/ui/tools/ve.ui.InspectorTool.js
@@ -119,3 +119,23 @@
ve.ui.LinkInspectorTool.static.inspector = 'link';
ve.ui.LinkInspectorTool.static.modelClasses = [ ve.dm.LinkAnnotation ];
ve.ui.toolFactory.register( ve.ui.LinkInspectorTool );
+
+/**
+ * Insert characters tool.
+ *
+ * @class
+ * @extends ve.ui.InspectorTool
+ * @constructor
+ * @param {OO.ui.ToolGroup} toolGroup
+ * @param {Object} [config] Configuration options
+ */
+ve.ui.InsertCharacterInspectorTool = function
VeUiInsertCharacterInspectorTool( toolGroup, config ) {
+ ve.ui.InspectorTool.call( this, toolGroup, config );
+};
+OO.inheritClass( ve.ui.InsertCharacterInspectorTool, ve.ui.InspectorTool );
+ve.ui.InsertCharacterInspectorTool.static.name = 'specialcharacter';
+ve.ui.InsertCharacterInspectorTool.static.group = 'insert';
+ve.ui.InsertCharacterInspectorTool.static.icon = 'special-character';
+ve.ui.InsertCharacterInspectorTool.static.titleMessage =
'visualeditor-specialcharacter-button-tooltip';
+ve.ui.InsertCharacterInspectorTool.static.inspector = 'specialcharacter';
+ve.ui.toolFactory.register( ve.ui.InsertCharacterInspectorTool );
diff --git a/modules/ve/ui/widgets/ve.ui.GroupButtonWidget.js
b/modules/ve/ui/widgets/ve.ui.GroupButtonWidget.js
new file mode 100644
index 0000000..7ac770a
--- /dev/null
+++ b/modules/ve/ui/widgets/ve.ui.GroupButtonWidget.js
@@ -0,0 +1,50 @@
+/*!
+ * VisualEditor UserInterface GroupButtonWidget class.
+ *
+ * @copyright 2011-2013 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * Creates an ve.ui.GroupButtonWidget object.
+ *
+ * @class
+ * @extends OO.ui.Widget
+ *
+ * @param {Object} [config] Configuration options
+ * @cfg {Object} [group] Button group parameters organized by { 'label':
returnValue }
+ * where 'returnValue' is the value associated with the button
+ */
+ve.ui.GroupButtonWidget = function VeUiGroupButtonWidget( config ) {
+ var item, button, arrButtons = [];
+
+ // Parent constructor
+ OO.ui.Widget.call( this, config );
+
+ // Mixin constructors
+ OO.ui.GroupElement.call( this, this.$( '<div>' ), config );
+
+ // Initialization
+ this.value = null;
+ this.group = config.group;
+ this.buttons = {};
+ // Set up the buttons
+ for ( item in this.group ) {
+ button = new OO.ui.PushButtonWidget( {
+ 'label': item,
+ } );
+ // store value
+ button.returnValue = this.group[item];
+ arrButtons.push( button );
+ }
+
+ this.addItems( arrButtons );
+
+ this.$element.append( this.$group.addClass( 've-ui-groupButtonWidget' )
);
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ui.GroupButtonWidget, OO.ui.Widget );
+
+OO.mixinClass( ve.ui.GroupButtonWidget, OO.ui.GroupElement );
--
To view, visit https://gerrit.wikimedia.org/r/90940
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I26d1f437feef1c8b61ed3be5f74ef524b33baf49
Gerrit-PatchSet: 30
Gerrit-Project: mediawiki/extensions/VisualEditor
Gerrit-Branch: master
Gerrit-Owner: Mooeypoo <[email protected]>
Gerrit-Reviewer: Amire80 <[email protected]>
Gerrit-Reviewer: Catrope <[email protected]>
Gerrit-Reviewer: Divec <[email protected]>
Gerrit-Reviewer: Esanders <[email protected]>
Gerrit-Reviewer: Jforrester <[email protected]>
Gerrit-Reviewer: jenkins-bot
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits