Karima Rafes has uploaded a new change for review.
https://gerrit.wikimedia.org/r/75326
Change subject: Export table to CSV
......................................................................
Export table to CSV
Change-Id: I9fd6b3b1ad00a45910b7f90018b4849b8f7d278f
---
M LinkedWiki.php
A js/table2CSV.js
A test/README
A test/step_definitions/CSV_steps.rb
M test/step_definitions/sparql_steps.rb
A test/support/pages/LinkedwikiTableBasic.rb
A test/table2CSV.feature
A test/tests.sh
8 files changed, 343 insertions(+), 13 deletions(-)
git pull ssh://gerrit.wikimedia.org:29418/mediawiki/extensions/LinkedWiki
refs/changes/26/75326/1
diff --git a/LinkedWiki.php b/LinkedWiki.php
index cb9a842..377e969 100644
--- a/LinkedWiki.php
+++ b/LinkedWiki.php
@@ -33,6 +33,20 @@
'author' => array( '[http://www.mediawiki.org/wiki/User:Karima_Rafes Karima
Rafes]' )
);
+$linkedWikiTpl = array(
+ 'localBasePath' => dirname( __FILE__ ) . '/js',
+ 'remoteExtPath' => 'LinkedWiki/js',
+ 'group' => 'ext.LinkedWiki',
+);
+
+$wgResourceModules += array(
+ /* Third-party modules */
+
+ 'ext.LinkedWiki.table2CSV' => $linkedWikiTpl + array(
+ 'scripts' => 'table2CSV.js',
+ ),
+);
+
//Paths
$wgLinkedWikiPath = dirname(__FILE__);
$wgLinkedWikiClassesPath = $wgLinkedWikiPath . "/class";
@@ -91,6 +105,9 @@
function efSparqlParserFunction_Render( $parser) {
//global
$wgLinkedWikiLocalEndPoint,$wgLinkedWikiEndPoint,$wgLinkedWikiGraphWiki;
+ global $wgOut;
+ $wgOut->addModules( 'ext.LinkedWiki.table2CSV' );
+
$args = func_get_args(); // $parser, $param1 = '', $param2 = ''
$countArgs = count($args);
$query = isset($args[1])? urldecode($args[1]) : "";
@@ -125,7 +142,7 @@
if($templates != ""){
return
efSparqlParserFunction_array($query,$endpoint,$classHeaders ,$headers ,
$templates,$footer , $debug);
}else{
- return
efSparqlParserFunction_simple($query,$endpoint,$classHeaders,$headers,$footer,
$debug);
+ return
efSparqlParserFunction_simpleHTML($query,$endpoint,$classHeaders,$headers,$footer,
$debug);
}
}
}else {
@@ -311,7 +328,7 @@
return array($str, 'noparse' => false, 'isHTML' => false);
}
-
+/*
function efSparqlParserFunction_simple( $querySparqlWiki,$endpoint
,$classHeaders = '',$headers = '',$footer = '', $debug = null){
$specialC = array("'");
$replaceC = array("'");
@@ -396,6 +413,98 @@
}
return array($str, 'noparse' => false, 'isHTML' => false);
+}*/
+
+function efSparqlParserFunction_simpleHTML( $querySparqlWiki,$endpoint
,$classHeaders = '',$headers = '',$footer = '', $debug = null){
+ $specialC = array("'");
+ $replaceC = array("'");
+ $querySparql = str_replace($specialC ,$replaceC , $querySparqlWiki);
+
+ $str = "";
+ $sp = new Endpoint($endpoint);
+ $rs = $sp->query($querySparqlWiki);
+ $errs = $sp->getErrors();
+ if ($errs) {
+ $strerr = "";
+ foreach ($errs as $err) {
+ $strerr .= "'''Error #sparql :". $err ."'''<br/>";
+ }
+ return $strerr;
+ }
+
+ $lignegrise = false;
+ $variables = $rs['result']['variables'];
+ $str = "<table class='wikitable sortable'>\n";
+ if( $headers !='' ){
+ $TableTitleHeaders = explode(",",$headers);
+ $TableClassHeaders = explode(",",$classHeaders);
+ $classStr = "";
+ $lineTD = "";
+ for ($i = 0; $i < count($TableClassHeaders) ; $i++) {
+ if(!isset($TableClassHeaders[$i]) ||
$TableClassHeaders[$i] == ""){
+ $classStr = "";
+ }else{
+ $classStr = " class=\"".$TableClassHeaders[$i]
. "\"";
+ }
+ $TableTitleHeaders[$i] = "<th".$classStr.">" .
$TableTitleHeaders[$i]."</th>";
+ }
+ $str .= "<tr>";
+ $str .= implode("\n",$TableTitleHeaders );
+ $str .= "</tr>\n";
+ }else{
+ $TableClassHeaders = explode(",",$classHeaders);
+ $classStr = "";
+ for ($i = 0; $i < count($variables) ; $i++) {
+ if(!isset($TableClassHeaders[$i]) ||
$TableClassHeaders[$i] == "")
+ $classStr = "";
+ else
+ $classStr = " class=\"".$TableClassHeaders[$i] . "\"";
+ $TableTitleHeaders[$i] =
"<th".$classStr.">".$variables[$i]."</th>";
+ }
+
+ $str .= "<tr>\n";
+ $str .= implode("\n",$TableTitleHeaders );
+ $str .= "</tr>\n";
+ }
+
+
+ foreach ( $rs['result']['rows'] as $row) {
+
+ $str .= "<tr";
+ if($lignegrise)
+ $str .= " bgcolor=\"#f5f5f5\" ";
+ $str .= ">\n";
+ $lignegrise = !$lignegrise;
+ foreach ( $variables as $variable) {
+ $str .= "<td>";
+
+ if($row[$variable." type"] == "uri" ){
+ $str .=
efSparqlParserFunction_uri2Link($row[$variable]) ;
+ }else{
+ $str .= $row[$variable] ;
+ }
+ $str .= "</td>\n";
+ }
+ $str .= "</tr>\n";
+ }
+
+ if($footer != "NO"){
+ $str .= "<tr style=\"font-size:80%\" align=\"right\">\n";
+ $str .= "<td colspan=\"".count($variables)."\">".
efSparqlParserFunction_footerHTML($rs['query_time'],$querySparqlWiki,$endpoint
,$classHeaders,$headers)."</td>\n";
+ $str .= "</tr>\n";
+ }
+
+ $str .= "</table>\n";
+
+ if ($debug != null && $debug == "YES"){
+ $str .= "INPUT WIKI : ".$querySparqlWiki."\n";
+ $str .= "Query : ".$querySparql."\n";
+ $str .= print_r($rs, true);
+ $str .= print_r($rs, true);
+ return array("<pre>".$str."</pre>",'noparse' => true, 'isHTML'
=> false);
+ }
+
+ return array($str, 'noparse' => false, 'isHTML' => true);
}
function efSparqlParserFunction_tableCell( $querySparqlWiki,$endpoint ,$debug
= null){
@@ -447,10 +556,30 @@
$today = date(wfMessage( 'linkedwiki-date' )->text());
return $today ." -- [{{fullurl:{{FULLPAGENAME}}|action=purge}}
".wfMessage( 'linkedwiki-refresh' )->text()."] -- ".
wfMessage( 'linkedwiki-durate' )->text()." :".
- round($duration, 3) ."s";
+ round($duration, 3) ."s" ;
//"Version :
[{{canonicalurl:Special:Specialexportcsv}}?query={{urlencode:$querySparqlWiki}}&$endpoint={{urlencode:$querySparqlWiki}}&classHeaders={{urlencode:$querySparqlWiki}}&headers={{urlencode:$querySparqlWiki}}
CSV] ";
}
+function
efSparqlParserFunction_footerHTML($duration,$querySparqlWiki,$endpoint
,$classHeaders = '',$headers = ''){
+ global $wgRequest;
+ $today = date(wfMessage( 'linkedwiki-date' )->text());
+
+ $subject = $wgRequest->getRequestURL();
+$url ="";
+$pattern = '/\?.*(title=[^&]*).*$/';
+if(preg_match($pattern, $subject) == 1)
+ $url = preg_replace($pattern, "?\${1}&action=purge",$subject) ;
+ else
+$url = $subject . "?action=purge";
+
+
+ //$url = preg_replace( '/(\?[^\?]*$)/i',
"",$wgRequest->getRequestURL()) . "?action=purge";
+ //$url = $wgRequest->getRequestURL() . "?action=purge";
+ return $today ." -- <a href=\"".$url."\">".wfMessage(
'linkedwiki-refresh' )->text()."</a> -- ".
+ wfMessage( 'linkedwiki-durate' )->text()." :".
+ round($duration, 3) ."s -- <a class=\"csv\" style=\"cursor: pointer;\"
>CSV</a>";
+ }
+
function efSparqlParserFunction_uri2Link($uri,$nowiki = false){
//TODO : $title ??? CLEAN ?
global $wgServer;
diff --git a/js/table2CSV.js b/js/table2CSV.js
new file mode 100644
index 0000000..b520a18
--- /dev/null
+++ b/js/table2CSV.js
@@ -0,0 +1,103 @@
+jQuery.fn.table2CSV = function(options) {
+ var options = jQuery.extend({
+ separator: ',',
+ header: [],
+ delivery: 'popup' // popup, value
+ },
+ options);
+
+ var csvData = [];
+ var headerArr = [];
+ var el = this;
+
+ //header
+ var numCols = options.header.length;
+ var tmpRow = []; // construct header avalible array
+
+ if (numCols > 0) {
+ for (var i = 0; i < numCols; i++) {
+ tmpRow[tmpRow.length] = formatData(options.header[i]);
+ }
+ } else {
+ $(el).filter(':visible').find('th').each(function() {
+ if ($(this).css('display') != 'none') tmpRow[tmpRow.length] =
formatData($(this).html());
+ });
+ }
+
+ row2CSV(tmpRow);
+
+ // actual data
+ $(el).find('tr').each(function() {
+ var tmpRow = [];
+ $(this).filter(':visible').find('td').each(function() {
+ if ($(this).css('display') != 'none') tmpRow[tmpRow.length] =
formatData($(this).html());
+ });
+ row2CSV(tmpRow);
+ });
+ if (options.delivery == 'popup') {
+ var mydata = csvData.join('\n');
+ return popup(mydata);
+ } else {
+ var mydata = csvData.join('\n');
+ return mydata;
+ }
+
+ function row2CSV(tmpRow) {
+ var tmp = tmpRow.join('') // to remove any blank rows
+ // alert(tmp);
+ if (tmpRow.length > 0 && tmp != '') {
+ var mystr = tmpRow.join(options.separator);
+ csvData[csvData.length] = mystr;
+ }
+ }
+ function formatData(input) {
+ // replace " with “
+ var regexp = new RegExp(/["]/g);
+ var output = input.replace(regexp, "“");
+ //HTML
+ var regexp = new RegExp(/\<[^\<]+\>/g);
+ var output = output.replace(regexp, "");
+ if (output == "") return '';
+ return '"' + output + '"';
+ }
+ function popup(data) {
+ var generator = window.open('', 'csv', 'height=400,width=600');
+ generator.document.write('<html><head><title>CSV</title>');
+ generator.document.write('</head><body >');
+ generator.document.write('<textArea cols=70 rows=15 wrap="off" >');
+ generator.document.write(data);
+ generator.document.write('</textArea>');
+ generator.document.write('</body></html>');
+ generator.document.close();
+ return true;
+ }
+};
+
+$( function () {
+ // This code must not be executed before the document is loaded.
+
+ //$("div").css("border","9px solid purple");
+
+ $('table').each(function() {
+ var $table = $(this);
+ var $l = $table.find(".csv");
+ $l.click(function() {
+ var csv = $table.table2CSV({delivery:'value'});
+ window.location.href = 'data:text/csv;charset=UTF-8,'
+ + encodeURIComponent(csv);
+ });
+
+//$('#example1').table2CSV({
+
+//separator : ';',
+
+//delivery:'value',
+
+//header:['prefix','Employee Name','Contact']
+
+//}));
+
+
+ });
+
+});
diff --git a/test/README b/test/README
new file mode 100644
index 0000000..89e1455
--- /dev/null
+++ b/test/README
@@ -0,0 +1,14 @@
+== Tests with browsertests ==
+
+You have :
+* insert the lines in browsertests/Gemfile :
+gem 'nokogiri'
+gem 'curb'
+gem 'fastercsv'
+* execute "bundle install" in browsertests
+* insert the lines in browsertests/features/support/env.rb :
+require 'nokogiri
+require 'curb'
+require 'fastercsv'
+* create the file browsertests/config/secret.yml and insert
"mediawiki_password: vagrant"
+* insert the user in the wiki of tests : Selenium user / vagrant
diff --git a/test/step_definitions/CSV_steps.rb
b/test/step_definitions/CSV_steps.rb
new file mode 100644
index 0000000..5ba9102
--- /dev/null
+++ b/test/step_definitions/CSV_steps.rb
@@ -0,0 +1,22 @@
+When(/^I click link export CSV$/) do
+ on(LinkedwikiTableBasic).CSV
+end
+
+When(/^I click link refresh$/) do
+ on(LinkedwikiTableBasic).refresh
+end
+
+#When /^I confirm popup$/ do
+# @browser.driver.browser.switch_to.alert.accept
+#end
+
+#When /^I dismiss popup$/ do
+# @browser.driver.browser.switch_to.alert.dismiss
+#end
+
+#Then(/^file CSV should be there:$/) do |table|
+ # table is a Cucumber::Ast::Table
+ # FasterCSV.foreach(@browser.html) do |row|
+ # puts row[0]
+ # end
+#end
diff --git a/test/step_definitions/sparql_steps.rb
b/test/step_definitions/sparql_steps.rb
index 9d304c1..64f17ad 100644
--- a/test/step_definitions/sparql_steps.rb
+++ b/test/step_definitions/sparql_steps.rb
@@ -1,14 +1,14 @@
-#When(/^I enter the wikitext:$/) do |wikiText|
-# on(EditPage).article_text = wikiText
-#end
+When(/^I enter the wikitext:$/) do |wikiText|
+ on(EditPage).article_text = wikiText
+end
-#Then(/^table should be there:$/) do |table|
-# nodesTR = Nokogiri::HTML(@browser.html).css(".wikitable tr")
-# tableResult = nodesTR.map {|tr| tr.css("th,td").map {|cell|
cell.text.strip}}
-## p tableResult
-## p table.raw()
-# table.diff!(tableResult)
-#end
+Then(/^table should be there:$/) do |table|
+ nodesTR = Nokogiri::HTML(@browser.html).css(".wikitable tr")
+ tableResult = nodesTR.map {|tr| tr.css("th,td").map {|cell|
cell.text.strip}}
+# p tableResult
+# p table.raw()
+ table.diff!(tableResult)
+end
Given /^I has a empty graph ([^ ]*) in the triplestore ([^ ]*)$/ do
|graph,endpoint|
c = Curl::Easy.http_delete("#{endpoint}/data/?graph=#{graph}")
diff --git a/test/support/pages/LinkedwikiTableBasic.rb
b/test/support/pages/LinkedwikiTableBasic.rb
new file mode 100644
index 0000000..e44f82d
--- /dev/null
+++ b/test/support/pages/LinkedwikiTableBasic.rb
@@ -0,0 +1,11 @@
+require 'page-object'
+
+class LinkedwikiTableBasic
+ include PageObject
+
+ include URL
+ page_url URL.url('<%=params[:page_name]%>')
+
+ a(:CSV, text: 'CSV')
+ a(:refresh, text: 'Refresh')
+end
diff --git a/test/table2CSV.feature b/test/table2CSV.feature
new file mode 100644
index 0000000..df87e09
--- /dev/null
+++ b/test/table2CSV.feature
@@ -0,0 +1,44 @@
+@login
+Feature: table2CSV
+ Background:
+ Given I am logged in
+ And I has a empty graph http://example.com/data in the triplestore
http://192.168.1.100:8181
+ And I do this SPARQL query in the triplestore http://192.168.1.100:8181:
+ """
+PREFIX dc: <http://purl.org/dc/elements/1.1/>
+INSERT DATA
+{ GRAPH <http://example.com/data> {
+ <http://example/book1> dc:title "Book 1" ;
+ dc:creator "A.N.Other1" .
+ <http://example/book2> dc:title "Book 2" ;
+ dc:creator "A.N.Other2" .
+}}
+ """
+
+#Check export CSV
+Scenario: Export CSV file of LinkedWiki's table
+ Given I am at page that does not exist
+ When I click link Create source
+ And I enter the wikitext:
+ """
+{{#sparql:
+PREFIX dc: <http://purl.org/dc/elements/1.1/>
+SELECT ?title ?creator WHERE {
+GRAPH <http://example.com/data>
+{ ?x dc:title ?title ;
+ dc:creator ?creator .
+}
+} ORDER BY ?title ?creator
+|endpoint=http://192.168.1.100:8181/sparql/
+}}
+ """
+ And I click Save page button
+ And I click link refresh
+ And I click link export CSV
+ And I confirm popup
+ Then file CSV should be there:
+ | title | creator |
+ | Book 1 | A.N.Other1 |
+ | Book 2 | A.N.Other2 |
+
+
diff --git a/test/tests.sh b/test/tests.sh
new file mode 100755
index 0000000..73ebd3d
--- /dev/null
+++ b/test/tests.sh
@@ -0,0 +1,7 @@
+export MEDIAWIKI_URL=http://127.0.0.1:8080/wiki/
+
+cp -R * ~/git/browsertests/features/
+cd ~/git/browsertests
+bundle exec cucumber -v -b ./features/sparqlbasic.feature
+bundle exec cucumber -v -b ./features/table2CSV.feature
+cd ~/git/vagrant/mediawiki/extensions/LinkedWiki/test/
\ No newline at end of file
--
To view, visit https://gerrit.wikimedia.org/r/75326
To unsubscribe, visit https://gerrit.wikimedia.org/r/settings
Gerrit-MessageType: newchange
Gerrit-Change-Id: I9fd6b3b1ad00a45910b7f90018b4849b8f7d278f
Gerrit-PatchSet: 1
Gerrit-Project: mediawiki/extensions/LinkedWiki
Gerrit-Branch: master
Gerrit-Owner: Karima Rafes <[email protected]>
_______________________________________________
MediaWiki-commits mailing list
[email protected]
https://lists.wikimedia.org/mailman/listinfo/mediawiki-commits