Esanders has uploaded a new change for review.
https://gerrit.wikimedia.org/r/262448
Change subject: WIP: VisualEditor support
......................................................................
WIP: VisualEditor support
Change-Id: I02e8297adfe986ca7744aa4b2b5c8960b0866715
---
M .jshintrc
M extension.json
A modules/ve-maps/ve.ce.MWMapsNode.js
A modules/ve-maps/ve.dm.MWMapsNode.js
A modules/ve-maps/ve.ui.MWMaps.css
A modules/ve-maps/ve.ui.MWMapsDialog.js
A modules/ve-maps/ve.ui.MWMapsTool.js
7 files changed, 525 insertions(+), 1 deletion(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/Kartographer
refs/changes/48/262448/1
diff --git a/.jshintrc b/.jshintrc
index d11f205..440d86c 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -19,9 +19,9 @@
"globals": {
"mediaWiki": false,
+ "mw": false,
"OO": false,
"ve": false,
- "vg": false,
"QUnit": false
}
}
diff --git a/extension.json b/extension.json
index 5fbaf59..245b17c 100644
--- a/extension.json
+++ b/extension.json
@@ -47,6 +47,21 @@
"mobile",
"desktop"
]
+ },
+ "ext.kartographer.visualEditor": {
+ "scripts": [
+ "modules/ve-maps/ve.dm.MWMapsNode.js",
+ "modules/ve-maps/ve.ce.MWMapsNode.js",
+ "modules/ve-maps/ve.ui.MWMapsDialog.js",
+ "modules/ve-maps/ve.ui.MWMapsTool.js"
+ ],
+ "styles": [
+ "modules/ve-maps/ve.ui.MWMaps.css"
+ ],
+ "dependencies": [
+ "ext.visualEditor.mwcore",
+ "oojs-ui.styles.icons-location"
+ ]
}
},
"ResourceFileModulePaths": {
@@ -61,6 +76,9 @@
"Kartographer\\Singleton::onParserAfterParse"
]
},
+ "VisualEditorPluginModules": [
+ "ext.kartographer.visualEditor"
+ ],
"config": {
"KartographerDfltStyle": "osm-intl",
"KartographerStyles": ["osm-intl", "osm"],
diff --git a/modules/ve-maps/ve.ce.MWMapsNode.js
b/modules/ve-maps/ve.ce.MWMapsNode.js
new file mode 100644
index 0000000..dbaf455
--- /dev/null
+++ b/modules/ve-maps/ve.ce.MWMapsNode.js
@@ -0,0 +1,120 @@
+/*!
+ * VisualEditor ContentEditable MWMaps class.
+ *
+ * @copyright 2011-2015 VisualEditor Team and others; see
http://ve.mit-license.org
+ */
+
+/**
+ * ContentEditable paragraph node.
+ *
+ * @class
+ * @extends ve.ce.LeafNode
+ * @mixins ve.ce.FocusableNode
+ * @mixins ve.ce.ResizableNode
+ * @mixins ve.ce.AlignableNode
+ *
+ * @constructor
+ * @param {ve.dm.MWMapsNode} model Model to observe
+ * @param {Object} [config] Configuration options
+ */
+ve.ce.MWMapsNode = function VeCeMWMaps( model, config ) {
+ config = config || {};
+
+ // Parent constructor
+ ve.ce.MWMapsNode.super.apply( this, arguments );
+
+ // Mixin constructors
+ ve.ce.ResizableNode.call( this, this.$element, config );
+ // ve.ce.AlignableNode.call( this, this.$element, config );
+
+ this.$imageLoader = null;
+
+ // Events
+ this.model.connect( this, { attributeChange: 'onAttributeChange' } );
+ this.connect( this, { focus: 'onMapFocus' } );
+
+ // DOM changes
+ this.$element
+ .empty()
+ .addClass( 've-ce-mwMapsNode' )
+ .css( this.model.getCurrentDimensions() );
+ this.update();
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ce.MWMapsNode, ve.ce.MWBlockExtensionNode );
+
+OO.mixinClass( ve.ce.MWMapsNode, ve.ce.ResizableNode );
+
+// OO.mixinClass( ve.ce.MWMapsNode, ve.ce.AlignableNode );
+
+/* Static Properties */
+
+ve.ce.MWMapsNode.static.name = 'mwMaps';
+
+ve.ce.MWMapsNode.static.tagName = 'div';
+
+ve.ce.MWMapsNode.static.primaryCommandName = 'mwMaps';
+
+/* Methods */
+
+/**
+ * Update the rendering of the 'align', src', 'width' and 'height' attributes
+ * when they change in the model.
+ *
+ * @method
+ * @param {string} key Attribute key
+ * @param {string} from Old value
+ * @param {string} to New value
+ */
+ve.ce.MWMapsNode.prototype.onAttributeChange = function () {
+ this.update();
+ $( '<img>' ).attr( 'src', this.model.getUrl( 640, 640 ) );
+};
+
+ve.ce.MWMapsNode.prototype.update = function ( width, height ) {
+ var url, node = this;
+
+ if ( !this.model.getCurrentDimensions().width ) {
+ return;
+ }
+
+ if ( this.$imageLoader ) {
+ this.$imageLoader.off();
+ this.$imageLoader = null;
+ }
+
+ url = this.model.getUrl( width, height );
+
+ this.$imageLoader = this.$( '<img>' ).on( 'load', function () {
+ node.$element.css( 'backgroundImage', 'url(' + url + ')' );
+ } ).attr( 'src', url );
+};
+
+ve.ce.MWMapsNode.prototype.onResizableResizing = function () {
+ // Mixin method
+ ve.ce.ResizableNode.prototype.onResizableResizing.apply( this,
arguments );
+
+ this.update( 640, 640 );
+};
+
+/**
+ * @inheritdoc ve.ce.ResizableNode
+ */
+ve.ce.MWMapsNode.prototype.getAttributeChanges = function ( width, height ) {
+ var mwData = ve.copy( this.model.getAttribute( 'mw' ) );
+
+ mwData.attrs.width = width.toString();
+ mwData.attrs.height = height.toString();
+
+ return { mw: mwData };
+};
+
+ve.ce.MWMapsNode.prototype.onMapFocus = function () {
+ $( '<img>' ).attr( 'src', this.model.getUrl( 640, 640 ) );
+};
+
+/* Registration */
+
+ve.ce.nodeFactory.register( ve.ce.MWMapsNode );
diff --git a/modules/ve-maps/ve.dm.MWMapsNode.js
b/modules/ve-maps/ve.dm.MWMapsNode.js
new file mode 100644
index 0000000..5abc6b2
--- /dev/null
+++ b/modules/ve-maps/ve.dm.MWMapsNode.js
@@ -0,0 +1,104 @@
+/*!
+ * VisualEditor DataModel MWMaps class.
+ *
+ * @copyright 2011-2015 VisualEditor Team and others; see
http://ve.mit-license.org
+ */
+
+/**
+ * DataModel MW Maps node.
+ *
+ * @class
+ * @extends ve.dm.MWBlockExtensionNode
+ * @mixins ve.dm.ResizableNode
+ *
+ * @constructor
+ * @param {Object} [element] Reference to element in linear model
+ * @param {ve.dm.Node[]} [children]
+ */
+ve.dm.MWMapsNode = function VeDmMWMaps() {
+ // Parent constructor
+ ve.dm.MWMapsNode.super.apply( this, arguments );
+
+ // Mixin constructors
+ ve.dm.ResizableNode.call( this );
+ // ve.dm.AlignableNode.call( this );
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.dm.MWMapsNode, ve.dm.MWBlockExtensionNode );
+
+OO.mixinClass( ve.dm.MWMapsNode, ve.dm.ResizableNode );
+
+// OO.mixinClass( ve.dm.MWMapsNode, ve.dm.AlignableNode );
+
+/* Static Properties */
+
+ve.dm.MWMapsNode.static.name = 'mwMaps';
+
+ve.dm.MWMapsNode.static.extensionName = 'maps';
+
+/* Static methods */
+
+ve.dm.MWMapsNode.static.toDataElement = function () {
+ var dataElement = ve.dm.MWMapsNode.super.static.toDataElement.apply(
this, arguments );
+
+ dataElement.attributes.width = +dataElement.attributes.mw.attrs.width;
+ dataElement.attributes.height = +dataElement.attributes.mw.attrs.height;
+
+ return dataElement;
+};
+
+ve.dm.MWMapsNode.static.getUrl = function ( dataElement, width, height ) {
+ var mwAttrs = dataElement.attributes.mw.attrs;
+
+ return 'https://maps.wikimedia.org/img/osm-intl,' +
+ mwAttrs.zoom + ',' +
+ mwAttrs.latitude + ',' +
+ mwAttrs.longitude + ',' +
+ ( width || mwAttrs.width ) + 'x' +
+ ( height || mwAttrs.height ) +
+ '.jpeg';
+};
+
+ve.dm.MWMapsNode.static.createScalable = function ( dimensions ) {
+ return new ve.dm.Scalable( {
+ fixedRatio: false,
+ currentDimensions: {
+ width: dimensions.width,
+ height: dimensions.height
+ },
+ minDimensions: {
+ width: 10,
+ height: 10
+ },
+ maxDimensions: {
+ width: 640,
+ height: 640
+ }
+ } );
+};
+
+ve.dm.MWMapsNode.prototype.getCurrentDimensions = function () {
+ return {
+ width: +this.getAttribute( 'mw' ).attrs.width,
+ height: +this.getAttribute( 'mw' ).attrs.height
+ };
+};
+
+/* Methods */
+
+ve.dm.MWMapsNode.prototype.getUrl = function ( width, height ) {
+ return this.constructor.static.getUrl( this.element, width, height );
+};
+
+/**
+ * @inheritdoc
+ */
+ve.dm.MWMapsNode.prototype.createScalable = function () {
+ return this.constructor.static.createScalable(
this.getCurrentDimensions() );
+};
+
+/* Registration */
+
+ve.dm.modelRegistry.register( ve.dm.MWMapsNode );
diff --git a/modules/ve-maps/ve.ui.MWMaps.css b/modules/ve-maps/ve.ui.MWMaps.css
new file mode 100644
index 0000000..b214883
--- /dev/null
+++ b/modules/ve-maps/ve.ui.MWMaps.css
@@ -0,0 +1,11 @@
+.ve-ce-mwMapsNode {
+ background-position: 50% 50%;
+ background-repeat: no-repeat;
+}
+
+.ve-ui-mwMapsDialog-mapWidget {
+ margin: 0 auto 1em auto;
+ max-width: 666px;
+ max-height: 400px;
+ overflow: auto;
+}
\ No newline at end of file
diff --git a/modules/ve-maps/ve.ui.MWMapsDialog.js
b/modules/ve-maps/ve.ui.MWMapsDialog.js
new file mode 100644
index 0000000..6c45caf
--- /dev/null
+++ b/modules/ve-maps/ve.ui.MWMapsDialog.js
@@ -0,0 +1,225 @@
+/*!
+ * VisualEditor UserInterface MWMapsDialog class.
+ *
+ * @copyright 2011-2015 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/* global L */
+
+/**
+ * Dialog for editing MW maps.
+ *
+ * @class
+ * @extends ve.ui.MWExtensionDialog
+ *
+ * @constructor
+ * @param {Object} [config] Configuration options
+ */
+ve.ui.MWMapsDialog = function VeUiMWMapsDialog( config ) {
+ // Parent constructor
+ ve.ui.MWMapsDialog.super.call( this, config );
+
+ this.mapsApiPromise = null;
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ui.MWMapsDialog, ve.ui.MWExtensionDialog );
+
+/* Static Properties */
+
+ve.ui.MWMapsDialog.static.name = 'mwMaps';
+
+ve.ui.MWMapsDialog.static.title = 'Map'; // OO.ui.deferMsg(
'visualeditor-dialog-map-title' );
+
+ve.ui.MWMapsDialog.static.size = 'large';
+
+ve.ui.MWMapsDialog.static.allowedEmpty = true;
+
+ve.ui.MWMapsDialog.static.modelClasses = [ ve.dm.MWMapsNode ];
+
+/**
+ * @inheritdoc
+ */
+ve.ui.MWMapsDialog.prototype.initialize = function () {
+ var panel/*, mapTypeSelectField*/, dimensionsField, alignField; //
dialog = this;
+
+ // Parent method
+ ve.ui.MWMapsDialog.super.prototype.initialize.call( this );
+
+ // this.mapTypeSelect = new OO.ui.ButtonSelectWidget( {
+ // items: [
+ // new OO.ui.ButtonOptionWidget( { data: 'roadmap', label:
'Road map' } ),
+ // new OO.ui.ButtonOptionWidget( { data: 'satellite',
label: 'Satellite' } ),
+ // new OO.ui.ButtonOptionWidget( { data: 'terrain', label:
'Terrain' } ),
+ // new OO.ui.ButtonOptionWidget( { data: 'hybrid', label:
'Hybrid' } )
+ // ]
+ // } ).on( 'choose', function ( item ) {
+ // if ( dialog.map ) {
+ // dialog.map.setMapTypeId( item.getData() );
+ // }
+ // } );
+
+ this.align = new ve.ui.AlignWidget( {
+ dir: this.getDir()
+ } );
+
+ this.$mapContainer = $( '<div>' ).addClass(
've-ui-mwMapsDialog-mapWidget' );
+ this.$map = $( '<div>' ).appendTo( this.$mapContainer );
+ this.map = null;
+ this.scalable = null;
+
+ this.dimensionsWidget = new ve.ui.DimensionsWidget( {} ).connect( this,
{
+ widthChange: 'onDimensionsChange',
+ heightChange: 'onDimensionsChange'
+ } );
+
+ panel = new OO.ui.PanelLayout( {
+ padded: true,
+ expanded: false
+ } );
+
+ // mapTypeSelectField = new OO.ui.FieldLayout( this.mapTypeSelect, {
+ // align: 'right',
+ // label: 'Map type'
+ // } );
+
+ alignField = new OO.ui.FieldLayout( this.align, {
+ align: 'right',
+ label: 'Alignment'
+ } );
+
+ dimensionsField = new OO.ui.FieldLayout( this.dimensionsWidget, {
+ align: 'right',
+ label: 'Size'
+ } );
+
+ panel.$element.append( /*mapTypeSelectField.$element,*/
/*alignField.$element, */dimensionsField.$element, this.$mapContainer );
+ this.$body.append( panel.$element );
+};
+
+ve.ui.MWMapsDialog.prototype.onDimensionsChange = function () {
+ var dimensions = this.dimensionsWidget.getDimensions(),
+ center = this.map && this.map.getCenter();
+
+ // Set container width for centering
+ this.$mapContainer.css( { width: dimensions.width } );
+ this.$map.css( dimensions );
+ this.setSize( this.size );
+
+ this.map.invalidateSize();
+ if ( center ) {
+ this.map.setView( center );
+ }
+};
+
+/**
+ * @inheritdoc ve.ui.MWExtensionWindow
+ */
+ve.ui.MWMapsDialog.prototype.updateMwData = function ( mwData ) {
+ var center, latitude, longitude, zoom,
+ dimensions = this.scalable.getBoundedDimensions(
+ this.dimensionsWidget.getDimensions()
+ );
+
+ if ( this.map ) {
+ center = this.map.getCenter();
+ latitude = center.lat;
+ longitude = center.lng;
+ zoom = this.map.getZoom();
+ } else {
+ // Map not loaded in insert, can't insert
+ return;
+ }
+
+ // mapType: this.mapTypeSelect.getSelectedItem().getData(),
+ mwData.attrs.latitude = latitude.toString();
+ mwData.attrs.longitude = longitude.toString();
+ //mwData.attrs.align = this.align.getSelectedItem().getData();
+ mwData.attrs.width = dimensions.width.toString();
+ mwData.attrs.height = dimensions.height.toString();
+ mwData.attrs.zoom = zoom.toString();
+};
+
+/**
+ * @inheritdoc
+ */
+ve.ui.MWMapsDialog.prototype.getReadyProcess = function ( data ) {
+ return ve.ui.MWMapsDialog.super.prototype.getReadyProcess.call( this,
data )
+ .next( function () {
+ return mw.loader.using( 'ext.kartographer.live' );
+ }, this );
+};
+
+/**
+ * @inheritdoc
+ */
+ve.ui.MWMapsDialog.prototype.getSetupProcess = function ( data ) {
+ data = data || {};
+ return ve.ui.MWMapsDialog.super.prototype.getSetupProcess.call( this,
data )
+ .next( function () {
+ var mwAttrs = this.selectedNode &&
this.selectedNode.getAttribute( 'mw' ).attrs || {};
+
+ this.actions.setMode( this.selectedNode ? 'edit' :
'insert' );
+ // this.mapTypeSelect.selectItem(
+ // this.mapTypeSelect.getItemFromData(
+ // ( this.selectedNode &&
this.selectedNode.getAttribute( 'mapType' ) ) || 'roadmap'
+ // )
+ // );
+
+ this.scalable = this.selectedNode ?
+ this.selectedNode.getScalable() :
+ ve.dm.MWMapsNode.static.createScalable( {
width: 400, height: 300 } );
+
+ this.setupMap();
+ this.dimensionsWidget.setDimensions(
this.scalable.getCurrentDimensions() );
+ //this.align.selectItemByData( mwAttrs.align ||
'center' );
+ }, this );
+};
+
+/**
+ * Setup the map control
+ */
+ve.ui.MWMapsDialog.prototype.setupMap = function () {
+ var style = 'osm-intl',
+ urlFormat = '/{z}/{x}/{y}.png',
+ mapServer = mw.config.get( 'wgKartographerMapServer' ),
+ mwAttrs = this.selectedNode && this.selectedNode.getAttribute(
'mw' ).attrs;
+
+ if ( !this.map ) {
+ this.map = L.map( this.$map[ 0 ] );
+
+ this.map.attributionControl.setPrefix( '' );
+ L.tileLayer( mapServer + '/' + style + urlFormat, {
+ maxZoom: 18,
+ attribution: 'Wikimedia maps beta | Map data © <a
href="http://openstreetmap.org/copyright">OpenStreetMap contributors</a>'
+ } ).addTo( this.map );
+
+ // var switcherControl = new OpenLayers.Control.LayerSwitcher();
+ // this.map.addControl( switcherControl );
+ // switcherControl.maximizeControl();
+
+ }
+
+ if ( mwAttrs ) {
+ this.map.setView( [ +mwAttrs.latitude, +mwAttrs.longitude ],
+mwAttrs.zoom );
+ } else {
+ this.map.setView( [ 0, 0 ], 2 );
+ }
+ // this.map.setMapTypeId(
this.mapTypeSelect.getSelectedItem().getData() );
+};
+
+/**
+ * @inheritdoc
+ */
+ve.ui.MWMapsDialog.prototype.getTeardownProcess = function ( data ) {
+ return ve.ui.MWMapsDialog.super.prototype.getTeardownProcess.call(
this, data )
+ .first( function () {
+ this.dimensionsWidget.clear();
+ }, this );
+};
+
+/* Registration */
+
+ve.ui.windowFactory.register( ve.ui.MWMapsDialog );
diff --git a/modules/ve-maps/ve.ui.MWMapsTool.js
b/modules/ve-maps/ve.ui.MWMapsTool.js
new file mode 100644
index 0000000..f5e0942
--- /dev/null
+++ b/modules/ve-maps/ve.ui.MWMapsTool.js
@@ -0,0 +1,46 @@
+/*!
+ * VisualEditor MediaWiki UserInterface gallery tool class.
+ *
+ * @copyright 2011-2015 VisualEditor Team and others; see AUTHORS.txt
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * MediaWiki UserInterface gallery tool.
+ *
+ * @class
+ * @extends ve.ui.FragmentWindowTool
+ * @constructor
+ * @param {OO.ui.ToolGroup} toolGroup
+ * @param {Object} [config] Configuration options
+ */
+ve.ui.MWMapsDialogTool = function VeUiMWMapsDialogTool() {
+ ve.ui.MWMapsDialogTool.super.apply( this, arguments );
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ui.MWMapsDialogTool, ve.ui.FragmentWindowTool );
+
+/* Static properties */
+
+ve.ui.MWMapsDialogTool.static.name = 'mwMaps';
+ve.ui.MWMapsDialogTool.static.group = 'object';
+ve.ui.MWMapsDialogTool.static.icon = 'map';
+ve.ui.MWMapsDialogTool.static.title = 'Map';
+ //OO.ui.deferMsg( 'visualeditor-mwmapsdialog-title' );
+ve.ui.MWMapsDialogTool.static.modelClasses = [ ve.dm.MWMapsNode ];
+ve.ui.MWMapsDialogTool.static.commandName = 'mwMaps';
+
+/* Registration */
+
+ve.ui.toolFactory.register( ve.ui.MWMapsDialogTool );
+
+/* Commands */
+
+ve.ui.commandRegistry.register(
+ new ve.ui.Command(
+ 'mwMaps', 'window', 'open',
+ { args: [ 'mwMaps' ], supportedSelections: [ 'linear' ] }
+ )
+);
--
To view, visit https://gerrit.wikimedia.org/r/262448
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I02e8297adfe986ca7744aa4b2b5c8960b0866715
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/Kartographer
Gerrit-Branch: master
Gerrit-Owner: Esanders <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits