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 &copy; <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

Reply via email to