1
0
mirror of https://github.com/gnosygnu/xowa.git synced 2026-03-02 03:49:30 +00:00

Res: Add resources from xowa_app_windows_64_v4.5.26.1810

This commit is contained in:
gnosygnu
2018-11-02 09:58:55 -04:00
parent a672fd8340
commit 5721913241
6057 changed files with 1156950 additions and 0 deletions

View File

@@ -0,0 +1,3 @@
// Back-compat: Export module as global
// XOWA: unused b/c module is not available
window.d3 = module.exports;

9554
res/bin/any/xowa/xtns/Graph/lib/d3.js vendored Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,505 @@
(function(f){if(typeof exports==="object"&&typeof module!=="undefined"){module.exports=f()}else if(typeof define==="function"&&define.amd){define([],f)}else{var g;if(typeof window!=="undefined"){g=window}else if(typeof global!=="undefined"){g=global}else if(typeof self!=="undefined"){g=self}else{g=this}g=(g.d3||(g.d3 = {}));g=(g.layout||(g.layout = {}));g.cloud = f()}})(function(){var define,module,exports;return (function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
// Word cloud layout by Jason Davies, https://www.jasondavies.com/wordcloud/
// Algorithm due to Jonathan Feinberg, http://static.mrfeinberg.com/bv_ch03.pdf
var dispatch = require("d3-dispatch").dispatch;
var cloudRadians = Math.PI / 180,
cw = 1 << 11 >> 5,
ch = 1 << 11;
module.exports = function() {
var size = [256, 256],
text = cloudText,
font = cloudFont,
fontSize = cloudFontSize,
fontStyle = cloudFontNormal,
fontWeight = cloudFontNormal,
rotate = cloudRotate,
padding = cloudPadding,
spiral = archimedeanSpiral,
words = [],
timeInterval = Infinity,
event = dispatch("word", "end"),
timer = null,
random = Math.random,
cloud = {},
canvas = cloudCanvas;
cloud.canvas = function(_) {
return arguments.length ? (canvas = functor(_), cloud) : canvas;
};
cloud.start = function() {
var contextAndRatio = getContext(canvas()),
board = zeroArray((size[0] >> 5) * size[1]),
bounds = null,
n = words.length,
i = -1,
tags = [],
data = words.map(function(d, i) {
d.text = text.call(this, d, i);
d.font = font.call(this, d, i);
d.style = fontStyle.call(this, d, i);
d.weight = fontWeight.call(this, d, i);
d.rotate = rotate.call(this, d, i);
d.size = ~~fontSize.call(this, d, i);
d.padding = padding.call(this, d, i);
return d;
}).sort(function(a, b) { return b.size - a.size; });
if (timer) clearInterval(timer);
timer = setInterval(step, 0);
step();
return cloud;
function step() {
var start = Date.now();
while (Date.now() - start < timeInterval && ++i < n && timer) {
var d = data[i];
d.x = (size[0] * (random() + .5)) >> 1;
d.y = (size[1] * (random() + .5)) >> 1;
cloudSprite(contextAndRatio, d, data, i);
if (d.hasText && place(board, d, bounds)) {
tags.push(d);
event.word(d);
if (bounds) cloudBounds(bounds, d);
else bounds = [{x: d.x + d.x0, y: d.y + d.y0}, {x: d.x + d.x1, y: d.y + d.y1}];
// Temporary hack
d.x -= size[0] >> 1;
d.y -= size[1] >> 1;
}
}
if (i >= n) {
cloud.stop();
event.end(tags, bounds);
}
}
}
cloud.stop = function() {
if (timer) {
clearInterval(timer);
timer = null;
}
return cloud;
};
function getContext(canvas) {
canvas.width = canvas.height = 1;
var ratio = Math.sqrt(canvas.getContext("2d").getImageData(0, 0, 1, 1).data.length >> 2);
canvas.width = (cw << 5) / ratio;
canvas.height = ch / ratio;
var context = canvas.getContext("2d");
context.fillStyle = context.strokeStyle = "red";
context.textAlign = "center";
return {context: context, ratio: ratio};
}
function place(board, tag, bounds) {
var perimeter = [{x: 0, y: 0}, {x: size[0], y: size[1]}],
startX = tag.x,
startY = tag.y,
maxDelta = Math.sqrt(size[0] * size[0] + size[1] * size[1]),
s = spiral(size),
dt = random() < .5 ? 1 : -1,
t = -dt,
dxdy,
dx,
dy;
while (dxdy = s(t += dt)) {
dx = ~~dxdy[0];
dy = ~~dxdy[1];
if (Math.min(Math.abs(dx), Math.abs(dy)) >= maxDelta) break;
tag.x = startX + dx;
tag.y = startY + dy;
if (tag.x + tag.x0 < 0 || tag.y + tag.y0 < 0 ||
tag.x + tag.x1 > size[0] || tag.y + tag.y1 > size[1]) continue;
// TODO only check for collisions within current bounds.
if (!bounds || !cloudCollide(tag, board, size[0])) {
if (!bounds || collideRects(tag, bounds)) {
var sprite = tag.sprite,
w = tag.width >> 5,
sw = size[0] >> 5,
lx = tag.x - (w << 4),
sx = lx & 0x7f,
msx = 32 - sx,
h = tag.y1 - tag.y0,
x = (tag.y + tag.y0) * sw + (lx >> 5),
last;
for (var j = 0; j < h; j++) {
last = 0;
for (var i = 0; i <= w; i++) {
board[x + i] |= (last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0);
}
x += sw;
}
delete tag.sprite;
return true;
}
}
}
return false;
}
cloud.timeInterval = function(_) {
return arguments.length ? (timeInterval = _ == null ? Infinity : _, cloud) : timeInterval;
};
cloud.words = function(_) {
return arguments.length ? (words = _, cloud) : words;
};
cloud.size = function(_) {
return arguments.length ? (size = [+_[0], +_[1]], cloud) : size;
};
cloud.font = function(_) {
return arguments.length ? (font = functor(_), cloud) : font;
};
cloud.fontStyle = function(_) {
return arguments.length ? (fontStyle = functor(_), cloud) : fontStyle;
};
cloud.fontWeight = function(_) {
return arguments.length ? (fontWeight = functor(_), cloud) : fontWeight;
};
cloud.rotate = function(_) {
return arguments.length ? (rotate = functor(_), cloud) : rotate;
};
cloud.text = function(_) {
return arguments.length ? (text = functor(_), cloud) : text;
};
cloud.spiral = function(_) {
return arguments.length ? (spiral = spirals[_] || _, cloud) : spiral;
};
cloud.fontSize = function(_) {
return arguments.length ? (fontSize = functor(_), cloud) : fontSize;
};
cloud.padding = function(_) {
return arguments.length ? (padding = functor(_), cloud) : padding;
};
cloud.random = function(_) {
return arguments.length ? (random = _, cloud) : random;
};
cloud.on = function() {
var value = event.on.apply(event, arguments);
return value === event ? cloud : value;
};
return cloud;
};
function cloudText(d) {
return d.text;
}
function cloudFont() {
return "serif";
}
function cloudFontNormal() {
return "normal";
}
function cloudFontSize(d) {
return Math.sqrt(d.value);
}
function cloudRotate() {
return (~~(Math.random() * 6) - 3) * 30;
}
function cloudPadding() {
return 1;
}
// Fetches a monochrome sprite bitmap for the specified text.
// Load in batches for speed.
function cloudSprite(contextAndRatio, d, data, di) {
if (d.sprite) return;
var c = contextAndRatio.context,
ratio = contextAndRatio.ratio;
c.clearRect(0, 0, (cw << 5) / ratio, ch / ratio);
var x = 0,
y = 0,
maxh = 0,
n = data.length;
--di;
while (++di < n) {
d = data[di];
c.save();
c.font = d.style + " " + d.weight + " " + ~~((d.size + 1) / ratio) + "px " + d.font;
var w = c.measureText(d.text + "m").width * ratio,
h = d.size << 1;
if (d.rotate) {
var sr = Math.sin(d.rotate * cloudRadians),
cr = Math.cos(d.rotate * cloudRadians),
wcr = w * cr,
wsr = w * sr,
hcr = h * cr,
hsr = h * sr;
w = (Math.max(Math.abs(wcr + hsr), Math.abs(wcr - hsr)) + 0x1f) >> 5 << 5;
h = ~~Math.max(Math.abs(wsr + hcr), Math.abs(wsr - hcr));
} else {
w = (w + 0x1f) >> 5 << 5;
}
if (h > maxh) maxh = h;
if (x + w >= (cw << 5)) {
x = 0;
y += maxh;
maxh = 0;
}
if (y + h >= ch) break;
c.translate((x + (w >> 1)) / ratio, (y + (h >> 1)) / ratio);
if (d.rotate) c.rotate(d.rotate * cloudRadians);
c.fillText(d.text, 0, 0);
if (d.padding) c.lineWidth = 2 * d.padding, c.strokeText(d.text, 0, 0);
c.restore();
d.width = w;
d.height = h;
d.xoff = x;
d.yoff = y;
d.x1 = w >> 1;
d.y1 = h >> 1;
d.x0 = -d.x1;
d.y0 = -d.y1;
d.hasText = true;
x += w;
}
var pixels = c.getImageData(0, 0, (cw << 5) / ratio, ch / ratio).data,
sprite = [];
while (--di >= 0) {
d = data[di];
if (!d.hasText) continue;
var w = d.width,
w32 = w >> 5,
h = d.y1 - d.y0;
// Zero the buffer
for (var i = 0; i < h * w32; i++) sprite[i] = 0;
x = d.xoff;
if (x == null) return;
y = d.yoff;
var seen = 0,
seenRow = -1;
for (var j = 0; j < h; j++) {
for (var i = 0; i < w; i++) {
var k = w32 * j + (i >> 5),
m = pixels[((y + j) * (cw << 5) + (x + i)) << 2] ? 1 << (31 - (i % 32)) : 0;
sprite[k] |= m;
seen |= m;
}
if (seen) seenRow = j;
else {
d.y0++;
h--;
j--;
y++;
}
}
d.y1 = d.y0 + seenRow;
d.sprite = sprite.slice(0, (d.y1 - d.y0) * w32);
}
}
// Use mask-based collision detection.
function cloudCollide(tag, board, sw) {
sw >>= 5;
var sprite = tag.sprite,
w = tag.width >> 5,
lx = tag.x - (w << 4),
sx = lx & 0x7f,
msx = 32 - sx,
h = tag.y1 - tag.y0,
x = (tag.y + tag.y0) * sw + (lx >> 5),
last;
for (var j = 0; j < h; j++) {
last = 0;
for (var i = 0; i <= w; i++) {
if (((last << msx) | (i < w ? (last = sprite[j * w + i]) >>> sx : 0))
& board[x + i]) return true;
}
x += sw;
}
return false;
}
function cloudBounds(bounds, d) {
var b0 = bounds[0],
b1 = bounds[1];
if (d.x + d.x0 < b0.x) b0.x = d.x + d.x0;
if (d.y + d.y0 < b0.y) b0.y = d.y + d.y0;
if (d.x + d.x1 > b1.x) b1.x = d.x + d.x1;
if (d.y + d.y1 > b1.y) b1.y = d.y + d.y1;
}
function collideRects(a, b) {
return a.x + a.x1 > b[0].x && a.x + a.x0 < b[1].x && a.y + a.y1 > b[0].y && a.y + a.y0 < b[1].y;
}
function archimedeanSpiral(size) {
var e = size[0] / size[1];
return function(t) {
return [e * (t *= .1) * Math.cos(t), t * Math.sin(t)];
};
}
function rectangularSpiral(size) {
var dy = 4,
dx = dy * size[0] / size[1],
x = 0,
y = 0;
return function(t) {
var sign = t < 0 ? -1 : 1;
// See triangular numbers: T_n = n * (n + 1) / 2.
switch ((Math.sqrt(1 + 4 * sign * t) - sign) & 3) {
case 0: x += dx; break;
case 1: y += dy; break;
case 2: x -= dx; break;
default: y -= dy; break;
}
return [x, y];
};
}
// TODO reuse arrays?
function zeroArray(n) {
var a = [],
i = -1;
while (++i < n) a[i] = 0;
return a;
}
function cloudCanvas() {
return document.createElement("canvas");
}
function functor(d) {
return typeof d === "function" ? d : function() { return d; };
}
var spirals = {
archimedean: archimedeanSpiral,
rectangular: rectangularSpiral
};
},{"d3-dispatch":2}],2:[function(require,module,exports){
(function (global, factory) {
typeof exports === 'object' && typeof module !== 'undefined' ? factory(exports) :
typeof define === 'function' && define.amd ? define(['exports'], factory) :
factory((global.dispatch = {}));
}(this, function (exports) { 'use strict';
function Dispatch(types) {
var i = -1,
n = types.length,
callbacksByType = {},
callbackByName = {},
type,
that = this;
that.on = function(type, callback) {
type = parseType(type);
// Return the current callback, if any.
if (arguments.length < 2) {
return (callback = callbackByName[type.name]) && callback.value;
}
// If a type was specified…
if (type.type) {
var callbacks = callbacksByType[type.type],
callback0 = callbackByName[type.name],
i;
// Remove the current callback, if any, using copy-on-remove.
if (callback0) {
callback0.value = null;
i = callbacks.indexOf(callback0);
callbacksByType[type.type] = callbacks = callbacks.slice(0, i).concat(callbacks.slice(i + 1));
delete callbackByName[type.name];
}
// Add the new callback, if any.
if (callback) {
callback = {value: callback};
callbackByName[type.name] = callback;
callbacks.push(callback);
}
}
// Otherwise, if a null callback was specified, remove all callbacks with the given name.
else if (callback == null) {
for (var otherType in callbacksByType) {
if (callback = callbackByName[otherType + type.name]) {
callback.value = null;
var callbacks = callbacksByType[otherType], i = callbacks.indexOf(callback);
callbacksByType[otherType] = callbacks.slice(0, i).concat(callbacks.slice(i + 1));
delete callbackByName[callback.name];
}
}
}
return that;
};
while (++i < n) {
type = types[i] + "";
if (!type || (type in that)) throw new Error("illegal or duplicate type: " + type);
callbacksByType[type] = [];
that[type] = applier(type);
}
function parseType(type) {
var i = (type += "").indexOf("."), name = type;
if (i >= 0) type = type.slice(0, i); else name += ".";
if (type && !callbacksByType.hasOwnProperty(type)) throw new Error("unknown type: " + type);
return {type: type, name: name};
}
function applier(type) {
return function() {
var callbacks = callbacksByType[type], // Defensive reference; copy-on-remove.
callback,
callbackValue,
i = -1,
n = callbacks.length;
while (++i < n) {
if (callbackValue = (callback = callbacks[i]).value) {
callbackValue.apply(this, arguments);
}
}
return that;
};
}
}
function dispatch() {
return new Dispatch(arguments);
}
dispatch.prototype = Dispatch.prototype; // allow instanceof
exports.dispatch = dispatch;
}));
},{}]},{},[1])(1)
});

View File

@@ -0,0 +1,697 @@
(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);var f=new Error("Cannot find module '"+o+"'");throw f.code="MODULE_NOT_FOUND",f}var l=n[o]={exports:{}};t[o][0].call(l.exports,function(e){var n=t[o][1][e];return s(n?n:e)},l,l.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o<r.length;o++)s(r[o]);return s})({1:[function(require,module,exports){
( function ( $, mw, vg ) {
'use strict';
/* global require */
var VegaWrapper = require( 'mw-graph-shared' );
// eslint-disable-next-line no-new
new VegaWrapper( {
datalib: vg.util,
useXhr: true,
isTrusted: true, // mw.config.get( 'wgGraphIsTrusted' ),
domains: '', // mw.config.get( 'wgGraphAllowedDomains' ),
domainMap: false,
logger: function ( warning ) {
mw.log.warn( warning );
},
parseUrl: function ( opt ) {
// Parse URL
var uri = {}; // new mw.Uri( opt.url );
// reduce confusion, only keep expected values
if ( uri.port ) {
uri.host += ':' + uri.port;
delete uri.port;
}
// If url begins with protocol:///... mark it as having relative host
if ( /^[a-z]+:\/\/\//.test( opt.url ) ) {
uri.isRelativeHost = true;
}
if ( uri.protocol ) {
// All other libs use trailing colon in the protocol field
uri.protocol += ':';
}
// Node's path includes the query, whereas pathname is without the query
// Standardizing on pathname
uri.pathname = uri.path;
delete uri.path;
return uri;
},
formatUrl: function ( uri, opt ) {
// Format URL back into a string
// Revert path into pathname
uri.path = uri.pathname;
delete uri.pathname;
if ( location.host.toLowerCase() === uri.host.toLowerCase() ) {
if ( !mw.config.get( 'wgGraphIsTrusted' ) ) {
// Only send this header when hostname is the same.
// This is broader than the same-origin policy,
// but playing on the safer side.
opt.headers = { 'Treat-as-Untrusted': 1 };
}
} else if ( opt.addCorsOrigin ) {
// All CORS api calls require origin parameter.
// It would be better to use location.origin,
// but apparently it's not universal yet.
uri.query.origin = location.protocol + '//' + location.host;
}
uri.protocol = VegaWrapper.removeColon( uri.protocol );
return uri.toString();
},
languageCode: 'en' // mw.config.get( 'wgUserLanguage' )
} );
/**
* Set up drawing canvas inside the given element and draw graph data
*
* @param {HTMLElement} element
* @param {Object|string} data graph spec
* @param {Function} [callback] function(error) called when drawing is done
*/
window.drawVegaGraph = function ( element, data, callback ) {
vg.parse.spec( data, function ( error, chart ) {
if ( !error ) {
chart( { el: element } ).update();
}
if ( callback ) {
callback( error );
}
} );
};
// mw.hook( 'wikipage.content' ).add( function ( $content ) {
var $content = $('#content');
var specs = {}; // mw.config.get( 'wgGraphSpecs' );
if ( !specs ) {
return;
}
$content.find( '.mw-graph.mw-graph-always' ).each( function () {
var graphId = $( this ).data( 'graph-id' );
if ( !specs.hasOwnProperty( graphId ) ) {
// mw.log.warn( graphId );
} else {
window.drawVegaGraph( this, specs[ graphId ], function ( error ) {
if ( error ) {
// mw.log.warn( error );
}
} );
}
} );
// } );
}( jQuery, null, vg ) );
},{"mw-graph-shared":3}],2:[function(require,module,exports){
'use strict';
/**
* Convert a list of domains into an object with a test method.
* equivalent regex: (any-subdomain)\.(wikipedia\.org|wikivoyage\.org|...)
*
* @param domains array of string domains
* @param allowSubdomains if true, allows any sub and sub-sub-* domains
* @returns {*}
*/
module.exports = function makeValidator(domains, allowSubdomains) {
if (!domains || domains.length === 0) return {
// Optimization - always return false
test: function () {
return false;
}
};
return new RegExp(
(allowSubdomains ? '^([^@/:]*\\.)?(' : '^(') +
domains
.map(function (s) {
return s.replace('.', '\\.');
})
.join('|') + ')$', 'i');
};
},{}],3:[function(require,module,exports){
'use strict';
/* global module */
var makeValidator = require('domain-validator'),
parseWikidataValue = require('wd-type-parser');
module.exports = VegaWrapper;
module.exports.removeColon = removeColon;
/**
* Utility function to remove trailing colon from a protocol
* @param {string} protocol
* @return {string}
*/
function removeColon(protocol) {
return protocol && protocol.length && protocol[protocol.length - 1] === ':'
? protocol.substring(0, protocol.length - 1) : protocol;
}
/**
* Shared library to wrap around vega code
* @param {Object} wrapperOpts Configuration options
* @param {Object} wrapperOpts.datalib Vega's datalib object
* @param {Object} wrapperOpts.datalib.load Vega's data loader
* @param {Function} wrapperOpts.datalib.load.loader Vega's data loader function
* @param {Function} wrapperOpts.datalib.extend similar to jquery's extend()
* @param {boolean} wrapperOpts.useXhr true if we should use XHR, false for node.js http loading
* @param {boolean} wrapperOpts.isTrusted true if the graph spec can be trusted
* @param {Object} wrapperOpts.domains allowed protocols and a list of their domains
* @param {Object} wrapperOpts.domainMap domain remapping
* @param {Function} wrapperOpts.logger
* @param {Function} wrapperOpts.parseUrl
* @param {Function} wrapperOpts.formatUrl
* @param {string} [wrapperOpts.languageCode]
* @constructor
*/
function VegaWrapper(wrapperOpts) {
var self = this;
// Copy all options into this object
self.objExtender = wrapperOpts.datalib.extend;
self.objExtender(self, wrapperOpts);
self.validators = {};
self.datalib.load.loader = function (opt, callback) {
var error = callback || function (e) { throw e; }, url;
try {
url = self.sanitizeUrl(opt); // enable override
} catch (err) {
error(err);
return;
}
// Process data response
var cb = function (error, data) {
return self.dataParser(error, data, opt, callback);
};
/*
if (self.useXhr) {
return self.datalib.load.xhr(url, opt, cb);
} else {
return self.datalib.load.http(url, opt, cb);
}
*/
return xo.xtns.graph.load_xowa(url, opt, cb);
};
self.datalib.load.sanitizeUrl = self.sanitizeUrl.bind(self);
// Prevent accidental use
self.datalib.load.file = alwaysFail;
if (self.useXhr) {
self.datalib.load.http = alwaysFail;
} else {
self.datalib.load.xhr = alwaysFail;
}
}
/**
* Check if host was listed in the allowed domains, normalize it, and get correct protocol
* @param {string} host
* @returns {Object}
*/
VegaWrapper.prototype.sanitizeHost = function sanitizeHost(host) {
// First, map the host
host = (this.domainMap && this.domainMap[host]) || host;
if (this.testHost('https:', host)) {
return {host: host, protocol: 'https:'};
} else if (this.testHost('http:', host)) {
return {host: host, protocol: 'http:'};
}
return undefined;
};
/**
* Test host against the list of allowed domains based on the protocol
* @param {string} protocol
* @param {string} host
* @returns {boolean}
*/
VegaWrapper.prototype.testHost = function testHost(protocol, host) {
if (!this.validators[protocol]) {
var domains = this._getProtocolDomains(protocol);
if (domains) {
this.validators[protocol] = makeValidator(domains, protocol === 'https:' || protocol === 'http:');
} else {
return false;
}
}
return this.validators[protocol].test(host);
};
/**
* Gets allowed domains for a given protocol. Assumes protocol ends with a ':'.
* Handles if this.domains's keys do not end in the ':'.
* @param {string} protocol
* @return {[]|false}
* @private
*/
VegaWrapper.prototype._getProtocolDomains = function _getProtocolDomains(protocol) {
return this.domains[protocol] || this.domains[removeColon(protocol)];
};
/**
* Validate and update urlObj to be safe for client-side and server-side usage
* @param {Object} opt passed by the vega loader, and will add 'graphProtocol' param
* @returns {boolean} true on success
*/
VegaWrapper.prototype.sanitizeUrl = function sanitizeUrl(opt) {
// In some cases we may receive a badly formed URL in a form customprotocol:https://...
opt.url = opt.url.replace(/^([a-z]+:)https?:\/\//, '$1//');
// XOWA: comment out URL parsing code as it relies on various unavailable MediaWiki functions; DATE:2018-03-13
// note that URL parsing will be done directly in Xograph.js
/*
var decodedPathname,
isRelativeProtocol = /^\/\//.test(opt.url),
urlParts = this.parseUrl(opt),
sanitizedHost = this.sanitizeHost(urlParts.host);
// if (!sanitizedHost) {
// throw new Error('URL hostname is not whitelisted: ' + opt.url);
// }
urlParts.host = sanitizedHost.host;
if (!urlParts.protocol) {
// node.js mode only - browser's url parser will always set protocol to current one
// Update protocol-relative URLs
urlParts.protocol = sanitizedHost.protocol;
isRelativeProtocol = true;
}
// Save original protocol to post-process the data
opt.graphProtocol = urlParts.protocol;
if (opt.type === 'open') {
// Trim the value here because mediawiki will do it anyway, so we might as well save on redirect
decodedPathname = decodeURIComponent(urlParts.pathname).trim();
switch (urlParts.protocol) {
case 'http:':
case 'https:':
// The default protocol for the open action is wikititle, so if isRelativeProtocol is set,
// we treat the whole pathname as title (without the '/' prefix).
if (!isRelativeProtocol) {
// If we get http:// and https:// protocol hardcoded, remove the '/wiki/' prefix instead
if (!/^\/wiki\/.+$/.test(decodedPathname)) {
throw new Error('wikititle: http(s) links must begin with /wiki/ prefix');
}
decodedPathname = decodedPathname.substring('/wiki'.length);
}
opt.graphProtocol = 'wikititle';
// fall-through
case 'wikititle:':
// wikititle:///My_page or wikititle://en.wikipedia.org/My_page
// open() at this point may only be used to link to a Wiki page, as it may be invoked
// without a click, thus potentially causing a privacy issue.
if (Object.keys(urlParts.query).length !== 0) {
throw new Error('wikititle: query parameters are not allowed');
}
if (!/^\/[^|]+$/.test(decodedPathname)) {
throw new Error('wikititle: invalid title');
}
urlParts.pathname = '/wiki/' + encodeURIComponent(decodedPathname.substring(1).replace(' ', '_'));
urlParts.protocol = sanitizedHost.protocol;
break;
default:
throw new Error('"open()" action only allows links with wikititle protocol, e.g. wikititle:///My_page');
}
} else {
switch (urlParts.protocol) {
case 'http:':
case 'https:':
if (!this.isTrusted) {
throw new Error('HTTP and HTTPS protocols are not supported for untrusted graphs.\n' +
'Use wikiraw:, wikiapi:, wikirest:, wikirawupload:, and other protocols.\n' +
'See https://www.mediawiki.org/wiki/Extension:Graph#External_data');
}
// keep the original URL
break;
case 'wikiapi:':
// wikiapi:///?action=query&list=allpages
// Call to api.php - ignores the path parameter, and only uses the query
urlParts.query = this.objExtender(urlParts.query, {format: 'json', formatversion: '2'});
urlParts.pathname = '/w/api.php';
urlParts.protocol = sanitizedHost.protocol;
opt.addCorsOrigin = true;
break;
case 'wikirest:':
// wikirest:///api/rest_v1/page/...
// Call to RESTbase api - requires the path to start with "/api/"
// The /api/... path is safe for GET requests
if (!/^\/api\//.test(urlParts.pathname)) {
throw new Error('wikirest: protocol must begin with the /api/ prefix');
}
// keep urlParts.query
// keep urlParts.pathname
urlParts.protocol = sanitizedHost.protocol;
break;
case 'wikiraw:':
case 'tabular:':
case 'map:':
// wikiraw:///MyPage/data
// Get content of a wiki page, where the path is the title
// of the page with an additional leading '/' which gets removed.
// Uses mediawiki api, and extract the content after the request
// Query value must be a valid MediaWiki title string, but we only ensure
// there is no pipe symbol, the rest is handled by the api.
decodedPathname = decodeURIComponent(urlParts.pathname);
if (!/^\/[^|]+$/.test(decodedPathname)) {
throw new Error(urlParts.protocol + ' invalid title');
}
if (urlParts.protocol === 'wikiraw:') {
urlParts.query = {
format: 'json',
formatversion: '2',
action: 'query',
prop: 'revisions',
rvprop: 'content',
titles: decodedPathname.substring(1)
};
} else {
urlParts.query = {
format: 'json',
formatversion: '2',
action: 'jsondata',
title: decodedPathname.substring(1)
};
if (urlParts.siteLanguage || this.languageCode) {
urlParts.query.uselang = urlParts.siteLanguage || this.languageCode;
}
}
urlParts.pathname = '/w/api.php';
urlParts.protocol = sanitizedHost.protocol;
opt.addCorsOrigin = true;
break;
case 'wikifile:':
// wikifile:///Einstein_1921.jpg
// Get an image for the graph, e.g. from commons, by using Special:Redirect
urlParts.pathname = '/wiki/Special:Redirect/file' + urlParts.pathname;
urlParts.protocol = sanitizedHost.protocol;
// keep urlParts.query
break;
case 'wikirawupload:':
// wikirawupload://upload.wikimedia.org/wikipedia/commons/3/3e/Einstein_1921.jpg
// Get an image for the graph, e.g. from commons
// This tag specifies any content from the uploads.* domain, without query params
this._validateExternalService(urlParts, sanitizedHost, opt.url);
urlParts.query = {};
// keep urlParts.pathname
break;
case 'wikidatasparql:':
// wikidatasparql:///?query=<QUERY>
// Runs a SPARQL query, converting it to
// https://query.wikidata.org/bigdata/namespace/wdq/sparql?format=json&query=...
this._validateExternalService(urlParts, sanitizedHost, opt.url);
if (!urlParts.query || !urlParts.query.query) {
throw new Error('wikidatasparql: missing query parameter in: ' + opt.url);
}
// Only keep the "query" parameter
urlParts.query = {query: urlParts.query.query};
urlParts.pathname = '/bigdata/namespace/wdq/sparql';
opt.headers = this.objExtender(opt.headers || {}, {'Accept': 'application/sparql-results+json'});
break;
case 'geoshape:':
case 'geoline:':
// geoshape:///?ids=Q16,Q30 or geoshape:///?query=...
// Get geoshapes data from OSM database by supplying Wikidata IDs
// https://maps.wikimedia.org/shape?ids=Q16,Q30
// 'geoline:' is an identical service, except that it returns lines instead of polygons
this._validateExternalService(urlParts, sanitizedHost, opt.url, 'geoshape:');
if (!urlParts.query || (!urlParts.query.ids && !urlParts.query.query)) {
throw new Error(opt.graphProtocol + ' missing ids or query parameter in: ' + opt.url);
}
// the query object is not modified
urlParts.pathname = '/' + removeColon(opt.graphProtocol);
break;
case 'mapsnapshot:':
// mapsnapshot:///?width=__&height=__&zoom=__&lat=__&lon=__ [&style=__]
// Converts it into a snapshot image request for Kartotherian:
// https://maps.wikimedia.org/img/{style},{zoom},{lat},{lon},{width}x{height}[@{scale}x].{format}
// (scale will be set to 2, and format to png)
if (!urlParts.query) {
throw new Error('mapsnapshot: missing required parameters');
}
validate(urlParts, 'width', 1, 4096);
validate(urlParts, 'height', 1, 4096);
validate(urlParts, 'zoom', 0, 22);
validate(urlParts, 'lat', -90, 90, true);
validate(urlParts, 'lon', -180, 180, true);
var query = urlParts.query;
if (query.style && !/^[-_0-9a-z]+$/.test(query.style)) {
throw new Error('mapsnapshot: if style is given, it must be letters/numbers/dash/underscores only');
}
// Uses the same configuration as geoshape service, so reuse settings
this._validateExternalService(urlParts, sanitizedHost, opt.url, 'geoshape:');
urlParts.pathname = '/img/' + (query.style || 'osm-intl') + ',' + query.zoom + ',' +
query.lat + ',' + query.lon + ',' + query.width + 'x' + query.height + '@2x.png';
urlParts.query = {}; // deleting it would cause errors in mw.Uri()
break;
default:
throw new Error('Unknown protocol ' + opt.url);
}
}
return this.formatUrl(urlParts, opt);
*/
return opt.url;
};
function validate(urlParts, name, min, max, isFloat) {
var value = urlParts.query[name];
if (value === undefined) {
throw new Error(urlParts.protocol + ' parameter ' + name + ' is not set');
}
if (!(isFloat ? /^-?[0-9]+\.?[0-9]*$/ : /^-?[0-9]+$/).test(value)) {
throw new Error(urlParts.protocol + ' parameter ' + name + ' is not a number');
}
value = isFloat ? parseFloat(value) : parseInt(value);
if (value < min || value > max) {
throw new Error(urlParts.protocol + ' parameter ' + name + ' is not valid');
}
}
VegaWrapper.prototype._validateExternalService = function _validateExternalService(urlParts, sanitizedHost, url, protocolOverride) {
var protocol = protocolOverride || urlParts.protocol,
domains = this._getProtocolDomains(protocol);
if (!domains) {
throw new Error(protocol + ': protocol is disabled: ' + url);
}
if (urlParts.isRelativeHost) {
urlParts.host = domains[0];
urlParts.protocol = this.sanitizeHost(urlParts.host).protocol;
} else {
urlParts.protocol = sanitizedHost.protocol;
}
if (!this.testHost(protocol, urlParts.host)) {
throw new Error(protocol + ': URL must either be relative (' + protocol + '///...), or use one of the allowed hosts: ' + url);
}
};
/**
* Performs post-processing of the data requested by the graph's spec
*/
VegaWrapper.prototype.dataParser = function dataParser(error, data, opt, callback) {
if (!error) {
try {
data = this.parseDataOrThrow(data, opt);
} catch (e) {
error = e;
}
}
if (error) data = undefined;
callback(error, data);
};
/**
* Parses the response from MW Api, throwing an error or logging warnings
*/
VegaWrapper.prototype.parseMWApiResponse = function parseMWApiResponse(data) {
data = JSON.parse(data);
if (data.error) {
throw new Error('API error: ' + JSON.stringify(data.error));
}
if (data.warnings) {
this.logger('API warnings: ' + JSON.stringify(data.warnings));
}
return data;
};
/**
* Performs post-processing of the data requested by the graph's spec, and throw on error
*/
VegaWrapper.prototype.parseDataOrThrow = function parseDataOrThrow(data, opt) {
switch (opt.xowa_protocol) { // XOWA: use opt.xowa_protocol
case 'wikiapi:':
data = this.parseMWApiResponse(data);
break;
case 'wikiraw:':
// XOWA: comment out call to MW API; Xograph will make call to xo_server; DATE:2018-03-13
/*
data = this.parseMWApiResponse(data);
try {
data = data.query.pages[0].revisions[0].content;
} catch (e) {
throw new Error('Page content not available ' + opt.url);
}
*/
break;
case null:
case 'tabular:':
case 'map:':
data = this.parseMWApiResponse(data).jsondata;
var metadata = [{
description: data.description,
license_code: data.license.code,
license_text: data.license.text,
license_url: data.license.url,
sources: data.sources
}];
if (opt.xowa_protocol === 'tabular:') {
var fields = data.schema.fields.map(function (v) {
return v.name;
});
data = {
meta: metadata,
fields: data.schema.fields,
data: data.data.map(function (v) {
var row = {}, i;
for (i = 0; i < fields.length; i++) {
// Need to copy nulls too -- Vega has no easy way to test for undefined
row[fields[i]] = v[i];
}
return row;
})
}
} else {
metadata[0].zoom = data.zoom;
metadata[0].latitude = data.latitude;
metadata[0].longitude = data.longitude;
data = {
meta: metadata,
data: data.data
};
}
break;
case 'wikidatasparql:':
data = JSON.parse(data);
if (!data.results || !Array.isArray(data.results.bindings)) {
throw new Error('SPARQL query result does not have "results.bindings"');
}
data = data.results.bindings.map(function (row) {
var key, result = {};
for (key in row) {
if (row.hasOwnProperty(key)) {
result[key] = parseWikidataValue(row[key]);
}
}
return result;
});
break;
}
return data;
};
/**
* Throw an error when called
*/
function alwaysFail() {
throw new Error('Disabled');
}
},{"domain-validator":2,"wd-type-parser":4}],4:[function(require,module,exports){
'use strict';
/* global module */
module.exports = parseWikidataValue;
/**
* Given a value object as returned from Wikidata Query Service, returns a simplified value
* @param {object} value Original object as sent by the Wikidata query service
* @param {string} value.type SPARQL data type (literal, uri)
* @param {string} value.datatype XMLSchema data type
* @param {*} value.value The actual value sent by the Wikidata query service
* @param {boolean=} ignoreUnknown if false, will return value.value even if it cannot be recognized
* @return {*}
*/
function parseWikidataValue(value, ignoreUnknown) {
var temp;
if (!value || !value.type || value.value === undefined) {
return undefined;
}
switch (value.type) {
case 'literal':
switch (value.datatype) {
case 'http://www.w3.org/2001/XMLSchema#double':
case 'http://www.w3.org/2001/XMLSchema#float':
case 'http://www.w3.org/2001/XMLSchema#decimal':
case 'http://www.w3.org/2001/XMLSchema#integer':
case 'http://www.w3.org/2001/XMLSchema#long':
case 'http://www.w3.org/2001/XMLSchema#int':
case 'http://www.w3.org/2001/XMLSchema#short':
case 'http://www.w3.org/2001/XMLSchema#nonNegativeInteger':
case 'http://www.w3.org/2001/XMLSchema#positiveInteger':
case 'http://www.w3.org/2001/XMLSchema#unsignedLong':
case 'http://www.w3.org/2001/XMLSchema#unsignedInt':
case 'http://www.w3.org/2001/XMLSchema#unsignedShort':
case 'http://www.w3.org/2001/XMLSchema#nonPositiveInteger':
case 'http://www.w3.org/2001/XMLSchema#negativeInteger':
temp = parseFloat(value.value);
if (temp.toString() === value.value) {
// use number only if it is fully round-tripable back to string
// TBD: this might be overcautios, and would cause more problems than solve
return temp;
}
break;
case 'http://www.opengis.net/ont/geosparql#wktLiteral':
// Point(-64.2 -36.62) -- (longitude latitude)
temp = /^Point\(([-0-9.]+) ([-0-9.]+)\)$/.exec(value.value);
if (temp) {
return [parseFloat(temp[1]), parseFloat(temp[2])];
}
break;
}
break;
case 'uri':
// "http://www.wikidata.org/entity/Q12345" -> "Q12345"
temp = /^http:\/\/www\.wikidata\.org\/entity\/(Q[1-9][0-9]*)$/.exec(value.value);
if (temp) {
return temp[1];
}
break;
}
return ignoreUnknown ? undefined : value.value;
}
},{}]},{},[1]);

View File

@@ -0,0 +1,57 @@
/*!
* StyleSheet for JQuery splitter Plugin
* Copyright (C) 2010 Jakub Jankiewicz <http://jcubic.pl>
*
* Same license as plugin
*/
.splitter_panel {
position: relative;
}
.splitter_panel .vsplitter {
background-color: grey;
cursor: col-resize;
z-index:900;
width: 7px;
}
.splitter_panel .hsplitter {
background-color: #5F5F5F;
cursor: row-resize;
z-index: 800;
height: 7px;
}
.splitter_panel .vsplitter.splitter-invisible,
.splitter_panel .hsplitter.splitter-invisible {
background: none;
}
.splitter_panel .vsplitter, .splitter_panel .left_panel, .splitter_panel .right_panel,
.splitter_panel .hsplitter, .splitter_panel .top_panel, .splitter_panel .bottom_panel {
position: absolute;
overflow: auto;
}
.splitter_panel .vsplitter, .splitter_panel .left_panel, .splitter_panel .right_panel {
height: 100%;
}
.splitter_panel .hsplitter, .splitter_panel .top_panel, .splitter_panel .bottom_panel {
width: 100%;
}
.splitter_panel .top_panel, .splitter_panel .left_panel, .splitter_panel .vsplitter {
top: 0;
}
.splitter_panel .top_panel, .splitter_panel .bottom_panel, .splitter_panel .left_panel, .splitter_panel .hsplitter {
left: 0;
}
.splitter_panel .bottom_panel {
bottom: 0;
}
.splitter_panel .right_panel {
right: 0;
}
.splitterMask {
position: absolute;
left: 0;
top: 0;
right: 0;
bottom: 0;
z-index: 1000;
}

View File

@@ -0,0 +1,307 @@
/*!
* JQuery Spliter Plugin version 0.20.1
* Copyright (C) 2010-2016 Jakub Jankiewicz <http://jcubic.pl>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
(function($, undefined) {
var count = 0;
var splitter_id = null;
var splitters = [];
var current_splitter = null;
$.fn.split = function(options) {
var data = this.data('splitter');
if (data) {
return data;
}
var panel_1;
var panel_2;
var settings = $.extend({
limit: 100,
orientation: 'horizontal',
position: '50%',
invisible: false,
onDragStart: $.noop,
onDragEnd: $.noop,
onDrag: $.noop
}, options || {});
this.settings = settings;
var cls;
var children = this.children();
if (settings.orientation == 'vertical') {
panel_1 = children.first().addClass('left_panel');
panel_2 = panel_1.next().addClass('right_panel');
cls = 'vsplitter';
} else if (settings.orientation == 'horizontal') {
panel_1 = children.first().addClass('top_panel');
panel_2 = panel_1.next().addClass('bottom_panel');
cls = 'hsplitter';
}
if (settings.invisible) {
cls += ' splitter-invisible';
}
var width = this.width();
var height = this.height();
var id = count++;
this.addClass('splitter_panel');
var splitter = $('<div/>').addClass(cls).bind('mouseenter touchstart', function() {
splitter_id = id;
}).bind('mouseleave touchend', function() {
splitter_id = null;
}).insertAfter(panel_1);
var position;
function get_position(position) {
if (typeof position === 'number') {
return position;
} else if (typeof position === 'string') {
var match = position.match(/^([0-9\.]+)(px|%)$/);
if (match) {
if (match[2] == 'px') {
return +match[1];
} else {
if (settings.orientation == 'vertical') {
return (width * +match[1]) / 100;
} else if (settings.orientation == 'horizontal') {
return (height * +match[1]) / 100;
}
}
} else {
//throw position + ' is invalid value';
}
} else {
//throw 'position have invalid type';
}
}
var self = $.extend(this, {
refresh: function() {
var new_width = this.width();
var new_height = this.height();
if (width != new_width || height != new_height) {
width = this.width();
height = this.height();
self.position(position);
}
},
position: (function() {
if (settings.orientation == 'vertical') {
return function(n, silent) {
if (n === undefined) {
return position;
} else {
position = get_position(n);
var sw = splitter.width();
var sw2 = sw/2, pw;
if (settings.invisible) {
pw = panel_1.width(position).outerWidth();
panel_2.width(self.width()-pw);
splitter.css('left', pw-sw2);
} else {
pw = panel_1.width(position-sw2).outerWidth();
panel_2.width(self.width()-pw-sw);
splitter.css('left', pw);
}
}
if (!silent) {
self.trigger('splitter.resize');
self.find('.splitter_panel').trigger('splitter.resize');
}
return self;
};
} else if (settings.orientation == 'horizontal') {
return function(n, silent) {
if (n === undefined) {
return position;
} else {
position = get_position(n);
var sw = splitter.height();
var sw2 = sw/2, pw;
if (settings.invisible) {
pw = panel_1.height(position).outerHeight();
panel_2.height(self.height()-pw);
splitter.css('top', pw-sw2);
} else {
pw = panel_1.height(position-sw2).outerHeight();
panel_2.height(self.height()-pw-sw);
splitter.css('top', pw);
}
}
if (!silent) {
self.trigger('splitter.resize');
self.find('.splitter_panel').trigger('splitter.resize');
}
return self;
};
} else {
return $.noop;
}
})(),
orientation: settings.orientation,
limit: settings.limit,
isActive: function() {
return splitter_id === id;
},
destroy: function() {
self.removeClass('splitter_panel');
splitter.unbind('mouseenter');
splitter.unbind('mouseleave');
splitter.unbind('touchstart');
splitter.unbind('touchmove');
splitter.unbind('touchend');
splitter.unbind('touchleave');
splitter.unbind('touchcancel');
if (settings.orientation == 'vertical') {
panel_1.removeClass('left_panel');
panel_2.removeClass('right_panel');
} else if (settings.orientation == 'horizontal') {
panel_1.removeClass('top_panel');
panel_2.removeClass('bottom_panel');
}
self.unbind('splitter.resize');
self.trigger('splitter.resize');
self.find('.splitter_panel').trigger('splitter.resize');
splitters[i] = null;
count--;
splitter.remove();
self.removeData('splitter');
var not_null = false;
for (var i=splitters.length; i--;) {
if (splitters[i] !== null) {
not_null = true;
break;
}
}
//remove document events when no splitters
if (!not_null) {
$(document.documentElement).unbind('.splitter');
$(window).unbind('resize.splitter');
splitters = [];
count = 0;
}
}
});
self.bind('splitter.resize', function(e) {
var pos = self.position();
if (self.orientation == 'vertical' &&
pos > self.width()) {
pos = self.width() - self.limit-1;
} else if (self.orientation == 'horizontal' &&
pos > self.height()) {
pos = self.height() - self.limit-1;
}
if (pos < self.limit) {
pos = self.limit + 1;
}
e.stopPropagation();
self.position(pos, true);
});
//inital position of splitter
var pos;
if (settings.orientation == 'vertical') {
if (pos > width-settings.limit) {
pos = width-settings.limit;
} else {
pos = get_position(settings.position);
}
} else if (settings.orientation == 'horizontal') {
//position = height/2;
if (pos > height-settings.limit) {
pos = height-settings.limit;
} else {
pos = get_position(settings.position);
}
}
if (pos < settings.limit) {
pos = settings.limit;
}
self.position(pos, true);
if (splitters.length === 0) { // first time bind events to document
$(window).bind('resize.splitter', function() {
$.each(splitters, function(i, splitter) {
if (splitter) {
splitter.refresh();
}
});
});
$(document.documentElement).on('mousedown.splitter touchstart.splitter', function(e) {
if (splitter_id !== null) {
current_splitter = splitters[splitter_id];
setTimeout(function() {
$('<div class="splitterMask"></div>').
css('cursor', current_splitter.children().eq(1).css('cursor')).
insertAfter(current_splitter);
});
current_splitter.settings.onDragStart(e);
}
}).bind('mouseup.splitter touchend.splitter touchleave.splitter touchcancel.splitter', function(e) {
if (current_splitter) {
setTimeout(function() {
$('.splitterMask').remove();
});
current_splitter.settings.onDragEnd(e);
current_splitter = null;
}
}).bind('mousemove.splitter touchmove.splitter', function(e) {
if (current_splitter !== null) {
var limit = current_splitter.limit;
var offset = current_splitter.offset();
if (current_splitter.orientation == 'vertical') {
var pageX = e.pageX;
if(e.originalEvent && e.originalEvent.changedTouches){
pageX = e.originalEvent.changedTouches[0].pageX;
}
var x = pageX - offset.left;
if (x <= current_splitter.limit) {
x = current_splitter.limit + 1;
} else if (x >= current_splitter.width() - limit) {
x = current_splitter.width() - limit - 1;
}
if (x > current_splitter.limit &&
x < current_splitter.width()-limit) {
current_splitter.position(x, true);
current_splitter.trigger('splitter.resize');
current_splitter.find('.splitter_panel').
trigger('splitter.resize');
//e.preventDefault();
}
} else if (current_splitter.orientation == 'horizontal') {
var pageY = e.pageY;
if(e.originalEvent && e.originalEvent.changedTouches){
pageY = e.originalEvent.changedTouches[0].pageY;
}
var y = pageY-offset.top;
if (y <= current_splitter.limit) {
y = current_splitter.limit + 1;
} else if (y >= current_splitter.height() - limit) {
y = current_splitter.height() - limit - 1;
}
if (y > current_splitter.limit &&
y < current_splitter.height()-limit) {
current_splitter.position(y, true);
current_splitter.trigger('splitter.resize');
current_splitter.find('.splitter_panel').
trigger('splitter.resize');
//e.preventDefault();
}
}
current_splitter.settings.onDrag(e);
}
});//*/
}
splitters[id] = self;
self.data('splitter', self);
return self;
};
})(jQuery);

File diff suppressed because one or more lines are too long

File diff suppressed because one or more lines are too long