@knight-lab/timelinejs 3.9.1 → 3.9.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +12 -0
- package/CONTRIBUTING.md +5 -0
- package/dist/css/fonts/font.amatic-andika.css +1 -1
- package/dist/css/fonts/font.bevan-pontanosans.css +2 -2
- package/dist/css/fonts/font.bitter-raleway.css +1 -1
- package/dist/css/fonts/font.default.css +3 -3
- package/dist/css/fonts/font.fjalla-average.css +1 -1
- package/dist/css/fonts/font.lustria-lato.css +2 -2
- package/dist/css/fonts/font.medula-lato.css +3 -3
- package/dist/css/fonts/font.opensans-gentiumbook.css +4 -4
- package/dist/css/fonts/font.playfair-faunaone.css +2 -2
- package/dist/css/fonts/font.pt.css +3 -3
- package/dist/css/fonts/font.roboto-megrim.css +2 -2
- package/dist/css/fonts/font.unicaone-vollkorn.css +3 -3
- package/dist/embed/index.html +1 -1
- package/dist/js/locale/en-gb.json +69 -0
- package/dist/js/locale/es.json +1 -1
- package/dist/js/locale/hi.json +0 -1
- package/dist/js/timeline.js +1 -1
- package/dist/js/timeline.js.map +1 -1
- package/package.json +4 -3
- package/src/embed/index.html +1 -1
- package/src/js/core/ConfigFactory.js +8 -2
- package/src/js/dom/DOM.js +7 -1
- package/src/js/language/Language.js +1 -0
- package/src/js/language/locale/en-gb.json +69 -0
- package/src/js/language/locale/es.json +1 -1
- package/src/js/language/locale/hi.json +0 -1
- package/src/js/media/MediaType.js +19 -6
- package/src/js/media/__tests__/MediaType.test.js +47 -0
- package/src/js/media/types/WikipediaImage.js +159 -0
- package/src/js/media/types/__tests__/WikipediaImage.test.js +48 -0
- package/src/js/net/Net.js +1 -1
- package/src/js/slider/Slide.js +3 -4
- package/src/js/slider/SlideNav.js +1 -1
- package/src/js/slider/StorySlider.js +1 -2
- package/src/js/timeline/Timeline.js +14 -22
- package/src/js/timenav/TimeEra.js +1 -2
- package/src/js/timenav/TimeMarker.js +2 -3
- package/src/js/ui/MenuBar.js +4 -4
- package/src/template/all-media-types.json +28 -2
- package/src/template/index.html +1 -0
- package/src/js/dom/DOMUtil.js +0 -25
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@knight-lab/timelinejs",
|
|
3
|
-
"version": "3.9.
|
|
3
|
+
"version": "3.9.3",
|
|
4
4
|
"license": "MPL-2.0",
|
|
5
5
|
"description": "TimelineJS v3: A Storytelling Timeline built in JavaScript, made by Northwestern University Knight Lab.",
|
|
6
6
|
"dependencies": {
|
|
@@ -59,7 +59,8 @@
|
|
|
59
59
|
"stage_dev": "npm run dist && node tasks/stage.js dev",
|
|
60
60
|
"prepublishOnly": "npm run dist"
|
|
61
61
|
},
|
|
62
|
-
"contributors": [
|
|
62
|
+
"contributors": [
|
|
63
|
+
{
|
|
63
64
|
"name": "Zach Wise",
|
|
64
65
|
"email": "wise@northwestern.edu",
|
|
65
66
|
"url": "https://github.com/zachwise"
|
|
@@ -70,4 +71,4 @@
|
|
|
70
71
|
"url": "https://github.com/JoeGermuska"
|
|
71
72
|
}
|
|
72
73
|
]
|
|
73
|
-
}
|
|
74
|
+
}
|
package/src/embed/index.html
CHANGED
|
@@ -150,7 +150,7 @@
|
|
|
150
150
|
var options = optionsFromUrlParams();
|
|
151
151
|
createEmbedDiv('timeline-embed', options.width, options.height);
|
|
152
152
|
// ga_property_id is not something we let users override
|
|
153
|
-
options.
|
|
153
|
+
options.ga_measurement_id = 'G-LVEFKMG087'
|
|
154
154
|
if (typeof(options.source) == 'undefined') {
|
|
155
155
|
options.source = '1xuY4upIooEeszZ_lCmeNx24eSFWe0rHe9ZdqH2xqVNk' // women in computing
|
|
156
156
|
}
|
|
@@ -154,7 +154,13 @@ export async function readGoogleAsCSV(url, sheets_proxy) {
|
|
|
154
154
|
if (error_json.proxy_err_code == 'response_not_csv') {
|
|
155
155
|
throw new TLError('Timeline could not read the data for your timeline. Make sure you have published it to the web.')
|
|
156
156
|
}
|
|
157
|
-
|
|
157
|
+
let msg = "undefined error"
|
|
158
|
+
if (Array.isArray(error_json.message)) {
|
|
159
|
+
msg = error_json.message.join('<br>')
|
|
160
|
+
} else {
|
|
161
|
+
msg = String(error_json.message)
|
|
162
|
+
}
|
|
163
|
+
throw new TLError(msg)
|
|
158
164
|
})
|
|
159
165
|
|
|
160
166
|
let timeline_config = { 'events': [], 'errors': [], 'warnings': [], 'eras': [] }
|
|
@@ -334,4 +340,4 @@ function handleRow(event, timeline_config) {
|
|
|
334
340
|
} else {
|
|
335
341
|
timeline_config.events.push(event);
|
|
336
342
|
}
|
|
337
|
-
}
|
|
343
|
+
}
|
package/src/js/dom/DOM.js
CHANGED
|
@@ -19,6 +19,12 @@ function create(tagName, className, container) {
|
|
|
19
19
|
return el;
|
|
20
20
|
}
|
|
21
21
|
|
|
22
|
+
function createButton(className, container) {
|
|
23
|
+
var el = create('button', className, container);
|
|
24
|
+
el.type = 'button';
|
|
25
|
+
return el;
|
|
26
|
+
}
|
|
27
|
+
|
|
22
28
|
function createText(content, container) {
|
|
23
29
|
var el = document.createTextNode(content);
|
|
24
30
|
if (container) {
|
|
@@ -78,4 +84,4 @@ let TRANSFORM = testProp(['transformProperty', 'WebkitTransform', 'OTransform',
|
|
|
78
84
|
let TRANSLATE_OPEN = 'translate' + (Browser.webkit3d ? '3d(' : '(')
|
|
79
85
|
let TRANSLATE_CLOSE = Browser.webkit3d ? ',0)' : ')'
|
|
80
86
|
|
|
81
|
-
export { get, create, getPosition }
|
|
87
|
+
export { get, create, createButton, getPosition }
|
|
@@ -318,6 +318,7 @@ var LANGUAGES = {
|
|
|
318
318
|
twitter_load_err: "Unable to load Tweet",
|
|
319
319
|
twitterembed_invalidurl_err: "Invalid Twitter Embed url",
|
|
320
320
|
wikipedia_load_err: "Unable to load Wikipedia entry",
|
|
321
|
+
wikipedia_image_load_err: "Unable to load Wikipedia image data",
|
|
321
322
|
spotify_invalid_url: "Invalid Spotify URL",
|
|
322
323
|
invalid_rgb_err: "Invalid RGB argument",
|
|
323
324
|
time_scale_scale_err: "Don't know how to get date from time for scale",
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
{
|
|
2
|
+
"lang": "en-gb",
|
|
3
|
+
"date": {
|
|
4
|
+
"month_abbr": [
|
|
5
|
+
"Jan",
|
|
6
|
+
"Feb",
|
|
7
|
+
"Mar",
|
|
8
|
+
"Apr",
|
|
9
|
+
"May",
|
|
10
|
+
"Jun",
|
|
11
|
+
"Jul",
|
|
12
|
+
"Aug",
|
|
13
|
+
"Sep",
|
|
14
|
+
"Oct",
|
|
15
|
+
"Nov",
|
|
16
|
+
"Dec"
|
|
17
|
+
],
|
|
18
|
+
"day_abbr": [
|
|
19
|
+
"Sun",
|
|
20
|
+
"Mon",
|
|
21
|
+
"Tue",
|
|
22
|
+
"Wed",
|
|
23
|
+
"Thu",
|
|
24
|
+
"Fri",
|
|
25
|
+
"Sat"
|
|
26
|
+
],
|
|
27
|
+
"day": [
|
|
28
|
+
"Sunday",
|
|
29
|
+
"Monday",
|
|
30
|
+
"Tuesday",
|
|
31
|
+
"Wednesday",
|
|
32
|
+
"Thursday",
|
|
33
|
+
"Friday",
|
|
34
|
+
"Saturday"
|
|
35
|
+
],
|
|
36
|
+
"month": [
|
|
37
|
+
"January",
|
|
38
|
+
"February",
|
|
39
|
+
"March",
|
|
40
|
+
"April",
|
|
41
|
+
"May",
|
|
42
|
+
"June",
|
|
43
|
+
"July",
|
|
44
|
+
"August",
|
|
45
|
+
"September",
|
|
46
|
+
"October",
|
|
47
|
+
"November",
|
|
48
|
+
"December"
|
|
49
|
+
]
|
|
50
|
+
},
|
|
51
|
+
"api": {
|
|
52
|
+
"wikipedia": "en"
|
|
53
|
+
},
|
|
54
|
+
"messages": {
|
|
55
|
+
"comment": "There is no need to repeat message keys because the fallback is English and this file only exists to control date formatting."
|
|
56
|
+
},
|
|
57
|
+
"dateformats": {
|
|
58
|
+
"full_long": "d mmm yyyy 'at' HH:MM TT",
|
|
59
|
+
"full_short": "d mmm",
|
|
60
|
+
"full": "d mmmm yyyy",
|
|
61
|
+
"month_short": "mmm",
|
|
62
|
+
"time_no_seconds_small_date": "HH:MM TT'<br/><small>'d mmmm yyyy'</small>'",
|
|
63
|
+
"month": "mmmm yyyy",
|
|
64
|
+
"time_no_seconds_short": "HH:MM TT",
|
|
65
|
+
"time_short": "HH:MM:ss",
|
|
66
|
+
"year": "yyyy",
|
|
67
|
+
"full_long_small_date": "HH:MM TT'<br/><small>d mmm yyyy'</small>'"
|
|
68
|
+
}
|
|
69
|
+
}
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"messages": {
|
|
55
55
|
"loading": "cargando",
|
|
56
56
|
"return_to_title": "Volver al título",
|
|
57
|
-
"
|
|
57
|
+
"swipe_to_navigate": "Desliza para ver<br><span class='tl-button'>OK</span>",
|
|
58
58
|
"wikipedia": "Desde Wikipedia, la enciclopedia libre",
|
|
59
59
|
"loading_content": "cargando",
|
|
60
60
|
"loading_timeline": "La cronología esta cargando"
|
|
@@ -15,6 +15,7 @@ import YouTube from "./types/YouTube"
|
|
|
15
15
|
import GoogleMap from "./types/GoogleMap"
|
|
16
16
|
import Blockquote from "./types/Blockquote"
|
|
17
17
|
import Wikipedia from "./types/Wikipedia"
|
|
18
|
+
import WikipediaImage from "./types/WikipediaImage"
|
|
18
19
|
import SoundCloud from "./types/SoundCloud"
|
|
19
20
|
import Vimeo from "./types/Vimeo"
|
|
20
21
|
import DailyMotion from "./types/DailyMotion"
|
|
@@ -133,6 +134,24 @@ export function lookupMediaType(m, image_only) {
|
|
|
133
134
|
match_str: /documentcloud.org\//,
|
|
134
135
|
cls: DocumentCloud
|
|
135
136
|
},
|
|
137
|
+
{
|
|
138
|
+
type: "wikipedia-image",
|
|
139
|
+
name: "WikipediaImage",
|
|
140
|
+
match_str: "^https:\/\/.+\.wiki[mp]edia\.org.+#/media/.+\.(jpg|jpeg|png|gif|svg|webp)",
|
|
141
|
+
cls: WikipediaImage
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
type: "wikipedia-image",
|
|
145
|
+
name: "WikipediaImage",
|
|
146
|
+
match_str: "^https:\/\/commons.wikimedia.org/wiki/File:.+\.(jpg|jpeg|png|gif|svg|webp)",
|
|
147
|
+
cls: WikipediaImage
|
|
148
|
+
},
|
|
149
|
+
{
|
|
150
|
+
type: "wikipedia",
|
|
151
|
+
name: "Wikipedia",
|
|
152
|
+
match_str: "^(https?:)?\/.+.wikipedia\.org",
|
|
153
|
+
cls: Wikipedia
|
|
154
|
+
},
|
|
136
155
|
{
|
|
137
156
|
type: "image",
|
|
138
157
|
name: "Image",
|
|
@@ -157,12 +176,6 @@ export function lookupMediaType(m, image_only) {
|
|
|
157
176
|
match_str: /^.*\.pdf(\?.*)?(\#.*)?/,
|
|
158
177
|
cls: PDF
|
|
159
178
|
},
|
|
160
|
-
{
|
|
161
|
-
type: "wikipedia",
|
|
162
|
-
name: "Wikipedia",
|
|
163
|
-
match_str: "^(https?:)?\/*(www.)?wikipedia\.org|^(https?:)?\/*([a-z][a-z].)?wikipedia\.org",
|
|
164
|
-
cls: Wikipedia
|
|
165
|
-
},
|
|
166
179
|
{
|
|
167
180
|
type: "spotify",
|
|
168
181
|
name: "spotify",
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
import { lookupMediaType } from "../MediaType";
|
|
2
|
+
import { test, expect } from "@jest/globals"
|
|
3
|
+
|
|
4
|
+
const TEST_CASES = [
|
|
5
|
+
// tuples: [URL, expected type, optional note which isn't used.]
|
|
6
|
+
['https://www.youtube.com/watch?v=pi2v1m6gmD8&t=5m21s', 'youtube', 'YouTube with time stamp'],
|
|
7
|
+
['//www.youtube.com/watch?v=pi2v1m6gmD8', 'youtube', 'YouTube with no protocol'],
|
|
8
|
+
['youtu.be/pi2v1m6gmD8', 'youtube', 'YouTu.be short url'],
|
|
9
|
+
['http://vimeo.com/20839673', 'vimeo'],
|
|
10
|
+
['http://www.dailymotion.com/video/x2fo0e8_the-history-of-advertising-in-60-seconds_lifestyle', 'dailymotion'],
|
|
11
|
+
['https://vine.co/v/Og5Ai71WHdD', 'vine'],
|
|
12
|
+
['https://soundcloud.com/usher-raymond-music/usher-i-dont-mind-feat-juicy-j', 'soundcloud'],
|
|
13
|
+
['https://twitter.com/NASASpaceflight/status/562327074384654336', 'twitter'],
|
|
14
|
+
['<blockquote class="twitter-tweet" lang="en"><p>Rough vs. smooth: the Anuket and Anubis regions on <a href="https://twitter.com/hashtag/67P?src=hash">#67P</a> <a href="http://t.co/kOyAiOKlma">http://t.co/kOyAiOKlma</a> <a href="https://twitter.com/hashtag/CometWatch?src=hash">#CometWatch</a> <a href="http://t.co/YmQ8bP5WbS">pic.twitter.com/YmQ8bP5WbS</a></p>— ESA Rosetta Mission (@ESA_Rosetta) <a href="https://twitter.com/ESA_Rosetta/status/563722810397560832">February 6, 2015</a></blockquote>', 'twitterembed'],
|
|
15
|
+
['https://www.google.com/maps/@42.032147,-87.6689625,15z', 'googlemaps', 'Google Maps with lat/long'],
|
|
16
|
+
['https://www.google.com/maps/search/target/@41.8747339,-87.6481257,13z?hl=en-US', 'googlemaps', 'Google Maps with search'],
|
|
17
|
+
['https://www.google.com/maps/place/Northwestern+University/@42.056459,-87.675267,17z/data=!3m1!4b1!4m2!3m1!1s0x880fd00b703e4c39:0x2c37b567fad56106', 'googlemaps', 'Google Maps with place'],
|
|
18
|
+
['https://www.google.com/maps/dir/W+Adams+St+%26+S+Clark+St,+Chicago,+IL/Northwestern+University,+633+Clark+Street,+Evanston,+IL+60208/@41.9672743,-87.7225481,12z/data=!3m1!4b1!4m13!4m12!1m5!1m1!1s0x880e2cbc8bcec53b:0x72d2c7372d97283d!2m2!1d-87.6308023!2d41.8794067!1m5!1m1!1s0x880fd00b703e4c39:0x2c37b567fad56106!2m2!1d-87.675267!2d42.056459', 'googlemaps', 'Google Maps with directions'],
|
|
19
|
+
['http://instagram.com/p/ymwL5JAsw5/', 'instagram'],
|
|
20
|
+
['http://instagram.com/lukerague/', 'profile'],
|
|
21
|
+
['https://www.flickr.com/photos/critterseeker/16420145375', 'flickr'],
|
|
22
|
+
['https://flic.kr/p/u7SSxw', 'flickr'],
|
|
23
|
+
['https://www.documentcloud.org/documents/1377371-folketinget.html', 'documentcloud'],
|
|
24
|
+
['http://www.kidzone.ws/images-changed/sharks/head.jpg', 'image', 'JPG'],
|
|
25
|
+
['http://usatlife.files.wordpress.com/2014/06/groundhog-day-bill-murray-winter-never-going-to-end.gif', 'image', 'GIF'],
|
|
26
|
+
['http://pngimg.com/upload/banana_PNG842.png', 'image', 'PNG'],
|
|
27
|
+
['http://upload.wikimedia.org/wikipedia/commons/c/c2/Rocky_Mountains.jpeg', 'image', 'JPEG'],
|
|
28
|
+
['https://docs.google.com/document/d/1RvKYxHuwweIP8zRrnjad-0exVoZOUsSVgDYPp0J1mzY/edit?usp=sharing', 'googledocs'],
|
|
29
|
+
['http://stlab.adobe.com/wiki/images/d/d3/Test.pdf', 'pdf'],
|
|
30
|
+
['https://en.wikipedia.org/wiki/1997_International_Tennis_Championships_%E2%80%93_Doubles', 'wikipedia'],
|
|
31
|
+
['<iframe src="https://embed.spotify.com/?uri=https://play.spotify.com/artist/2iE18Oxc8YSumAU232n4rW" width="300" height="380" frameborder="0" allowtransparency="true"></iframe>', 'spotify', 'artist'],
|
|
32
|
+
['https://play.spotify.com/user/edvard_m/playlist/4xFSdiuP4gpR4wq2OghlOs', 'spotify', 'playlist'],
|
|
33
|
+
['https://play.spotify.com/track/5SdB3onMcO9ZBoKrdvCqhR', 'spotify', 'track'],
|
|
34
|
+
["<iframe src='https://cdn.knightlab.com/libs/timeline/latest/embed/index.html?source=10fFZXg4kioMz8uTVDZfawiJkgrWZxfJuziK1i1AaCrs&font=Bevan-PotanoSans&maptype=toner&lang=en&height=650' width='100%' height='650' frameborder='0'></iframe>", 'iframe'],
|
|
35
|
+
['<blockquote>This is a block quote.</blockquote>', 'blockquote'],
|
|
36
|
+
['http://2.bp.blogspot.com/-dxJbW0CG8Zs/TmkoMA5-cPI/AAAAAAAAAqw/fQpsz9GpFdo/s1600/voyage-dans-la-lune-1902-02-g.jpg', 'image'],
|
|
37
|
+
['https://de.wikipedia.org/wiki/Beryllium#/media/Datei:Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg', 'wikipedia-image', 'regular wikipedia link'],
|
|
38
|
+
['https://commons.wikimedia.org/wiki/File:Hyperspace_Mountain_(27766070223).jpg', 'wikipedia-image', 'Wikimedia Commons link'],
|
|
39
|
+
['https://commons.wikimedia.org/wiki/Category:Airdancers#/media/File:Sky-dancer-japan.jpg', 'wikipedia-image', 'Wikimedia Commons link'],
|
|
40
|
+
|
|
41
|
+
]
|
|
42
|
+
|
|
43
|
+
test.each(TEST_CASES)("Ensure test URLs yield expected type", (url, expected_type) => {
|
|
44
|
+
const result = lookupMediaType({ url: url })
|
|
45
|
+
expect(result.type).toBe(expected_type)
|
|
46
|
+
|
|
47
|
+
})
|
|
@@ -0,0 +1,159 @@
|
|
|
1
|
+
import { Media } from "../Media";
|
|
2
|
+
import { getJSON, fetchJSON } from "../../net/Net";
|
|
3
|
+
import TLError from "../../core/TLError";
|
|
4
|
+
import { unhtmlify } from "../../core/Util";
|
|
5
|
+
|
|
6
|
+
export function computeMediaId(url) {
|
|
7
|
+
|
|
8
|
+
if (url.match(/^.+#\/media\/.+/)) {
|
|
9
|
+
let parts = url.split('#')
|
|
10
|
+
let file_parts = parts[1].split(':') // the prefix is File in English but different on other language WPs
|
|
11
|
+
return `File:${file_parts[1]}`
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
if (url.match(/^.*commons.wikimedia.org\/wiki\/File:.+/)) {
|
|
15
|
+
let parts = url.split('/')
|
|
16
|
+
return parts[parts.length - 1]
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
return null
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
/**
|
|
23
|
+
* Given a JSON response from a Wikimedia Commons API call, extract the base thumbnail URL
|
|
24
|
+
* and the page ID, which can be used to get alt text later.
|
|
25
|
+
* We assume that there is only one meaningful result in the object.
|
|
26
|
+
*
|
|
27
|
+
* @param {Object} j
|
|
28
|
+
*/
|
|
29
|
+
export function processImageInfoAPIJSON(j) {
|
|
30
|
+
let response = {}
|
|
31
|
+
if (j.query && j.query.pages) {
|
|
32
|
+
let page_ids = Object.keys(j.query.pages)
|
|
33
|
+
response['page_id'] = page_ids[0]
|
|
34
|
+
let data = j.query.pages[response['page_id']]
|
|
35
|
+
response['url'] = data.imageinfo[0].thumburl
|
|
36
|
+
if (data.entityterms && data.entityterms.label) {
|
|
37
|
+
response['label'] = data.entityterms.label[0]
|
|
38
|
+
}
|
|
39
|
+
}
|
|
40
|
+
return response
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export default class WikipediaImage extends Media {
|
|
44
|
+
|
|
45
|
+
_loadMedia() {
|
|
46
|
+
var api_url,
|
|
47
|
+
image_width = this.options.width || 1000,
|
|
48
|
+
language_code = this.getLanguage().lang.toLowerCase(),
|
|
49
|
+
self = this;
|
|
50
|
+
|
|
51
|
+
try {
|
|
52
|
+
// Get Media ID
|
|
53
|
+
this.establishMediaID();
|
|
54
|
+
|
|
55
|
+
// API URL
|
|
56
|
+
api_url = `https://commons.wikimedia.org/w/api.php?action=query&titles=${this.media_id}&prop=imageinfo|entityterms&iiprop=url&&iiurlwidth=${image_width}&format=json&origin=*&wbetlanguage=${language_code}`
|
|
57
|
+
// API Call
|
|
58
|
+
getJSON(api_url, function(d) {
|
|
59
|
+
let response = processImageInfoAPIJSON(d)
|
|
60
|
+
if (response.url) {
|
|
61
|
+
self.base_image_url = response.url
|
|
62
|
+
self.page_id = response.page_id
|
|
63
|
+
if (!(self.data.alt) && response.label) {
|
|
64
|
+
self.data.alt = response.label
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
if (!self.options.background) {
|
|
68
|
+
self.createMedia();
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
self.onLoaded();
|
|
72
|
+
} else {
|
|
73
|
+
self.loadErrorDisplay(self._("wikipedia_image_load_err"));
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
} catch (e) {
|
|
77
|
+
self.loadErrorDisplay(self._(e.message_key));
|
|
78
|
+
}
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
/**
|
|
82
|
+
* Analyze the URL provided in the data object passed to the constructor to extract
|
|
83
|
+
* the Wikimedia commons "page" name
|
|
84
|
+
*/
|
|
85
|
+
establishMediaID() {
|
|
86
|
+
let media_id = computeMediaId(this.data.url)
|
|
87
|
+
if (media_id) {
|
|
88
|
+
this.media_id = media_id
|
|
89
|
+
} else {
|
|
90
|
+
throw new TLError(`Invalid Wikipedia Image URL`)
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
createMedia() {
|
|
95
|
+
var self = this;
|
|
96
|
+
|
|
97
|
+
// Photo
|
|
98
|
+
this._el.content_item = this.domCreate("img", "tl-media-item tl-media-image tl-media-wikipedia-image tl-media-shadow", this._el.content);
|
|
99
|
+
|
|
100
|
+
if (this.data.alt) {
|
|
101
|
+
this._el.content_item.alt = this.data.alt;
|
|
102
|
+
} else if (this.page_id) {
|
|
103
|
+
let wikibase_id = `M${this.page_id}`
|
|
104
|
+
let wikibase_url = `https://commons.wikimedia.org/w/api.php?action=wbgetentities&format=json&ids=${wikibase_id}&format=json&origin=*`
|
|
105
|
+
fetchJSON(wikibase_url).then(j => {
|
|
106
|
+
if (j.entities && j.entities[wikibase_id]) {
|
|
107
|
+
let labels = j.entities[wikibase_id].labels
|
|
108
|
+
let language_code = self.getLanguage().lang.toLowerCase()
|
|
109
|
+
let label = null
|
|
110
|
+
if (labels[language_code]) {
|
|
111
|
+
label = labels[language_code]
|
|
112
|
+
} else if (language_code.length > 2 && labels[language_code.substr(0, 2)]) {
|
|
113
|
+
label = labels[language_code.substr(0, 2)]
|
|
114
|
+
} else if (labels['en']) {
|
|
115
|
+
label = labels['en']
|
|
116
|
+
}
|
|
117
|
+
if (label) {
|
|
118
|
+
console.log(`wikibase_id: ${self.media_id} alt ${label.value}`)
|
|
119
|
+
self.data.alt = label.value
|
|
120
|
+
self._el.content_item.alt = self.data.alt
|
|
121
|
+
} else {
|
|
122
|
+
console.log(`wikibase_id: ${self.media_id} ain't got no alt`)
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
})
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
if (this.data.title) {
|
|
129
|
+
this._el.content_item.title = this.data.title;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Media Loaded Event
|
|
133
|
+
this._el.content_item.addEventListener('load', function(e) {
|
|
134
|
+
self.onMediaLoaded();
|
|
135
|
+
});
|
|
136
|
+
|
|
137
|
+
// Set Image Source
|
|
138
|
+
this._el.content_item.src = this.getImageURL(this.options.width, this.options.height);
|
|
139
|
+
}
|
|
140
|
+
|
|
141
|
+
_getImageURL(w, h) {
|
|
142
|
+
if (w && this.base_image_url) {
|
|
143
|
+
let match = this.base_image_url.match(/(\/\d+px-)/)
|
|
144
|
+
if (match) {
|
|
145
|
+
return this.base_image_url.replace(match[1], `/${w}px-`) // Wikipedia will autoscale the image for us
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
// they don't always have that pattern!
|
|
149
|
+
return this.base_image_url
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
/**
|
|
155
|
+
*
|
|
156
|
+
*
|
|
157
|
+
* https://commons.wikimedia.org/w/api.php?action=query&titles=File:Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg&prop=imageinfo&iiprop=url&&iiurlwidth=1000
|
|
158
|
+
* https://commons.wikimedia.org/wiki/File:Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg
|
|
159
|
+
*/
|
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
import { computeMediaId, processImageInfoAPIJSON } from "../WikipediaImage"
|
|
2
|
+
import { test, expect } from "@jest/globals"
|
|
3
|
+
|
|
4
|
+
const TEST_CASES = [
|
|
5
|
+
['https://commons.wikimedia.org/wiki/https://commons.wikimedia.org/wiki/File:Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg', 'File:Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg'],
|
|
6
|
+
['https://en.wikipedia.org/wiki/Main_Page#/media/File:Symphyotrichum_kentuckiense_233619783_(inflor).jpg', 'File:Symphyotrichum_kentuckiense_233619783_(inflor).jpg'],
|
|
7
|
+
['https://es.wikipedia.org/wiki/Portal:M%C3%BAsica#/media/Archivo:David-Bowie_Chicago_2002-08-08_photoby_Adam-Bielawski-cropped.jpg', 'File:David-Bowie_Chicago_2002-08-08_photoby_Adam-Bielawski-cropped.jpg'],
|
|
8
|
+
['https://commons.wikimedia.org/wiki/Category:Airdancers#/media/File:Sky-dancer-japan.jpg', 'File:Sky-dancer-japan.jpg']
|
|
9
|
+
]
|
|
10
|
+
|
|
11
|
+
const IMAGE_INFO_JSON_RESPONSE = {
|
|
12
|
+
"batchcomplete": "",
|
|
13
|
+
"query": {
|
|
14
|
+
"normalized": [{
|
|
15
|
+
"from": "File:Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg",
|
|
16
|
+
"to": "File:Beryl-Quartz-Emerald-Zambia-33mm 0885.jpg"
|
|
17
|
+
}],
|
|
18
|
+
"pages": {
|
|
19
|
+
"10450749": {
|
|
20
|
+
"pageid": 10450749,
|
|
21
|
+
"ns": 6,
|
|
22
|
+
"title": "File:Beryl-Quartz-Emerald-Zambia-33mm 0885.jpg",
|
|
23
|
+
"imagerepository": "local",
|
|
24
|
+
"imageinfo": [{
|
|
25
|
+
"thumburl": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg/100px-Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg",
|
|
26
|
+
"thumbwidth": 100,
|
|
27
|
+
"thumbheight": 121,
|
|
28
|
+
"thumbmime": "image/jpeg",
|
|
29
|
+
"responsiveUrls": { "1.5": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg/150px-Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg", "2": "https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg/200px-Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg" },
|
|
30
|
+
"url": "https://upload.wikimedia.org/wikipedia/commons/d/df/Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg",
|
|
31
|
+
"descriptionurl": "https://commons.wikimedia.org/wiki/File:Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg",
|
|
32
|
+
"descriptionshorturl": "https://commons.wikimedia.org/w/index.php?curid=10450749",
|
|
33
|
+
"mime": "image/jpeg"
|
|
34
|
+
}]
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
test.each(TEST_CASES)("Ensure correct file identifier is extracted", (url, file_id) =>
|
|
41
|
+
expect(computeMediaId(url)).toBe(file_id)
|
|
42
|
+
)
|
|
43
|
+
|
|
44
|
+
test("get image info data", () => {
|
|
45
|
+
let response = processImageInfoAPIJSON(IMAGE_INFO_JSON_RESPONSE)
|
|
46
|
+
expect(response.url).toBe("https://upload.wikimedia.org/wikipedia/commons/thumb/d/df/Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg/100px-Beryl-Quartz-Emerald-Zambia-33mm_0885.jpg")
|
|
47
|
+
expect(response.page_id).toBe("10450749")
|
|
48
|
+
})
|
package/src/js/net/Net.js
CHANGED
|
@@ -1477,7 +1477,7 @@ window.$ === undefined && (window.$ = Zepto)
|
|
|
1477
1477
|
|
|
1478
1478
|
/**
|
|
1479
1479
|
* Add a promisified option to better handle cases where we need the data
|
|
1480
|
-
*
|
|
1480
|
+
* asynchronously.
|
|
1481
1481
|
* @param {String} url
|
|
1482
1482
|
*/
|
|
1483
1483
|
$.fetchJSON = function(url) {
|
package/src/js/slider/Slide.js
CHANGED
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import "wicg-inert";
|
|
2
2
|
|
|
3
|
-
import { addClass } from "../dom/DOMUtil"
|
|
4
3
|
import { I18NMixins } from "../language/I18NMixins";
|
|
5
4
|
import Events from "../core/Events";
|
|
6
5
|
import { DOMMixins } from "../dom/DOMMixins";
|
|
@@ -321,17 +320,17 @@ export class Slide {
|
|
|
321
320
|
|
|
322
321
|
// Add to DOM
|
|
323
322
|
if (!this.has.text && !this.has.headline && this.has.media) {
|
|
324
|
-
|
|
323
|
+
this._el.container.classList.add('tl-slide-media-only');
|
|
325
324
|
this._media.addTo(this._el.content);
|
|
326
325
|
} else if (this.has.headline && this.has.media && !this.has.text) {
|
|
327
|
-
|
|
326
|
+
this._el.container.classList.add('tl-slide-media-only');
|
|
328
327
|
this._text.addTo(this._el.content);
|
|
329
328
|
this._media.addTo(this._el.content);
|
|
330
329
|
} else if (this.has.text && this.has.media) {
|
|
331
330
|
this._text.addTo(this._el.content);
|
|
332
331
|
this._media.addTo(this._el.content);
|
|
333
332
|
} else if (this.has.text || this.has.headline) {
|
|
334
|
-
|
|
333
|
+
this._el.container.classList.add('tl-slide-text-only');
|
|
335
334
|
this._text.addTo(this._el.content);
|
|
336
335
|
}
|
|
337
336
|
|
|
@@ -39,7 +39,7 @@ export class SlideNav {
|
|
|
39
39
|
mergeData(this.data, data);
|
|
40
40
|
|
|
41
41
|
|
|
42
|
-
this._el.container = DOM.
|
|
42
|
+
this._el.container = DOM.createButton("tl-slidenav-" + this.options.direction);
|
|
43
43
|
|
|
44
44
|
if (Browser.mobile) {
|
|
45
45
|
this._el.container.setAttribute("ontouchstart"," ");
|
|
@@ -6,7 +6,6 @@ import { Animate } from "../animation/Animate"
|
|
|
6
6
|
import * as DOM from "../dom/DOM"
|
|
7
7
|
import { DOMEvent } from "../dom/DOMEvent"
|
|
8
8
|
import * as Browser from "../core/Browser"
|
|
9
|
-
import { addClass } from "../dom/DOMUtil"
|
|
10
9
|
import Swipable from "../ui/Swipable";
|
|
11
10
|
import Message from "../ui/Message"
|
|
12
11
|
import { Slide } from "./Slide"
|
|
@@ -394,7 +393,7 @@ export class StorySlider {
|
|
|
394
393
|
================================================== */
|
|
395
394
|
_initLayout() {
|
|
396
395
|
|
|
397
|
-
|
|
396
|
+
this._el.container.classList.add('tl-storyslider');
|
|
398
397
|
|
|
399
398
|
// Create Navigation
|
|
400
399
|
this._nav.previous = new SlideNav({ title: "Previous", description: "description" }, { direction: "previous" }, this._el.container);
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import * as DOM from "../dom/DOM"
|
|
2
|
-
import { addClass } from "../dom/DOMUtil"
|
|
3
2
|
import { hexToRgb, mergeData, classMixin, isTrue, trace, addTraceHandler } from "../core/Util";
|
|
4
3
|
import { easeInOutQuint, easeOutStrong } from "../animation/Ease";
|
|
5
4
|
import Message from "../ui/Message"
|
|
@@ -134,6 +133,7 @@ class Timeline {
|
|
|
134
133
|
slide_default_fade: "0%", // landscape fade
|
|
135
134
|
zoom_sequence: [0.5, 1, 2, 3, 5, 8, 13, 21, 34, 55, 89], // Array of Fibonacci numbers for TimeNav zoom levels
|
|
136
135
|
language: "en",
|
|
136
|
+
ga_measurement_id: null,
|
|
137
137
|
ga_property_id: null,
|
|
138
138
|
track_events: ['back_to_start', 'nav_next', 'nav_previous', 'zoom_in', 'zoom_out'],
|
|
139
139
|
theme: null,
|
|
@@ -192,17 +192,17 @@ class Timeline {
|
|
|
192
192
|
}
|
|
193
193
|
|
|
194
194
|
// Apply base class to container
|
|
195
|
-
|
|
195
|
+
this._el.container.classList.add('tl-timeline');
|
|
196
196
|
this._el.container.setAttribute('tabindex', '0');
|
|
197
197
|
this._el.container.setAttribute('role', 'region');
|
|
198
198
|
this._el.container.setAttribute('aria-label', this._('aria_label_timeline'));
|
|
199
199
|
|
|
200
200
|
if (this.options.is_embed) {
|
|
201
|
-
|
|
201
|
+
this._el.container.classList.add('tl-timeline-embed');
|
|
202
202
|
}
|
|
203
203
|
|
|
204
204
|
if (this.options.is_full_embed) {
|
|
205
|
-
|
|
205
|
+
this._el.container.classList.add('tl-timeline-full-embed');
|
|
206
206
|
}
|
|
207
207
|
|
|
208
208
|
this._loadLanguage(data);
|
|
@@ -992,31 +992,23 @@ class Timeline {
|
|
|
992
992
|
this._el.container.focus();
|
|
993
993
|
}
|
|
994
994
|
|
|
995
|
-
_initGoogleAnalytics() {
|
|
996
|
-
(
|
|
997
|
-
|
|
998
|
-
|
|
999
|
-
|
|
1000
|
-
|
|
1001
|
-
a = s.createElement(o), m = s.getElementsByTagName(o)[0];
|
|
1002
|
-
a.async = 1;
|
|
1003
|
-
a.src = g;
|
|
1004
|
-
m.parentNode.insertBefore(a, m)
|
|
1005
|
-
})(window, document, 'script', '//www.google-analytics.com/analytics.js', 'ga');
|
|
1006
|
-
|
|
1007
|
-
ga('create', this.options.ga_property_id, 'auto');
|
|
1008
|
-
ga('set', 'anonymizeIp', true);
|
|
995
|
+
_initGoogleAnalytics(measurement_id) {
|
|
996
|
+
loadJS(`https://www.googletagmanager.com/gtag/js?id=${measurement_id}`)
|
|
997
|
+
window.dataLayer = window.dataLayer || [];
|
|
998
|
+
window.gtag = function(){dataLayer.push(arguments);}
|
|
999
|
+
gtag('js', new Date());
|
|
1000
|
+
gtag('config', measurement_id);
|
|
1009
1001
|
}
|
|
1010
1002
|
|
|
1011
1003
|
_initAnalytics() {
|
|
1012
|
-
|
|
1013
|
-
|
|
1014
|
-
|
|
1004
|
+
let measurement_id = this.options.ga_measurement_id || this.options.ga_property_id || null;
|
|
1005
|
+
if (!measurement_id) { return; }
|
|
1006
|
+
this._initGoogleAnalytics(measurement_id);
|
|
1015
1007
|
var events = this.options.track_events;
|
|
1016
1008
|
for (let i = 0; i < events.length; i++) {
|
|
1017
1009
|
var event_ = events[i];
|
|
1018
1010
|
this.addEventListener(event_, function(e) {
|
|
1019
|
-
|
|
1011
|
+
gtag('event', e.type);
|
|
1020
1012
|
});
|
|
1021
1013
|
}
|
|
1022
1014
|
}
|
|
@@ -2,7 +2,6 @@ import { classMixin, unlinkify, mergeData } from "../core/Util"
|
|
|
2
2
|
import Events from "../core/Events"
|
|
3
3
|
import { DOMMixins } from "../dom/DOMMixins"
|
|
4
4
|
import * as Browser from "../core/Browser"
|
|
5
|
-
import { removeClass } from "../dom/DOMUtil";
|
|
6
5
|
import { easeInSpline } from "../animation/Ease";
|
|
7
6
|
import * as DOM from "../dom/DOM"
|
|
8
7
|
|
|
@@ -156,7 +155,7 @@ export class TimeEra {
|
|
|
156
155
|
this.setPosition({ top: n });
|
|
157
156
|
|
|
158
157
|
if (remainder < 56) {
|
|
159
|
-
|
|
158
|
+
this._el.content_container.remove("tl-timeera-content-container-small");
|
|
160
159
|
}
|
|
161
160
|
}
|
|
162
161
|
|