jenkins-bot has submitted this change and it was merged.
Change subject: Render Vega specifications inside VisualEditor
......................................................................
Render Vega specifications inside VisualEditor
* Declared a new MWGraphNode, which listens for <graph> tags in wiki pages
* Renders Vega inside based on the JSON contained within the tag
Bug: T99936
Change-Id: I66ff1d3574813daea22274777261b02d8b18b513
---
M .jshintrc
A Graph.hooks.php
M Gruntfile.js
M extension.json
M i18n/en.json
M i18n/qqq.json
A modules/ve-graph/ve.ce.MWGraphNode.js
A modules/ve-graph/ve.dm.MWGraphNode.js
8 files changed, 277 insertions(+), 7 deletions(-)
Approvals:
Mooeypoo: Looks good to me, approved
jenkins-bot: Verified
diff --git a/.jshintrc b/.jshintrc
index 10bb722..c198255 100644
--- a/.jshintrc
+++ b/.jshintrc
@@ -2,7 +2,6 @@
// Enforcing
"bitwise": true,
"eqeqeq": true,
- "es3": true,
"freeze": true,
"latedef": true,
"noarg": true,
@@ -11,12 +10,17 @@
"unused": true,
"strict": false,
+ // Relaxing
+ "es5": false,
+
// Environment
"browser": true,
"jquery": true,
"globals": {
- "mediaWiki": true,
- "vg": true
+ "mediaWiki": false,
+ "OO": false,
+ "ve": false,
+ "vg": false
}
}
diff --git a/Graph.hooks.php b/Graph.hooks.php
new file mode 100644
index 0000000..4a37c92
--- /dev/null
+++ b/Graph.hooks.php
@@ -0,0 +1,47 @@
+<?php
+/**
+ * Graph extension Hooks
+ *
+ * @file
+ * @ingroup Extensions
+ */
+
+class GraphHooks {
+ /**
+ * Conditionally register the ext.graph.VisualEditor module if
VisualEditor
+ * has been loaded
+ *
+ * @param ResourceLoader $resourceLoader
+ * @return boolean true
+ */
+ public static function onResourceLoaderRegisterModules( ResourceLoader
&$resourceLoader ) {
+ $resourceModules = $resourceLoader->getConfig()->get(
'ResourceModules' );
+
+ $graphModuleTemplate = array(
+ 'localBasePath' => __DIR__,
+ 'remoteExtPath' => 'Graph'
+ );
+
+ $addModules = array(
+ 'ext.graph.visualEditor' => $graphModuleTemplate +
array(
+ 'scripts' => array(
+ 'modules/ve-graph/ve.dm.MWGraphNode.js',
+ 'modules/ve-graph/ve.ce.MWGraphNode.js'
+ ),
+ 'dependencies' => array(
+ 'ext.visualEditor.mwcore',
+ 'ext.graph'
+ ),
+ 'messages' => array(
+ 'graph-ve-no-spec'
+ )
+ )
+ );
+
+ if ( isset( $resourceModules[ 'ext.visualEditor.mwcore' ] ) ||
$resourceLoader->isModuleRegistered( 'ext.visualEditor.mwcore' ) ) {
+ $resourceLoader->register( $addModules );
+ }
+
+ return true;
+ }
+}
diff --git a/Gruntfile.js b/Gruntfile.js
index e692d27..e8e5d84 100644
--- a/Gruntfile.js
+++ b/Gruntfile.js
@@ -20,7 +20,8 @@
jshintrc: true
},
all: [
- 'js/*.js'
+ 'js/*.js',
+ 'modules/ve-graph/*.js'
]
},
jscs: {
diff --git a/extension.json b/extension.json
index a142778..7ee5283 100644
--- a/extension.json
+++ b/extension.json
@@ -15,7 +15,8 @@
},
"AutoloadClasses": {
"Graph\\Singleton": "Graph.body.php",
- "Graph\\Content": "Graph.body.php"
+ "Graph\\Content": "Graph.body.php",
+ "GraphHooks": "Graph.hooks.php"
},
"ResourceModules": {
"ext.graph": {
@@ -59,8 +60,14 @@
],
"ParserAfterParse": [
"Graph\\Singleton::onParserAfterParse"
+ ],
+ "ResourceLoaderRegisterModules": [
+ "GraphHooks::onResourceLoaderRegisterModules"
]
},
+ "VisualEditorPluginModules": [
+ "ext.graph.visualEditor"
+ ],
"config": {
"GraphDataDomains": [],
"GraphUrlBlacklist": false,
diff --git a/i18n/en.json b/i18n/en.json
index 5401583..2a8a457 100644
--- a/i18n/en.json
+++ b/i18n/en.json
@@ -5,5 +5,6 @@
"Yuri Astrakhan"
]
},
- "graph-desc": "Allows <graph> tags or entire pages to become
[http://trifacta.github.io/vega/ Vega]-based graphs"
+ "graph-desc": "Allows <graph> tags or entire pages to become
[http://trifacta.github.io/vega/ Vega]-based graphs",
+ "graph-ve-no-spec": "No graph specification found"
}
diff --git a/i18n/qqq.json b/i18n/qqq.json
index 5f498bc..8d73ea5 100644
--- a/i18n/qqq.json
+++ b/i18n/qqq.json
@@ -5,5 +5,6 @@
"Mormegil"
]
},
- "graph-desc":
"{{desc|name=Graph|url=https://www.mediawiki.org/wiki/Extension:Graph}}"
+ "graph-desc":
"{{desc|name=Graph|url=https://www.mediawiki.org/wiki/Extension:Graph}}",
+ "graph-ve-no-spec": "Label to display on a graph node when no spec is
found"
}
diff --git a/modules/ve-graph/ve.ce.MWGraphNode.js
b/modules/ve-graph/ve.ce.MWGraphNode.js
new file mode 100644
index 0000000..b188fdc
--- /dev/null
+++ b/modules/ve-graph/ve.ce.MWGraphNode.js
@@ -0,0 +1,91 @@
+/*!
+ * VisualEditor ContentEditable MWGraphNode class.
+ *
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * ContentEditable MediaWiki graph node.
+ *
+ * @class
+ * @extends ve.ce.MWBlockExtensionNode
+ *
+ * @constructor
+ * @param {ve.dm.MWGraphNode} model Model to observe
+ * @param {Object} [config] Configuration options
+ */
+ve.ce.MWGraphNode = function VeCeMWGraphNode() {
+ // Parent constructor
+ ve.ce.MWGraphNode.super.apply( this, arguments );
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.ce.MWGraphNode, ve.ce.MWBlockExtensionNode );
+
+/* Static Properties */
+
+ve.ce.MWGraphNode.static.name = 'mwGraph';
+
+ve.ce.MWGraphNode.static.primaryCommandName = 'graph';
+
+/* Methods */
+
+/**
+ * @inheritdoc
+ */
+ve.ce.MWGraphNode.prototype.onSetup = function () {
+ // Parent method
+ ve.ce.MWGraphNode.super.prototype.onSetup.call( this );
+
+ // Events
+ this.getModel().connect( this, {
+ specChange: 'onSpecChange'
+ } );
+
+ // Initial rendering
+ this.renderGraph();
+};
+
+/**
+ * @inheritdoc
+ */
+ve.ce.MWGraphNode.prototype.onTeardown = function () {
+ // Parent method
+ ve.ce.MWGraphNode.super.prototype.onTeardown.call( this );
+
+ // Events
+ this.getModel().disconnect( this );
+};
+
+/**
+ * Render a Vega graph inside the node
+ *
+ * @private
+ */
+ve.ce.MWGraphNode.prototype.renderGraph = function () {
+ var element = this.$element[0],
+ spec = this.getModel().getSpec();
+
+ // Check if the spec is currently valid
+ if ( spec !== null ) {
+ vg.parse.spec( spec, function ( chart ) {
+ chart( { el: element } ).update();
+ } );
+ } else {
+ $( element ).text( ve.msg( 'graph-ve-no-spec' ) );
+ }
+};
+
+/**
+ * React to specification model update
+ *
+ * @private
+ */
+ve.ce.MWGraphNode.prototype.onSpecChange = function () {
+ this.renderGraph();
+};
+
+/* Registration */
+
+ve.ce.nodeFactory.register( ve.ce.MWGraphNode );
diff --git a/modules/ve-graph/ve.dm.MWGraphNode.js
b/modules/ve-graph/ve.dm.MWGraphNode.js
new file mode 100644
index 0000000..2202a85
--- /dev/null
+++ b/modules/ve-graph/ve.dm.MWGraphNode.js
@@ -0,0 +1,118 @@
+/*!
+ * VisualEditor DataModel MWGraphNode class.
+ *
+ * @license The MIT License (MIT); see LICENSE.txt
+ */
+
+/**
+ * DataModel MediaWiki graph node.
+ *
+ * @class
+ * @extends ve.dm.MWBlockExtensionNode
+ *
+ * @constructor
+ * @param {Object} [element]
+ */
+ve.dm.MWGraphNode = function VeDmMWGraphNode() {
+ var mw, extsrc;
+
+ // Parent constructor
+ ve.dm.MWGraphNode.super.apply( this, arguments );
+
+ // Properties
+ this.spec = null;
+
+ // Initialize specificiation
+ mw = this.getAttribute( 'mw' );
+ extsrc = ve.getProp( mw, 'body', 'extsrc' );
+
+ if ( extsrc !== undefined ) {
+ this.setSpecFromString( extsrc );
+ }
+};
+
+/* Inheritance */
+
+OO.inheritClass( ve.dm.MWGraphNode, ve.dm.MWBlockExtensionNode );
+
+/* Static Members */
+
+ve.dm.MWGraphNode.static.name = 'mwGraph';
+
+ve.dm.MWGraphNode.static.tagName = 'graph';
+
+ve.dm.MWGraphNode.static.extensionName = 'graph';
+
+/* Events */
+
+/**
+ * @event specChange
+ *
+ * Change when the specification object is updated
+ *
+ * @param {Object} The new specification object
+ */
+
+/* Static Methods */
+
+/**
+ * Parses a spec string and returns its object representation.
+ *
+ * @param {string} str The spec string to validate
+ * @return {Object|null} The object specification if the parsing was
successful, null otherwise
+ */
+ve.dm.MWGraphNode.static.parseSpecString = function ( str ) {
+ try {
+ return JSON.parse( str );
+ } catch ( err ) {
+ return null;
+ }
+};
+
+/* Methods */
+
+/**
+ * Get the specification string
+ *
+ * @return {string} The specification JSON string
+ */
+ve.dm.MWGraphNode.prototype.getSpecString = function () {
+ return JSON.stringify( this.spec, null, '\t' );
+};
+
+/**
+ * Get the parsed JSON specification
+ *
+ * @return {Object} The specification object
+ */
+ve.dm.MWGraphNode.prototype.getSpec = function () {
+ return this.spec;
+};
+
+/**
+ * Update the spec with new parameters
+ *
+ * @param {Object} params The new parameters to be updated in the spec
+ * @fires specChange
+ */
+ve.dm.MWGraphNode.prototype.updateSpec = function ( params ) {
+ this.spec = $.extend( {}, this.spec, params );
+
+ this.emit( 'specChange', this.spec );
+};
+
+/**
+ * Set the specification from a stringified version
+ *
+ * @param {string} str The new specification JSON string
+ * @fires specChange
+ */
+ve.dm.MWGraphNode.prototype.setSpecFromString = function ( str ) {
+ this.spec = ve.dm.MWGraphNode.static.parseSpecString( str );
+
+ this.emit( 'specChange', this.spec );
+};
+
+/* Registration */
+
+ve.dm.modelRegistry.register( ve.dm.MWGraphNode );
--
To view, visit https://gerrit.wikimedia.org/r/215668
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: merged
Gerrit-Change-Id: I66ff1d3574813daea22274777261b02d8b18b513
Gerrit-PatchSet: 7
Gerrit-Project: mediawiki/extensions/Graph
Gerrit-Branch: master
Gerrit-Owner: Ferdbold <[email protected]>
Gerrit-Reviewer: Ferdbold <[email protected]>
Gerrit-Reviewer: Jforrester <[email protected]>
Gerrit-Reviewer: Krinkle <[email protected]>
Gerrit-Reviewer: Legoktm <[email protected]>
Gerrit-Reviewer: Mooeypoo <[email protected]>
Gerrit-Reviewer: Mvolz <[email protected]>
Gerrit-Reviewer: Siebrand <[email protected]>
Gerrit-Reviewer: jenkins-bot <>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits