(function(Instajam) {
'use strict';
(function(Instajam) {
'use strict';
Instajam.init = function(options) {
options = options || {};
Throw an error if either the client ID or the redirect URI isn't provided.
if (!options.clientId || !options.redirectUri) {
throw new InstajamError("Client ID and Redirect URI are required.");
}
If the app is requesting additional scopes, build a string to append to the auth URL.
if (options.scope && typeof options.scope === 'object') {
this.scope = '&scope=' + options.scope.join('+');
} else {
this.scope = '&scope=basic';
}
Build an authentication URL using constructor parameters.
this.authUrl = 'https://instagram.com/oauth/authorize/?client_id=' + options.clientId + '&redirect_uri=' + options.redirectUri + '&response_type=token' + (this.scope || '');
When the library is initialized, verify whether a user is currently authenticated.
this.authenticate();
return this;
};
Attempts to authenticate a user via localStorage data or by parsing data from the URL hash.
Instajam.authenticate = function() {
First, check if a localStorage key exists for the access_token...
if (localStorage.getItem('instagram_access_token')) {
...and if there is, set the authenticated property to true.
this.authenticated = true;
If there is no localStorage key...
} else {
...then check if there's a match for access_token in the URL hash.
if (hashParam('access_token')) {
If we can parse the access_token from the URL hash, set the localStorage param...
localStorage.setItem('instagram_access_token', hashParam('access_token', true));
...and set the authenticated property to true
this.authenticated = true;
} else {
Otherwise, if there is no localStorage key and there is nothing to parse from the hash, set the authenticated property to false
this.authenticated = false;
}
}
};
Effectively de-authenticates the current user by removing their access token from localStorage and setting the authenticated property to false. This does not revoke your app's permissions on the server.
Instajam.deauthenticate = function() {
localStorage.removeItem('instagram_access_token');
this.authenticated = false;
};
var User = function() {};
var Self = function() {};
User.prototype.self = new Self();
Self.prototype.profile = function(callback) {
request({
url: 'users/self',
success: callback
});
};
Self.prototype.media = function(options, callback) {
Make the options argument optional
if (typeof options === 'function') {
callback = options;
options = null;
}
Make a request to the API
request({
url: 'users/self/media/recent',
data: options,
success: callback
});
};
Self.prototype.feed = function(options, callback) {
Make the options argument optional
if (typeof options === 'function') {
callback = options;
options = null;
}
Make a request to the API
request({
url: 'users/self/feed',
data: options,
success: callback
});
};
Self.prototype.favorites = function(options, callback) {
Make the options argument optional
if (typeof options === 'function') {
callback = options;
options = null;
}
Make a request to the API
request({
url: 'users/self/media/liked',
data: options,
success: callback
});
};
User.prototype.requests = function(callback) {
Make a request to the API
request({
url: 'users/self/requested-by',
success: callback
});
};
User.prototype.relationshipWith = function(id, callback) {
Make a request to the API
request({
url: 'users/' + id + '/relationship',
success: callback
});
};
User.prototype.get = function(id, callback) {
Require that an ID or username be passed
if (!id) {
throw new InstajamError('A user\'s ID or username is required for user.get()');
}
if (typeof id === 'number') {
Make a request to the API
request({
url: 'users/' + id,
success: callback
});
} else if (typeof id === 'string') {
Make a request to the API
User.prototype.search.call(this, id, {}, function(result) {
If the initial user search yields any results, then just return the first, but otherwise return nothing.
if (result.data && result.data.length === 1) {
result = result.data[0];
} else {
result = false;
}
Call the initial callback, passing the result
if (typeof callback === 'function') {
callback(result);
}
});
}
};
User.prototype.media = function(id, options, callback) {
Require that an ID be passed
if (!id) {
throw new InstajamError('A user\'s ID or username is required for user.media()');
}
Make the options argument optional
if (typeof options === 'function' && !callback) {
callback = options;
options = null;
}
If we're looking up the user by ID...
if (typeof id === 'number') {
Make a request to that API
request({
url: 'users/' + id + '/media/recent',
data: options,
success: callback
});
}
Or rather looking up the user by username...
else if (typeof id === 'string') {
...then first search for the username...
User.prototype.search.call(this, id, {}, function(result) {
If the initial user search yields any results, then just return the first, but otherwise return nothing.
if (result.data && result.data.length > 0) {
result = result.data[0];
} else {
result = false;
}
if (result) {
Make a request to that API
request({
url: 'users/' + result.id + '/media/recent',
data: options,
success: callback
});
} else {
if (typeof callback === 'function') {
callback(result);
}
}
});
}
};
User.prototype.search = function(term, options, callback) {
Require that a search term be passed
if (!term) {
throw new InstajamError('A search term is required for user.search()');
}
Make the options argument optional
if (typeof options === 'function') {
callback = options;
options = {};
}
Add the search term to the options object
options.q = term;
Make a request to the API
request({
url: 'users/search',
data: options,
success: callback
});
};
User.prototype.follows = function(id, callback) {
Make a request to the API
request({
url: 'users/' + id + '/follows',
success: callback
});
};
User.prototype.following = function(id, callback) {
Make a request to the API
request({
url: 'users/' + id + '/followed-by',
success: callback
});
};
var Media = function() {};
Media.prototype.get = function(id, callback) {
Make a request to the API
request({
url: 'media/' + id,
success: callback
});
};
Media.prototype.search = function(options, callback) {
options = options || {};
Require that a latitude and longitude are passed in, at a minimum.
if (!options.lat || !options.lng) {
throw new InstajamError('A latitude AND a longitude are required for media.search()');
}
Make a request to the API
request({
url: 'media/search',
data: options,
success: callback
});
};
Media.prototype.popular = function(callback) {
Make a request to the API
request({
url: 'media/popular',
success: callback
});
};
Media.prototype.comments = function(id, callback) {
if (!id) {
throw new InstajamError('A media ID is required for media.comments()');
}
Make a request to the API
request({
url: 'media/' + id + '/comments',
success: callback
});
};
Media.prototype.likes = function(id, callback) {
if (!id) {
throw new InstajamError('A media ID is required for media.likes()');
}
Make a request to the API
request({
url: 'media/' + id + '/likes',
success: callback
});
};
var Tag = function() {};
Tag.prototype.get = function(name, callback) {
We need at least a tag name to get information for
if (!name) {
throw new InstajamError('A tag name is required for tag.get()');
}
Make a request to the API
request({
url: 'tags/' + name,
success: callback
});
};
Tag.prototype.media = function(name, options, callback) {
We need at least a tag name to work with
if (!name) {
throw new InstajamError('A tag name is required for tag.media()');
}
Make the options argument optional
if (typeof options === 'function' && !callback) {
callback = options;
options = {};
}
Make a request to the API
request({
url: 'tags/' + name + '/media/recent',
data: options,
success: callback
});
};
Tag.prototype.search = function(term, callback) {
We need at least a tag string to search for
if (!term) {
throw new InstajamError('A tag name is required for tag.search()');
}
var options = {
q: term
};
Make a request to the API
request({
url: '/tags/search',
data: options,
success: callback
});
};
var Location = function() {};
Location.prototype.get = function(id, callback) {
We need at least a location ID to work with
if (!id) {
throw new InstajamError('An ID is required for location.get()');
}
Make a request to the API
request({
url: 'locations/' + id,
success: callback
});
};
Location.prototype.media = function(id, options, callback) {
We need at least a location ID to work with
if (!id) {
throw new InstajamError('An ID is required for location.get()');
}
Make the options argument optional
if (typeof options === 'function' && !callback) {
callback = options;
options = {};
}
Make a request to the API
request({
url: 'locations/' + id + '/media/recent',
success: callback
});
};
Location.prototype.search = function(options, callback) {
options = options || {};
We need at LEAST a lat/lng pair, or a Foursquare ID to work with
if ( (!options.lat || !options.lng) && !options.foursquare_v2_id) {
throw new InstajamError('A latitude and longitude OR a Foursquare place ID is required for location.search()');
}
Make a request to the API
request({
url: 'locations/search',
data: options,
success: callback
});
};
var Geography = function() {};
Geography.prototype.media = function(id, options, callback) {
We need at least a Geography ID to work with
if (!id) {
throw new InstajamError('A Geography ID is required for geography.get()');
}
The options argument defaults to an empty object
options = options || {};
Make a request to the API
request({
url: 'geographies/' + id + '/media/recent',
data: options,
success: callback
});
};
Returns the client-specific authentication URL that is created upon initialization.
Parses a given parameter from the browsers hash. Optionally, the parameter can be removed from the URL upon successful matching.
function hashParam (param, remove) {
Create a RegExp object for parsing params
var regex = new RegExp("(?:&|#)" + param + "=([a-z0-9._-]+)", "i");
Look for matches in the windows hash
var matches = window.location.hash.match(regex);
If matches are found...
if (matches) {
...then remove the parameter if specified
if (remove) {
var removeRegex = new RegExp("(?:&|#)" + param + "=" + matches[1], "i");
window.location.hash = window.location.hash.replace(removeRegex, '');
}
...and return the first matching param
return matches[1];
}
Otherwise return false if no matching params are found
return false;
}
Makes JSONP requests to the Instagram API
function request (options) {
var urlBase = 'https://api.instagram.com/v1/',
callbackName = 'instajam' + Math.round(new Date().getTime() / 1000) + Math.floor(Math.random() * 100);
options = options || {};
options.data = options.data || {};
options.data.access_token = localStorage.getItem('instagram_access_token');
options.data.callback = callbackName;
var queryString = serializeParams(options.data);
if (options.url) {
options.url = urlBase + options.url + '?' + queryString;
window[callbackName] = function(data) {
if (typeof options.success === 'function') {
options.success(data);
}
script.parentNode.removeChild(script);
delete window[callbackName];
};
var script = document.createElement('script');
script.type = 'text/javascript';
script.src = options.url;
document.getElementsByTagName('body')[0].appendChild(script);
} else {
throw new InstajamError("Instajam:: Missing request URL");
}
}
Given a JavaScript object, return a string suitable for passing in a URL
function serializeParams (obj) {
var str = [];
for (var p in obj) {
str.push(encodeURIComponent(p) + '=' + encodeURIComponent(obj[p]));
}
return str.join('&');
}
Define a custom error object
function InstajamError (message) {
this.name = "InstajamError";
this.message = message || '';
}
InstajamError.prototype = Error.prototype;
Return new instances of the endpoint helpers as top-level keys
Instajam.user = new User();
Instajam.media = new Media();
Instajam.tag = new Tag();
Instajam.location = new Location();
Instajam.geography = new Geography();
}(window.Instajam = window.Instajam || {}));