@knight-lab/timelinejs
Advanced tools
Comparing version 3.8.9 to 3.8.10
{ | ||
"name": "@knight-lab/timelinejs", | ||
"version": "3.8.9", | ||
"version": "3.8.10", | ||
"license": "MPL-2.0", | ||
@@ -5,0 +5,0 @@ "description": "TimelineJS v3: A Storytelling Timeline built in JavaScript, made by Northwestern University Knight Lab.", |
@@ -278,3 +278,4 @@ import { mergeData, pad, trace } from "../core/Util" | ||
axis_helper_scale_err: "No AxisHelper available for scale", | ||
invalid_integer_option: "Invalid option value—must be a whole number." | ||
invalid_integer_option: "Invalid option value—must be a whole number.", | ||
instagram_bad_request: "Invalid or private Instagram URL" | ||
}, | ||
@@ -281,0 +282,0 @@ date: { |
@@ -95,3 +95,4 @@ { | ||
"axis_helper_scale_err": "No AxisHelper available for scale", | ||
"invalid_integer_option": "Invalid option value—must be a whole number." | ||
"invalid_integer_option": "Invalid option value—must be a whole number.", | ||
"instagram_bad_request": "Invalid or private Instagram URL" | ||
}, | ||
@@ -120,3 +121,3 @@ "dateformats": { | ||
}, | ||
"period_labels": { // use of t/tt/T/TT is a legacy of original Timeline date format | ||
"period_labels": { // use of t/tt/T/TT is a legacy of original Timeline date format | ||
"t": ["a", "p"], | ||
@@ -127,2 +128,2 @@ "tt": ["am", "pm"], | ||
}, | ||
} | ||
} |
@@ -44,3 +44,4 @@ /* | ||
* tested against patterns which are known to return images suitable for use as | ||
* thumbnails and backgrounds. | ||
* thumbnails and backgrounds. Media classes returned when image_only is true should | ||
* implement the getImageURL() function | ||
* | ||
@@ -47,0 +48,0 @@ * @param {Object} m |
import { unhtmlify, trace } from "../../core/Util"; | ||
import { getJSON } from "../../net/Net"; | ||
import { ajax, fetchJSON } from "../../net/Net"; | ||
import { Media } from "../Media"; | ||
const CLIENT_TOKEN = '830b21071290df4f81a35c56abbea096' | ||
const FB_APP_ID = '704270473831239' | ||
const ACCESS_TOKEN = `${FB_APP_ID}|${CLIENT_TOKEN}` | ||
const API_URL_ROOT = `https://graph.facebook.com/v8.0/instagram_oembed?access_token=${ACCESS_TOKEN}&fields=html,thumbnail_url,author_name&url=` | ||
/** | ||
* Break out from AJAX call for clarity. Remember to .bind() a this value. | ||
* @param {XMLHttpResponse} resp | ||
*/ | ||
function successHandler(resp) { | ||
this.oembed_response = resp; | ||
// Link | ||
this._el.content_link = this.domCreate("a", "", this._el.content); | ||
this._el.content_link.href = this.data.url; | ||
this._el.content_link.target = "_blank"; | ||
// Photo | ||
this._el.content_item = this.domCreate("img", "tl-media-item tl-media-image tl-media-instagram tl-media-shadow", this._el.content_link); | ||
if (this.data.alt) { | ||
this._el.content_item.alt = this.data.alt; | ||
} else if (this.data.caption) { | ||
this._el.content_item.alt = unhtmlify(this.data.caption); | ||
} | ||
if (this.data.title) { | ||
this._el.content_item.title = this.data.title; | ||
} else if (this.data.caption) { | ||
this._el.content_item.title = unhtmlify(this.data.caption); | ||
} | ||
// Media Loaded Event | ||
this._el.content_item.addEventListener('load', function(e) { | ||
this.onMediaLoaded(); | ||
}.bind(this)); | ||
this._el.content_item.src = resp.thumbnail_url | ||
// After Loaded | ||
this.onLoaded(); | ||
} | ||
/** | ||
* Break out from AJAX call for clarity. Remember to .bind() a this value. | ||
* @param {XMLHttpResponse} resp | ||
*/ | ||
function errorHandler(resp) { | ||
let msg = `${resp.statusText} [${resp.status}]` | ||
if (resp.status == 400) { | ||
msg = this._('instagram_bad_request') | ||
} | ||
this.loadErrorDisplay(msg) | ||
} | ||
export default class Instagram extends Media { | ||
_loadMedia() { | ||
@@ -14,56 +74,45 @@ // Get Media ID | ||
// After Loaded | ||
this.onLoaded(); | ||
} | ||
createMedia() { | ||
this.oembed_response = null; | ||
var self = this; | ||
// Link | ||
this._el.content_link = this.domCreate("a", "", this._el.content); | ||
this._el.content_link.href = this.data.url; | ||
this._el.content_link.target = "_blank"; | ||
let data_url = `${API_URL_ROOT}${this.data.url}` | ||
try { | ||
ajax({ // getJSON doesn't let us set an errorhandler :-( | ||
url: data_url, | ||
dataType: 'json', | ||
success: successHandler, | ||
error: errorHandler, | ||
context: this | ||
}) | ||
} catch (e) { | ||
console.log(`Instagram: error fetching ${data_url}`) | ||
console.log(e) | ||
debugger; | ||
} | ||
// Photo | ||
this._el.content_item = this.domCreate("img", "tl-media-item tl-media-image tl-media-instagram tl-media-shadow", this._el.content_link); | ||
if (this.data.alt) { | ||
this._el.content_item.alt = this.data.alt; | ||
} else if (this.data.caption) { | ||
this._el.content_item.alt = unhtmlify(this.data.caption); | ||
} | ||
} | ||
if (this.data.title) { | ||
this._el.content_item.title = this.data.title; | ||
} else if (this.data.caption) { | ||
this._el.content_item.title = unhtmlify(this.data.caption); | ||
getImageURL() { | ||
if (this.oembed_response && this.oembed_response.thumbnail_url) { | ||
return this.oembed_response.thumbnail_url | ||
} | ||
// Media Loaded Event | ||
this._el.content_item.addEventListener('load', function(e) { | ||
self.onMediaLoaded(); | ||
}); | ||
this._el.content_item.src = this.getImageURL(this._el.content.offsetWidth); | ||
fetchJSON(`${API_URL_ROOT}${this.data.url}`).then(json => { | ||
return json.thumbnail_url | ||
}).catch(err => { | ||
trace(`Instagram getImageURL Error: ${err.status} ${err.statusText}`) | ||
}) | ||
} | ||
getImageURL(w, h) { | ||
let img_url = "https://instagram.com/p/" + this.media_id + "/media/?size=" + this.sizes(w) | ||
trace('insta URL', img_url) | ||
return img_url; | ||
} | ||
_getMeta() { | ||
var self = this, | ||
api_url; | ||
// API URL | ||
api_url = "https://api.instagram.com/oembed?url=https://instagr.am/p/" + this.media_id + "&callback=?"; | ||
// API Call | ||
getJSON(api_url, function(d) { | ||
self.data.credit_alternate = "<a href='" + d.author_url + "' target='_blank'>" + d.author_name + "</a>"; | ||
self.data.caption_alternate = d.title; | ||
self.updateMeta(); | ||
}); | ||
if (this.oembed_response && this.oembed_response.author_name) { | ||
this.data.credit_alternate = `Instagram: <a href="https://instagram.com/${this.oembed_response.author_name}" target="_blank">@${this.oembed_response.author_name}</a>` | ||
} | ||
// nothing in our data helps us provide an alternative caption... | ||
// this.data.caption_alternate = d.title; | ||
this.updateMeta(); | ||
} | ||
@@ -70,0 +119,0 @@ |
@@ -1437,2 +1437,37 @@ var Zepto = (function() { | ||
/** | ||
* Add a promisified option to better handle cases where we need the data | ||
* synchronously. | ||
* @param {String} url | ||
*/ | ||
$.fetchJSON = function (url) { | ||
var request = new XMLHttpRequest(); | ||
return new Promise(function (resolve, reject) { | ||
// Setup our listener to process compeleted requests | ||
request.onreadystatechange = function () { | ||
// Only run if the request is complete | ||
if (request.readyState !== 4) return; | ||
// Process the response | ||
if (request.status >= 200 && request.status < 300) { | ||
var json = JSON.parse(request.responseText) | ||
resolve(json); | ||
} else { | ||
reject({ | ||
status: request.status, | ||
statusText: request.statusText | ||
}); | ||
} | ||
}; | ||
// Setup our HTTP request | ||
request.open('GET', url, true); | ||
// Send the request | ||
request.send(); | ||
}) | ||
} | ||
$.fn.load = function(url, data, success){ | ||
@@ -1553,4 +1588,4 @@ if (!this.length) return this | ||
export const ajax = Zepto.ajax; | ||
export const fetchJSON = Zepto.fetchJSON; | ||
// Based on https://github.com/madrobby/zepto/blob/5585fe00f1828711c04208372265a5d71e3238d1/src/ajax.js | ||
@@ -1557,0 +1592,0 @@ // Zepto.js |
@@ -210,3 +210,3 @@ import * as DOM from "../dom/DOM" | ||
this.options.font.indexOf('http') == 0 || | ||
this.options.font.match(/^[^A-Za-z]/))) { | ||
this.options.font.match(/\.css$/))) { | ||
font_css_url = this.options.font | ||
@@ -222,3 +222,5 @@ } else if (this.options.font) { | ||
if (this.options.theme && this.options.theme.indexOf('http') == 0) { | ||
if (this.options.theme && ( | ||
this.options.theme.indexOf('http') == 0 || | ||
this.options.theme.match(/\.css$/))) { | ||
theme_css_url = this.options.theme | ||
@@ -225,0 +227,0 @@ } else if (this.options.theme) { |
@@ -24,3 +24,3 @@ [{ | ||
"question": "There aren't enough options. I want more control over the [font size/color/etc]. Can I change things using CSS?", | ||
"answer": "Because there are so many details to the styling, this is not exactly simple, but, if you have some technical capacity, you can override TimelineJS's <abbr title='Cascading Style Sheets'>CSS</abbr> rules and have complete control over the look of the timeline. For details, see <a href='/docs/overriding-styles.html'>Using the TimelineJS CSS selectors</a>. You will need to be able to <a href='/docs/instantiate-a-timeline.html'>instantiate the Timeline</a> in javascript on your own page. (There is no way to override the CSS using the <code>iframe</code> embed.) Then, either in <code><style></code> tags in that page, or in an external stylesheet, you can specify CSS rules changing some or all of TimelineJS's default presentation. The basis of TimelineJS's styles are in <a href='https://github.com/NUKnightLab/TimelineJS3/tree/master/src/less'>these files</a>, which use the <a href='http://lesscss.org/'>Less CSS preprocessor</a>." | ||
"answer": "Because there are so many details to the styling, this is not exactly simple, but, if you have some technical capacity, you can override TimelineJS's <abbr title='Cascading Style Sheets'>CSS</abbr> rules and have complete control over the look of the timeline. For details, see <a href='/docs/overriding-styles.html'>Using the TimelineJS CSS selectors</a>." | ||
}, | ||
@@ -27,0 +27,0 @@ { |
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
Sorry, the diff of this file is not supported yet
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
5368932
23357
416