suki.sprd
Version:
Spreadshirt extension for suki.js
784 lines (589 loc) • 14.5 kB
JavaScript
define([
'./suki.js',
'./polyfill.js'
], function(suki, polyfill) {
suki = suki.extend();
// ---
var Connection, connection;
/**
* TODO: check @params
* TODO: check @example
* TODO: check if every example has its test representation
*/
/**
* @constructor
*/
Connection = function(name, defaults, debug) {
this.attributes = {
_name : name || null,
_debug : debug || false,
_schema : null,
_config : {
functionAutoExec : false,
schemaStrict : false
},
_events : new suki.Events(),
// ---
context : null,
contextId : null,
country : 'US',
endpoint : null,
id : null,
language : 'en',
locale : 'en_US',
platform : 'NA',
proxy : null,
type : 'json'
};
// ---
suki.util.extend(this.attributes, defaults || {});
// ---
this.attributesPrev = {};
};
Connection.prototype = new suki.Base;
Connection.prototype.me = function() { return 'connection'; };
/**
* @function .locale(str)
* Builds `location` object containing valid `country`, `language` and
* `locale` attributes. Also invokes some mapping procedures to fix
* those weird (WTF!) Spreadshirt locales.
* @param (str)(opt) locale
* @return {this}
*/
Connection.prototype.locale = function(locale) {
var that = this;
// ---
if (locale) this.set('locale', locale);
// ---
function add() {
var language
, locale
, location = {}
, country;
// ---
var arr,
pattern;
// ---
locale = that.get('locale');
// ---
// de-DE
pattern = new RegExp('-');
if (pattern.test(locale)) {
arr = locale.split('-');
language = arr[0].toLowerCase();
if (arr.length > 1) country = arr[1].toUpperCase();
}
// de_DE
pattern = new RegExp('');
if (pattern.test(locale)) {
arr = locale.split('');
language = arr[0].toLowerCase();
if (arr.length > 1) country = arr[1].toUpperCase();
}
// de
// if language is still undefined, locale
// comes without country
if (!language) language = locale.toLowerCase();
// ---
$.extend(location, {
'country' : country,
'language' : language,
'locale' : (function(language, country) {
// de
if (!country) return language;
// de_DE
return language + '' + country;
})(language, country)
});
// ---
return location;
}
function map() {
var map = polyfill.api.map.language;
// ---
var location
, language = that.get('language')
, country = that.get('country')
, locale = that.get('locale')
, platform = that.get('platform');
// ---
for (var key in map) {
if (key === language) {
location = map[key];
}
}
// ---
//
// if language not found, use platform specific fallback
// if found
// -> check if we have a country
// if found
// -> check if we have a country specific languageObj
// if found
// -> (+)
// if not
// -> (+) fallback, based on platform and language
// if not
// -> (+) fallback based on platform and language
//
if (location) {
if (location.locale) {
// single country language
return location;
} else {
// multi country language
if (country) {
// known country
location = map[language][country] || null;
if (!location) {
switch (platform) {
case 'EU' :
switch (language) {
case 'de' :
location = map['de']['DE'];
break;
case 'fr' :
location = map['fr']['FR'];
break;
default : // en
location = map['en']['EU'];
break;
}
break;
default : // NA
switch (location.language) {
case 'fr' :
location = map['fr']['CA'];
break;
default : // en
location = map['en']['US'];
break;
}
break;
}
}
return location;
} else {
// unknown country
switch (platform) {
case 'EU' :
switch (language) {
case 'de' :
location = map['de']['DE'];
break;
case 'fr' :
location = map['fr']['FR'];
break;
default : // en
location = map['en']['EU'];
break;
}
break;
default : // NA
switch (location.language) {
case 'fr' :
location = map['fr']['CA'];
break;
default : // en
location = map['en']['US'];
break;
}
break;
}
return location;
}
}
} else {
// fallback to platform specific
// location obj
switch (platform) {
case 'EU' :
location = map['en']['EU'];
break;
default : // NA
location = map['en']['US'];
break;
}
return location;
}
}
// ---
this.set(add());
this.set(map());
// ---
return this;
};
/**
* @function .endpoint()
* Creates valid endpoint for calls to Spreadshirt's API, based
* on platform or optional proxy settings. If `proxy` is set on
* connection instance, it searches for string `:platform`, if
* found this will be replaced by platform (`EU` or `NA`,
* uppercase), if not platform will be added at the end
* ([proxy]/EU or [proxy]/NA).
* @param (str)(opt) proxy
* @return {this}
*/
Connection.prototype.endpoint = function(proxy) {
var platform
, endpoint
, map
, proxy
, model
, pattern;
// ---
if (proxy) this.set('proxy', proxy);
// ---
map = polyfill.api.map.endpoint;
// ---
platform = this.get('platform');
proxy = this.get('proxy');
// ---
if (proxy) {
// if proxy set, check if given string contains playholder
// `:platform` that has to replaced with the `platform` str,
// if not add `platform` str to the end of url
pattern = new RegExp(':platform');
if (pattern.test(proxy)) {
endpoint = proxy.replace(':platform', platform);
} else {
endpoint = proxy + '/' + platform;
}
} else {
// if proxy not set, use original sprd `endpoint`, won't
// work on other domains than:
// `www.spreadshirt.net` (EU)
// `www.spreadshirt.com` (NA)
endpoint = map[platform];
}
// ---
this.set('endpoint', endpoint);
// ---
return this;
};
/**
* @function .end()
* Allows to work in instance's context (callback style), if
* callback is set
* @param (func)(opt) fn
* invoked in context of `this`, gets `err` obj or `null` as
* 1st argument (for consistency reasons), 2nd parameter is
* plain `attributes` obj.
* @callback
*
* @param err
* @param attributes
*
* @return {this}
* @example
*
* ...
* .set('name', 'Peter')
* .end(function(err, attr) {
*
* // returns 'Peter'
* console.log(attr.name);
*
* // work in context of `this`
* this.set('name', 'Chris');
*
* // returns 'Chris'
* console.log(this.get('name'));
*
* // Attention: still returns 'Peter'
* // `attr` is local, no reference to changed
* // `this._attributes`
* console.log(attr.name);
*
* });
*
*/
Connection.prototype.end = function(fn) {
if (fn) return fn.call(this, null, this.get());
return this;
};
/**
* @function .api()
* Public wrapper for request method functions.
* @return {Object}
*/
Connection.prototype._api = function() {
var that = this;
return {
get : function(url, query, callback) {
return that._apiGet.call(that, url, query, callback);
},
post : function(url, data, query, callback) {
return that._apiPost.call(that, url, data, query, callback);
},
put : function(url, data, query, callback) {
return that._apiPut.call(that, url, data, query, callback);
},
del : function(url, query, callback) {
return that._apiDelete.call(that, url, query, callback);
}
};
};
/**
* @function ._prepareQuery(obj)
* Adds query params to Spreadshirt specific default
* query params.
* @param (obj)(req) query
* @return {Object}
* @private
*/
Connection.prototype._prepareQuery = function(query) {
var connection = this.get();
// ---
query = query || {};
// ---
var obj = {
apiKey : connection.id,
locale : connection.locale,
mediaType : connection.type
};
// ---
suki.util.extend(obj, query);
return obj;
};
/**
* @function ._prepareUrl(str)
* Builds request url based on proxy, endpoint, context and
* contextId settings.
* @param (str)(req) url
* @return {String}
* @private
*/
Connection.prototype._prepareUrl = function(url) {
var connection = this.get();
// ---
// TODO: add feature to handle fully qualified API urls
// ---
url = url || '';
// ---
var path = ''
, context = connection.context || null
, contextId = connection.contextId || null
, endpoint = connection.endpoint;
if (context) {
path += endpoint;
path += '/';
path += context;
path += (contextId) ? '/' + contextId : '';
path += url;
} else {
path += endpoint;
path += url;
}
return path;
};
/**
* @function ._prepareData(obj)
* Placeholder method in case data object needs to be changed
* before send.
* @param (obj)(req) data
* @return {Object}
* @private
*/
Connection.prototype._prepareData = function(data) {
return data;
};
/**
* @function ._apiGet(str, [obj], [func])
* Internal representation of `.api.get()`, prepares incoming
* `url` and optional `query` to make valid Spreadshirt API
* calls.
* @param (str)(req) url
* can be either fully qualified Spreadshirt API
* `https://api.spreadshirt.net/api/v1/shops/205909?mediaType=json`
* or valid API uri
* `/articles`
* @param (obj)(opt) query
* @param (fun)(opt) cb
* @private
*/
Connection.prototype._apiGet = function(url, query, cb) {
// no query, but callback
if (suki.util.is.function(query)) {
cb = query;
query = {};
}
// ---
url = this._prepareUrl(url);
query = this._prepareQuery(query);
// ---
suki.request
.get(url)
.query(query)
.end(function(err, res) {
(cb) ? cb(err, res) : suki.util.noop;
});
};
/**
* @function ._apiPost(str, [obj], [obj], [func])
* Internal representation of `.api.post()`, prepares incoming
* `url` and optional `query` to make valid Spreadshirt API
* calls.
* @param (str)(req) url
* can be either fully qualified Spreadshirt API
* `https://api.spreadshirt.net/api/v1/shops/205909?mediaType=json`
* or valid API uri
* `/articles`
* @param (obj)(req) data
* @param (obj)(opt) query
* @param (fun)(opt) cb
* @private
*/
Connection.prototype._apiPost = function(url, data, query, cb) {
// no query, but callback
if (suki.util.is.function(query)) {
cb = query;
query = {};
}
// ---
url = this._prepareUrl(url);
query = this._prepareQuery(query);
data = this._prepareData(data);
// ---
suki.request
.post(url)
.data(data)
.query(query)
.end(function(err, res) {
console.log(8);
cb(err, res);
});
};
/**
* @function ._apiPut(str, [obj], [obj], [func])
* Internal representation of `.api.put()`, prepares incoming
* `url` and optional `query` to make valid Spreadshirt API
* calls.
* @param (str)(req) url
* can be either fully qualified Spreadshirt API
* `https://api.spreadshirt.net/api/v1/shops/205909?mediaType=json`
* or valid API uri
* `/articles`
* @param (obj)(req) data
* @param (obj)(opt) query
* @param (fun)(opt) cb
* @private
*/
Connection.prototype._apiPut = function(url, data, query, cb) {
// no query, but callback
if (suki.util.is.function(query)) {
cb = query;
query = {};
}
// ---
url = this._prepareUrl(url);
query = this._prepareQuery(query);
data = this._prepareData(data);
// ---
suki.request
.put(url)
.data(data)
.query(query)
.end(function(err, res) {
cb(err, res);
});
};
/**
* @function ._apiDelete(str, [obj], [func])
* Internal representation of `.api.del()`, prepares incoming
* `url` and optional `query` to make valid Spreadshirt API
* calls.
* @param (str)(req) url
* can be either fully qualified Spreadshirt API
* `https://api.spreadshirt.net/api/v1/shops/205909?mediaType=json`
* or valid API uri
* `/articles`
* @param (obj)(opt) query
* @param (fun)(opt) cb
* @private
*/
Connection.prototype._apiDelete = function(url, query, cb) {
// no query, but callback
if (suki.util.is.function(query)) {
cb = query;
query = {};
}
// ---
url = this._prepareUrl(url);
query = this._prepareQuery(query);
// ---
suki.request
.del(url)
.query(query)
.end(function(err, res) {
cb(err, res);
});
};
/**
* @static
* Static object that holds methods to be exported to `requirejs`.
*/
connection = Connection;
/**
* @function .init()
* Creates new instance of `Connection`, exports API.
* @param (str)(req) name
* @param (obj)(opt) defaults
* @return {Object}
*
* @api get
* @api set
* @api end
* @api api.get
* @api api.post
* @api api.put
* @api api.del
*
* @static
*/
connection.init = function(name, defaults, debug) {
if (suki.util.is.boolean(defaults)) {
debug = defaults;
defaults = {};
} else {
defaults = defaults || {};
}
// ---
var inst
, exports;
// ---
inst = new Connection(name, defaults, debug);
// ---
inst.locale();
inst.endpoint();
// ---
exports = {
get : function(key) {
return inst.get.call(inst, key);
},
set : function(key, value) {
return inst.set.call(inst, key, value);
},
end : function(callback) {
return inst.end.call(inst, callback);
},
locale : function(locale) {
return inst.locale.call(inst, locale);
},
endpoint : function(proxy) {
return inst.endpoint.call(inst, proxy);
},
api : inst._api.call(inst),
me : function() {
return inst.me.call(inst);
}
};
// ---
if (inst.get('_debug') === true) {
suki.util.extend(exports, inst);
}
// ---
return exports;
};
return Connection;
});