(function () {
Ipsp.js version 1.3.1
Ipsp JS Modules - юзать могут все <:)
а работать будет только у нас ;)
Button Checkout Url
var button = $ipsp.get('button');
button.setMerchantId(1000);
button.setHost('api.oplata.com');
button.setAmount(100,'UAH');
button.setResponseUrl('http://site.com/result/');
button.addField({
label:'ФИО',
name:'fio',
value:'Желе',
required:true,
valid:{}
});
var url = button.getUrl();
In-Page Checkout
$ipsp.get('checkout').config({
'wrapper': '#frameholder' ,
'styles' : {
'body':{'overflow':'hidden'},
'.page-section-shopinfo':{display:'none'},
'.page-section-footer':{display:'none'}
}
}).scope(function(){
this.width(480);
this.height(480);
this.loadUrl(url);
});
Handle Checkout Data
$ipsp.get('checkout').config({
'wrapper':'#frameholder',
'styles' : {},
}).scope(function(){
this.width(480);
this.height(480);
this.addCallback(__DEFAULTCALLBACK__);
this.loadUrl(url);
});
Fullscreen Checkout
$ipsp.get('checkout').config({
'wrapper':'body',
'ismodal':true,
'styles' : {
'body':{'overflow':'hidden'},
'.page-section-shopinfo':{display:'none'},
'.page-section-footer':{display:'none'}
}
}).scope(function(){
this.loadUrl(url);
});
Ipsp Modules Wrapper example:
$ipsp('checkout'); // return singleton object
$ipsp.get('checkout'); // create new instance
(function () {
ipsp module version
var version = '1.3.1';
defined list of existing ipsp modules
var modules = {};
defined list of singleton module instances
var instance = {};
create instance of ipsp module class always return singleton object by module name
this.$ipsp = function (name) {
if (instance[name])
return instance[name];
return (instance[name] = arguments.callee.get(name) );
};
create new instance of ipsp module class always return new object;
this.$ipsp.get = function (name) {
if (!modules[name])
throw Error('module is undefined');
return new modules[name];
};
Add class to ipsp module wrapper
this.$ipsp.add = function (name, module) {
if (modules[name]) {
throw Error('module already added');
}
modules[name] = module;
};
Setup ipsp version
this.$ipsp.version = function (v) {
version = v;
return this;
};
this.$ipsp._debug_ = (function(){
return Number(document.cookie.replace(/(?:(?:^|.*;\s*)ipsp_debug\s*\=\s*([^;]*).*$)|^.*$/,"$1"));
})();
this.$ipsp.debug = function(state){
document.cookie = ['ipsp_debug',Number(state)].join('=');
};
this.$ipsp.log = function(){
if(this._debug_ && 'console' in window){
console.log.apply(console,arguments);
}
};
}).call(window || {});
Oplata Namespace support
(function () {
this.$oplata = this.$ipsp;
}).call(window || {});
Add Event Listener Helper
(function(){
this.addListener = function(el,type,callback){
if(!el) return false;
if(el.addEventListener) el.addEventListener(type, callback);
else if(el.attachEvent) el.attachEvent('on'+type,callback);
};
})();
JS Errors handler
(function(){
addListener(window,'error',function(ev){
$ipsp.log(ev.message,ev.filename,ev.lineno,ev.colno);
});
})();
String Helpers
(function () {
this.camelCase = function (s) {
return (s || '').toLowerCase().replace(/(\b|-)\w/g, function (m) {
return m.toUpperCase().replace(/-/, '');
});
};
}).call(window || {});
Type Helpers
(function () {
var type = function (o) {
return ({}).toString.call(o).match(/\s([a-zA-Z]+)/)[1].toLowerCase();
};
this.isObject = function (o) {
return type(o) === 'object';
};
this.isRegexp = function (o) {
return type(o) === 'regexp';
};
this.isArguments = function (o) {
return type(o) === 'arguments';
};
this.isError = function (o) {
return type(o) === 'error';
};
this.isArray = function (o) {
return type(o) === 'array';
};
this.isDate = function (o) {
return type(o) === 'date';
};
this.isString = function (o) {
return type(o) === 'string';
};
this.isNumber = function (o) {
return type(o) === 'number';
};
this.isBoolean = function (o) {
return type(o) === 'boolean';
};
this.isElement = function (o) {
return o && o.nodeType === 1;
};
this.getType = type;
}).call(window || {});
Popup Blocker Test
(function () {
this.popupBlocker = function (poppedWindow) {
var result = false;
try {
if (typeof poppedWindow == 'undefined') {
result = true;
} else if (poppedWindow && poppedWindow.closed) {
result = false;
} else if (poppedWindow && poppedWindow.test) {
result = false;
} else {
result = true;
}
} catch (err) {
}
return result;
};
}).call(window || {});
Form Helpers
(function () {
this.prepareFormData = function (url, data, target) {
var elem;
var form = document.createElement('form');
form.action = url;
form.target = target || '_self';
form.method = 'POST';
for (var prop in data) {
if (data.hasOwnProperty(prop)) {
elem = document.createElement('input');
elem.type = 'hidden';
elem.name = prop;
elem.value = data[prop];
form.appendChild(elem);
}
}
form.style.display = 'none';
return form;
};
}).call(window || {});
inspired by John Resig class inheritance
(function () {
Define init flag
var init = false;
var fnTest = /xyz/.test(function (){ xyz;}) ? /\b_super\b/ : /.*/;
Class constructor
this.Class = function () {
if (!(this instanceof arguments.callee))
throw Error('use Class with "extend" method');
};
Class prototype
this.Class.prototype = {
init: function () {
}
};
Class.extend function use to make inherit class
this.Class.extend = function (instance) {
var prop, proto, parent = this.prototype;
init = true;
proto = new this();
init = false;
for (prop in instance) {
if (instance.hasOwnProperty(prop)) {
if (typeof(parent[prop]) == 'function' &&
typeof(instance[prop]) == 'function' &&
fnTest.test(instance[prop])
) {
proto[prop] = (function (name, fn) {
return function () {
var temp = this._super, result;
this._super = parent[name];
result = fn.apply(this, arguments);
this._super = temp;
return result;
};
})(prop, instance[prop]);
} else {
proto[prop] = instance[prop];
}
}
}
function Class(options) {
prevent call init method
if (!init)
this.init.apply(this, arguments);
}
apply new proto object as Class.prototype
Class.prototype = proto;
set constructor
Class.prototype.constructor = Class;
apply this function as Class static method
Class.extend = arguments.callee;
return new created class
return Class;
};
}).call(window || {});
(function () {
define topic list storage and subscriber uid token
var topics = {}, subUid = -1;
publish event with arguments to subscribers
this.publish = function (topic, data) {
$ipsp.log(topic,data);
if (!topics[topic]) {
return false;
}
var subscribers = topics[topic], len = subscribers ? subscribers.length : 0;
var args = Array.prototype.slice.call(arguments, 2);
var topic = topic.split('/').pop();
for (i = 0; i < len; i++) {
subscribers[i].func(data, topic);
}
return this;
};
Add listener function on specified event name
.
return subscriber token uid
this.subscribe = function (topic, func) {
if (!topics[topic]) {
topics[topic] = [];
}
var token = (++subUid).toString();
topics[topic].push({
token: token,
func: func
});
return token;
};
Remove listener function by passing subscriber token
uid
this.unsubscribe = function (token) {
for (var m in topics) {
if (topics.hasOwnProperty(m) && topics[m]) {
for (var i = 0, j = topics[m].length; i < j; i++) {
if (topics[m][i].token === token) {
topics[m].splice(i, 1);
return token;
}
}
}
}
return this;
};
}).call(window.pubsub = {});
DOM Ready Helper
(function (window) {
function contentLoaded(win, fn) {
var done = false, top = true,
doc = win.document,
root = doc.documentElement,
modern = doc.addEventListener,
add = modern ? 'addEventListener' : 'attachEvent',
rem = modern ? 'removeEventListener' : 'detachEvent',
pre = modern ? '' : 'on',
init = function (e) {
if (e.type == 'readystatechange' && doc.readyState != 'complete') return;
(e.type == 'load' ? win : doc)[rem](pre + e.type, init, false);
if (!done && (done = true)) fn.call(win, e.type || e);
},
poll = function () {
try {
root.doScroll('left');
} catch (e) {
setTimeout(poll, 50);
return;
}
init('poll');
};
if (doc.readyState == 'complete') fn.call(win, 'lazy');
else {
if (!modern && root.doScroll) {
try {
top = !win.frameElement;
} catch (e) {
}
if (top) poll();
}
doc[add](pre + 'DOMContentLoaded', init, false);
doc[add](pre + 'readystatechange', init, false);
win[add](pre + 'load', init, false);
}
};
window.domReady = function (fn) {
contentLoaded(window, fn);
};
})(window);
contains handy crossbrowser methods to manipulate DOM and Events javascript api
(function () {
this.Module = Class.extend({
find element by css selector example:
.find('#block .item');
.find('body .oneblock');
return HTMLElement
find: function (selector) {
return isElement(selector) ? selector : (document.querySelector(selector) || null);
},
find list of html element by css selector example:
.findAll('body input');
.findAll('table td.item');
findAll: function (selector) {
return document.querySelectorAll(selector);
},
merge objects properties in first passed object example:
.extend(targetObject,{prop1:true,prop2:'value'});
.extend(targetObject,{prop1:true,prop2:'value'},{prop1:false,prop3:[1]});
return modified targetObject
extend: function _extend() {
var i, prop, item, obj = arguments[0], ext = Array.prototype.slice.call(arguments, 1);
for (i = 0; i < ext.length; i++) {
if (( item = ext[i]) !== null) {
for (prop in item) {
if (item.hasOwnProperty(prop)) {
obj[prop] = item[prop];
}
}
}
}
return obj;
},
Javascript closure proxy function
proxy: function (func, wrapper) {
var wrapper = wrapper || this;
return function () {
return func.apply(wrapper, Array.prototype.slice.call(arguments));
};
},
Apply css styles to element
addCss: function (elem, styles) {
if (!elem)
return false;
for (var prop in styles) {
if (styles.hasOwnProperty(prop)) {
elem.style[prop] = styles[prop];
}
}
},
Fire custom javascript event
fireEvent: function (elem, eventName) {
var evt;
if (elem) {
if (document.createEventObject) {
evt = document.createEventObject();
return elem.fireEvent('on' + eventName, evt);
} else {
evt = document.createEvent("HTMLEvents");
evt.initEvent(eventName, true, true);
return !elem.dispatchEvent(evt);
}
}
},
Crossbrowser add event listener
addEvent: function (elem, type, handler) {
if (elem) {
if (elem.addEventListener) {
elem.addEventListener(type, handler, false);
} else {
elem.attachEvent('on' + type, handler);
}
}
return this;
},
Crossbrowser add event listener
removeEvent: function (elem, type, handler) {
if (elem) {
if (elem.removeEventListener) {
elem.removeEventListener(type, handler, false);
} else {
elem.detachEvent('on' + type, handler);
}
}
return this;
},
Document ready event
onDomReady: function (fn) {
domReady(this.proxy(fn));
return this;
},
Apply attributes to specified html element
addAttr: function (elem, attributes) {
var prop;
if (!elem)
return false;
for (prop in attributes) {
if (attributes.hasOwnProperty(prop)) {
elem.setAttribute(prop, attributes[prop]);
}
}
},
use ipsp functionality in module scope
scope: function (fn) {
this.onDomReady(fn);
return this;
},
print object
print: function () {
var prop, stack = [];
for (prop in this) {
stack.push([[this.name, prop].join('.'), getType(this[prop])].join(' : '));
}
return stack.join('\n');
}
});
}).call(window || {});
example:
$ipsp('connector').setTarget( window.top || iframe );
$ipsp('connector').action('origin',function(data,type){
// receive data
});
// send data to target window
$ipsp('connector').send('actionName',object);
(function () {
var UID = -1;
this.Connector = Module.extend({
name: 'crossdomain',
origin: '*',
Connector
class constructor
init: function () {
this.addEvent(window, 'message', this.proxy(this.route));
this.setName([this.name, ++UID, location.host].join('/'));
},
set connector name
setName: function (name) {
if (name) {
this.name = name;
}
},
get connector name
getName: function () {
return this.name;
},
set connector target window
object
setTarget: function (target) {
if (target) {
this.target = target;
}
},
get connector target object eg window
or iframe.contentWindow
getTarget: function () {
return this.target || {
postMessage: function () {
}
};
},
handle window onmessage event
then parse event.data
and retrieve action
and data
properties
then publish this data to subscribers with specified action
route: function (ev) {
var response;
try {
response = JSON.parse(ev.data.toString());
} catch (e) {
return false;
}
if (this.getTarget() !== ev.source)
return false;
if (!response.action)
return false;
if (response.action == 'origin') {
this.setOrigin(response.data.origin);
}
this.publish(response.action, response.data);
},
get origin property
getOrigin: function () {
return '*';
},
set origin property
setOrigin: function (url) {
this.origin = url || '*';
},
add subscriber to handle onmessage event actions
action: function (action, fn) {
return pubsub.subscribe([this.name, action].join('/'), fn);
},
remove connector subscriber by token
removeAction: function (token) {
pubsub.unsubscribe(token);
return this;
},
direct action publish
publish: function (action, data) {
return pubsub.publish([this.name, action].join('/'), data);
},
window.postMessage
wrapper
send: function (action, data) {
this.getTarget().postMessage(JSON.stringify({
action: action,
data: data
}), this.getOrigin());
}
});
add Connector class to ipsp modules
this.$ipsp.add('connector', this.Connector);
}).call(window || {});
(function (URL) {
define location property
var HOST = URL.host;
var PROTOCOL = URL.protocol;
var ORIGIN = URL.origin;
basic iframe attributes
var attrs = {
frameborder: '0',
allowtransparency: 'true'
};
basic iframe styles
var styles = {
'zIndex': '9999',
'overflowX': 'hidden',
'border': '0',
'display': 'none',
'position': 'static',
'top': '0px',
'left': '0px',
'bottom': '0px',
'right': '0px',
'width': '100%',
'height': '100%'
};
Default Client-side callback handler access from global scope “DEFAULTCALLBACK“ example:
.addCallback(__DEFAULTCALLBACK__);
override default function:
.addCallback(function(data,type){
// your code is here...
})
var Callback = function (data, type) {
var form;
if (data.action == 'redirect') {
this.loadUrl(data.url);
return;
}
if (data.send_data.order_status=='processing'){
return;
} else {
this.unbind('ready').action('ready', function () {
this.show();
});
}
if (data.send_data && data.url) {
form = prepareFormData(data.url, data.send_data);
this.find('body').appendChild(form);
form.submit();
form.parentNode.removeChild(form);
}
};
Create Checkout
class from Module
var Checkout = Module.extend({
checkout module core methods and properties
name: '$ipsp.checkout',
version of checkout module
version: '1.0',
iframe object
iframe: null,
connector object
connector: null,
client_callback: false,
checkout class constructor
init: function () {
this.options = {
checkout_attr: 'href',
checkout_url: null,
wrapper: 'body',
styles: {},
ismodal: false
};
this.actions = {};
this.initConnector();
this.ready();
},
config: function (options) {
this.extend(this.options, options);
return this;
},
set checkout open type:
true
- open checkout in fixed position in fullscreen mode
false
- open checkout in static position inside merchant page
examples:
$ipsp('checkout').setCheckoutWrapper('#checkoutwrapper');
setModal: function (bool) {
this.options.ismodal = bool;
this.onDomReady(function () {
this.addCss(this.iframe, {
'position': this.options.ismodal === true ? 'fixed' : 'static'
});
});
},
set checkout wrapper for iframe, default value body
for modal usage
examples:
$ipsp('checkout').setCheckoutWrapper('#checkoutwrapper');
setCheckoutWrapper: function (wrapper) {
this.options.wrapper = wrapper;
},
set remote style for checkout
examples:
$ipsp('checkout').setCssStyle({
'body':{ color:'#333' }
'.selector':{ 'background-color':'#efefef' }
});
setCssStyle: function (styles) {
this.extend(this.options.styles, styles);
},
set checkout background
examples:
$ipsp('checkout').setCheckoutBg('rgba(0,0,0,0.2)');
$ipsp('checkout').setCheckoutBg('#efefef');
$ipsp('checkout').setCheckoutBg('#efefef url(/path/to/image.jpg)');
setCheckoutBg: function (value) {
this.onDomReady(function () {
this.addCss(this.iframe, {
'background': value
});
});
},
set checkout frame width
examples:
$ipsp('checkout').setCheckoutWidth(640);
$ipsp('checkout').setCheckoutWidth('100%');
setCheckoutWidth: function (size) {
if (size >= 0 || size == 'auto') {
this.onDomReady(function () {
this.addCss(this.iframe, {
'width': ''
});
this.addAttr(this.iframe, {
'width': size
});
});
}
return this;
},
alias for setCheckoutWidth
width: function (size) {
this.setCheckoutWidth(size);
return this;
},
set checkout frame height
examples:
$ipsp('checkout').setCheckoutHeight(480);
$ipsp('checkout').setCheckoutHeight('100%');
setCheckoutHeight: function (size) {
if (size >= 0 || size == 'auto') {
this.onDomReady(function () {
this.addCss(this.iframe, {
'height': ''
});
this.addAttr(this.iframe, {
'height': size
});
});
}
},
alias for setCheckoutHeight
height: function (size) {
this.setCheckoutHeight(size);
return this;
},
setCheckoutOrigin: function (url) {
if (!url)
throw Error('url param is required');
var link = document.createElement('a');
link.href = url;
this.options.checkout_url = link.origin || [link.protocol, link.host].join('//');
return this;
},
get origin checkout url
examples:
// return origin host from setCheckoutUrl() set value
$ipsp('checkout').getCheckoutOrigin();
getCheckoutOrigin: function () {
if (!this.options.checkout_url)
throw Error('checkout url is not defined');
return this.options.checkout_url;
},
set element attribute that contains checkout url
use it with method setClickElement
setElementAttr: function (attr) {
this.options.checkout_attr = attr;
},
bind click event to open checkout iframe with passing url
examples:
$ipsp('checkout').setClickElement('.test-selector');
$ipsp('checkout').setClickElement('.test-selector a');
setClickElement: function (selector) {
this.onDomReady(function () {
var i, nodes = this.findAll(selector);
for (i = 0; i < nodes.length; i++) {
this.addEvent(nodes[i], 'click', this.proxy(function (ev) {
ev.preventDefault();
this.loadUrl(ev.target.getAttribute(this.options.checkout_attr));
}));
}
});
},
load url to iframe
examples:
$ipsp('checkout').loadUrl('http://checkouturl.com/checkout?token=asd6f976gda5sd76adsf');
loadUrl: function (url) {
if (!url) throw Error('checkout url is not defined');
this.onDomReady(function () {
if (!this.iframe)
throw Error('checkout iframe is null or undefined');
this.iframe.src = url;
this.find(this.options.wrapper).appendChild(this.iframe);
});
},
get origin url from merchant page
examples:
// get host origin from current url
$ipsp('checkout').getCurrentOrigin();
getCurrentOrigin: function () {
return ORIGIN || [PROTOCOL, HOST].join('//');
},
show checkout frame
examples:
$ipsp('checkout').show();
// disable triggering show event
$ipsp('checkout').show(true);
show: function (silent) {
if (this.options.ismodal === true) {
this.addCss(this.find('body'), {
'overflow': 'hidden'
});
this.addCss(this.find('html'), {
'overflow': 'hidden'
});
}
this.addCss(this.iframe, {
'display': 'block'
});
this.iframe.focus();
if (silent !== true) {
this.connector.publish('show', {});
}
return this;
},
hide checkout frame
examples:
$ipsp('checkout').hide();
// disable triggering hide event
$ipsp('checkout').hide(true);
hide: function (silent) {
if (this.options.ismodal === true) {
this.addCss(this.find('body'), {
'overflow': ''
});
this.addCss(this.find('html'), {
'overflow': ''
});
}
this.addCss(this.iframe, {
'display': 'none'
});
if (silent !== true) {
this.connector.publish('hide', {});
}
return this;
},
send data to checkout frame
examples:
$ipsp('checkout').send('actionname',{data:{}});
$ipsp('checkout').send('actionname','');
send: function (action, params) {
this.connector.send(action, params);
return this;
},
publish:function(action,params){
this.connector.publish(action, params);
},
add handler to connector
examples:
$ipsp('checkout').action('actionname',function(data,type){});
$ipsp('checkout').action('actionname',callbackFunction);
action: function (action, callback) {
var token = this.connector.action(action, this.proxy(callback, this));
if (!isArray(this.actions[action]))
this.actions[action] = [];
this.actions[action].push(token);
return token;
},
remove action callback by token returned by method action
examples:
var token = $ipsp('checkout').action('actionname',function(data,type){});
$ipsp('checkout').removeAction(token);
removeAction: function (token) {
this.connector.removeAction(token);
return this;
},
remove action callbacks by name
examples:
$ipsp('checkout').action('actionname',function(data,type){});
$ipsp('checkout').unbind('actionname',function(data,type){});
$ipsp('checkout').unbind('actionname');
unbind: function (name) {
var tokens = this.actions[name];
for (var i = 0; i < tokens.length; i++)
this.removeAction(tokens[i]);
return this;
},
initialize iframe on DOM ready event
ready: function () {
this.onDomReady(this.initFrame);
return this;
},
initiate frame creation
initFrame: function () {
if (this.iframe) throw Error('iframe already initialized');
this.iframe = document.createElement('iframe');
this.addCss(this.iframe, styles);
this.addAttr(this.iframe, attrs);
this.addEvent(this.iframe, 'load', this.proxy(function (frame) {
this.loadConnector(this.iframe);
}));
},
init connector
initConnector: function () {
this.connector = new Connector;
this.action('load', function (data) {
this.send('origin', {
origin: this.getCurrentOrigin(),
styles: this.options.styles
});
});
this.action('cancel', function (data) {
if (this.options.ismodal)
this.hide();
});
this.action('locale', function (data) {
this.locale = data;
});
this.action('ready', function (data) {
this.show();
});
this.action('3dsform', function (data) {
this.acsCallback(data);
});
this.action('callback',this.callback);
},
default callback action handler
for client-side usage unbind callback action and set your own
examples:
$ipsp('checkout').unbind('callback');
$ipsp('checkout').action('callback',function(data,type){});
callback: function(data,type){
this.send(type,data);
},
set acs handler function
setAcsCallback: function (fn) {
this.acsCallback = fn;
},
addCallback: function (fn) {
if(!fn) fn = Callback;
if(!this.client_callback) {
this.unbind('callback');
this.client_callback = true;
}
this.action('callback',fn);
this.action('decline',fn);
return this;
},
acs handler open popup dialog
acsCallback: function (data) {
var checkout = this;
var acsframe = $ipsp('acsframe');
var popup = $ipsp.get('popup');
popup.config({
width: '700px'
});
popup.close = this.proxy(function () {
this.send('cancel');
});
this.action('close_submit3ds', function (data) {
acsframe.send('close');
});
popup.title.innerHTML = this.locale.HELP_3DS;
this.addEvent(popup.title.querySelector('a'), 'click', function () {
acsframe.submitHelp();
});
acsframe.scope(function () {
this.setData(data);
this.setLocale(checkout.locale);
this.setWrapper(popup.content);
this.action('close', function(){
popup.hide();
});
this.action('load', function(){
popup.show();
});
this.action('response',function(data){
checkout.send('cancel');
checkout.publish('callback',data);
popup.hide();
});
this.submit();
});
},
submit 3ds form
submit3ds: function (data, wrapper) {
return $ipsp('acssubmit').scope(function () {
this.setData(data);
this.setWrapper(wrapper);
});
},
load connector
loadConnector: function (frame) {
this.setCheckoutOrigin(frame.src);
this.connector.setTarget(frame.contentWindow);
this.connector.setOrigin(this.getCheckoutOrigin());
}
});
this.__DEFAULTCALLBACK__ = Callback;
this.Checkout = Checkout;
Add checkout class to ipsp modules
this.$ipsp.add('checkout', Checkout);
}).call(window || {}, location || {});
(function () {
var PROTOCOL = 'https';
var HOST = 'api.local.devoplata.com';
var PATH = '/api/checkout?button=';
Field Class
var Field = Class.extend({
init: function (f) {
this.initialize(f);
},
set field properties passed by
method addField
in Button Class
initialize: function (f) {
this.setName(f.name);
this.setValue(f.value);
this.setLabel(f.label);
this.setPlaceholder(f.placeholder);
this.setRequired(f.required);
this.setValid(f.valid);
this.setReadonly(f.readonly);
},
set user field name used in validation function
setName: function (name) {
if (!isString(name))
console.error('field property `name` is not a string', this);
this.name = name;
return this;
},
set user field placeholder
setPlaceholder: function (placeholder) {
if (placeholder && !isString(placeholder))
console.error('field property `placeholder` is not a string', this);
this.placeholder = placeholder;
return;
},
set user field value
if field is not readonly user can edit this property
setValue: function (value) {
if (value && !isString(value))
console.error('field property `value` is not a string', this);
this.value = value;
return this;
},
set user label (field description)
setLabel: function (label) {
if (!isString(label))
console.error('field property `label` is not a string', this);
this.label = label;
return this;
},
set validation options for user field
setValid: function (valid) {
var prop, value = [];
if (valid && !isObject(valid))
console.error('field property `valid` is not an object', this);
for (prop in valid)
if (valid.hasOwnProperty(prop))
value.push([prop, valid[prop]].join(':'));
this.valid = value.concat(this.valid).join(';');
return this;
},
set user field require to fill in form
setRequired: function (required) {
this.valid = '';
if (required && isBoolean(required))
this.valid = 'required'
},
set readonly flag
by default used false value
setReadonly: function (readonly) {
if (readonly && !isBoolean(readonly))
console.error('field property `readonly` is not an boolean', this);
this.readonly = readonly;
return this;
}
});
Button Class
var Button = Class.extend({
init: function () {
this.data = {
merchant_id: null,
currency: null,
fields: [],
params: {}
};
},
validate button object
validate: function () {
var prop;
var errors = [];
var data = this.data;
for (prop in data)
if (data.hasOwnProperty(prop) && data[prop] === null)
errors.push(['data param -', prop, 'is incorrect'].join(' '))
return errors;
},
set gateway protocol
default is https
setProtocol: function (protocol) {
if (protocol && protocol.match(/https?/)) {
PROTOCOL = protocol;
}
},
set gateway host
default is api.oplata.com
setHost: function (host) {
if (host) {
HOST = host;
}
},
getButton: function (text, style, target) {
var link = document.createElement('a');
link.href = this.getUrl();
link.className = style || '';
link.innerHTML = text;
link.target = target;
return link;
},
build checkout url
getUrl: function () {
var valid;
if ((valid = this.validate()).length > 0) return console.error(valid.join('\n'));
return PROTOCOL.concat('://')
.concat(HOST).concat(PATH)
.concat(encodeURIComponent(JSON.stringify(this.data)));
},
setMerchantId: function (merchant_id) {
if (!isNumber(merchant_id)) console.error('parameter `merchant_id` is required and must be integer');
this.data.merchant_id = merchant_id;
},
set order amount@param (Number) amount
@param (String) currency
@param (Boolean) readonly
examples:
$ipsp('button').setAmount(100,'USD',true);
setAmount: function (amount, currency, readonly) {
if (isNumber(parseInt(amount))) this.data.amount = amount;
if (isString(currency)) this.data.currency = currency;
if (isBoolean(readonly) && readonly === true)
this.data.amount_readonly = readonly;
},
add response url for handling payment response
on merchant site
examples:
$ipsp('button').setResponseUrl('http://site.com/result/');
setResponseUrl: function (url) {
if (!isString(url)) console.error('parameter `url` is required and must be string');
this.addParam('response_url', url);
return this;
},
add user field
examples:
$ipsp('button').addField({
'label':'Account Id',
'name' :'account_id',
'value':'127318273', //optional , default empty
'readonly':true|false, // optional , default false
'required':true|false, // optional , default false
'valid':{
'pattern':'[a-z]+'
}
});
addField: function (field) {
if (!isObject(field)) console.error('parameter field is required')
this.data.fields.push(new Field(field));
return this;
},
add protocol parameter@param (String) name
@param (String|Number) value
examples:
$ipsp('button').addParam('delayed','y')
addParam: function (name, value) {
this.data.params[name] = value;
return this;
},
setRecurringState: function (state) {
this.data.recurring_state = Boolean(state);
},
addRecurringData: function (data) {
this.data.params['subscription'] = 'y';
this.data.recurring = {
period: data.period || 'month',
every: data.every || 1 ,
start_time: data.start_time || this.calcStartDate(data) || this.getDefaultStartDate(),
end_time: data.end_time || this.getDefaultEndDate(),
amount: this.data.amount || '',
custom_period: data.period && data.every
};
},
calcStartDate: function (data) {
if (data.period && data.every) {
return this.getFuturePeriod(data.period,data.every);
} else{
return null;
}
},
getFuturePeriod: function (period, every) {
var d = new Date();
switch (period) {
case 'day':
d.setDate(d.getDate() + (1 * every));
break;
case 'week':
d.setDate(d.getDate() + (7 * every));
break;
case 'month':
d.setMonth(d.getMonth() + (1 * every));
break;
}
return this.getDateFormat(d);
},
getDefaultStartDate: function (period, every) {
var d = new Date();
d.setMonth(d.getMonth() + 1);
return this.getDateFormat(d);
}
,
getDefaultEndDate: function () {
var d = new Date();
d.setFullYear(d.getFullYear() + 5);
return this.getDateFormat(d);
},
getDateFormat:function(d){
return d.getFullYear() + "-" + (("0" + (d.getMonth() + 1)).slice(-2)) + "-" + (("0" + d.getDate()).slice(-2))
}
});
this.$ipsp.add('button', Button);
}).call(window || {});
(function () {
acs frame default attributes
var attrs = {
'frameborder': '0',
'allowtransparency': 'true',
'scrolling': 'no'
};
acs frame default styles
var styles = {
'zIndex': '9999',
'overflowX': 'hidden',
'border': '0',
'display': 'none',
'position': 'fixed',
'top': '0px',
'left': '0px',
'bottom': '0px',
'right': '0px',
'width': '100%',
'height': '100%'
};
asc module init
var AscFrame = Module.extend({
name: '$ipsp.frame3ds',
frame: null,
form: null,
wrapper: 'body',
isloaded: false,
options: {
url: '',
data: {},
wrapper: {}
},
acs frame constructor
init: function () {
this.name = [this.name,Math.round(Math.random()*1000000000)].join('');
this.initFrame();
this.initEvents();
this.initConnector();
},
add handler to acs frame actions
@param (String) name
@param (Function) callback
examples:
$ipsp('acsframe').action('load',function(data,type){});
$ipsp('acsframe').action('close',callbackFunction);
action: function(name,callback){
return pubsub.subscribe([this.name, name].join(':'), callback);
},
trigger handler on acs frame
@param (String) name
@param (Object) data
examples:
$ipsp('acsframe').send('load');
$ipsp('acsframe').action('close');
send: function (name, data) {
pubsub.publish([this.name, name].join(':'), data || {});
return this;
},
remove handler by return token with method action@param (String) token
examples:
var token = $ipsp('acsframe').action('load',function(){});
$ipsp('acsframe').removeAction(token);
removeAction: function (token) {
pubsub.unsubscribe(token);
return this;
},
set localization messages
@param (Object) locale
setLocale: function (locale) {
this.locale = locale;
},
initialize acs frame events
initEvents: function () {
this.addEvent(this.iframe, 'load', this.proxy(function () {
this.loadConnector();
this.send('load',{});
this.addCss(this.iframe, {
'height': '720px'
});
}));
},
initialize acs frame element
initFrame: function (selector) {
this.iframe = this.find(selector) || document.createElement('iframe');
this.iframe.name = this.name;
this.iframe.id = this.name;
this.addAttr(this.iframe,attrs);
this.addCss(this.iframe,{
'width': '100%',
'height': '100%',
});
},
initialize 3ds page connector
initConnector:function(){
this.connector = new Connector;
this.connector.action('response',this.proxy(function(data,type){
this.send(type,data);
}));
},
set 3ds window to current connector
loadConnector:function(){
this.connector.setTarget(this.iframe.contentWindow);
},
set data object passed by checkout callback:$ipsp('checkout').action('3dsform')
setData: function (data) {
this.extend(this.options, data);
return this;
},
set acs frame element wrapper
use css selector
or existing htmlelement
as first argument wrapper
setWrapper: function (wrapper) {
if (isString(wrapper)) {
this.wrapper = this.find(wrapper);
} else {
this.wrapper = wrapper;
}
if (!wrapper) {
throw Error('acsframe element wrapper is undefined');
}
return this;
},
submit acs data in top window
submitHelp: function () {
this.form = prepareFormData(this.options.url, this.options.send_data, this.name);
this.form.target = "_blank";
this.wrapper.appendChild(this.form);
this.form.submit();
},
submit acs data to frame
submit: function () {
this.form = prepareFormData(this.options.url, this.options.send_data, this.name);
this.wrapper.appendChild(this.iframe);
this.wrapper.appendChild(this.form);
this.form.submit();
}
});
Add popup class to ipsp modules
this.$ipsp.add('acsframe', AscFrame);
}).call(window || {});
(function () {
var AscSubmit = Module.extend({
name: '$ipsp.frame3ds',
target: '_blank',
frame: null,
form: null,
wrapper: 'body',
isloaded: false,
options: {
url: '',
data: {},
wrapper: {},
},
acs frame constructor
init: function () {
this.name = [this.name, Math.round(Math.random() * 1000000000)].join('');
this.initEvents();
},
action: function (name, callback) {
return pubsub.subscribe([this.name, name].join(':'), callback);
},
trigger handler on acs page examples:
$ipsp('acssubmit').send('load');
$ipsp('acssubmit').send('close');
send: function (name, data) {
pubsub.publish([this.name, name].join(':'), data || {});
return this;
},
remove handler by return token with method action@param (String) token
examples:
var token = $ipsp('acssubmit').action('close',function(){});
$ipsp('acssubmit').removeAction(token);
removeAction: function (token) {
pubsub.unsubscribe(token);
return this;
},
initialize acs page events
initEvents: function () {
this.action('close', this.proxy(function () {
this.find(this.wrapper).removeChild(this.form);
}));
},
setData: function (data) {
this.extend(this.options, data);
return this;
},
set acs frame element wrapper
use css selector
or existing htmlelement
as first argument wrapper
setWrapper: function (wrapper) {
if (!wrapper) {
throw Error('asc submit wrapper element is undefined');
}
if (isString(wrapper)) {
this.wrapper = this.find(wrapper);
} else if (isElement(wrapper)) {
this.wrapper = wrapper;
}
return this;
},
submit acs data to frame
submit: function () {
this.form = prepareFormData(this.options.url, this.options.send_data, this.name);
this.wrapper.appendChild(this.form);
this.popup = window.open('about:blank', this.name);
if (this.popup && popupBlocker(this.popup)) {
this.form.submit();
} else {
this.send('blocked3dsPopup', this.options);
}
return this;
}
});
Add popup class to ipsp modules
this.$ipsp.add('acssubmit', AscSubmit);
}).call(window || {});
(function () {
Define style object
var styles = {};
modal window styles
styles.modal = {
'display': 'block',
'overflow': 'hidden',
'position': 'relative',
'background': '#fff',
'zIndex': '99999',
'boxShadow': '0px 0px 5px rgba(0,0,0,0.2)'
};
modal title styles
styles.title = {
'margin': '0px',
'overflow': 'hidden',
'padding': '17px 20px',
'fontFamily': 'Arial, Helvetica',
'lineHeight': '14px',
'fontSize': '12px'
};
close button styles
styles.button = {
'display': 'block',
'float': 'right',
'position': 'relative',
'fontWeight': 'bold',
'fontSize': '48px',
'padding': '0 8px',
'lineHeight': '100%',
'cursor': 'pointer'
};
modal splash styles
styles.wrapper = {
'position': 'fixed',
'top': '0px',
'left': '0px',
'right': '0px',
'bottom': '0px',
'zIndex': '9999',
'display': 'none',
'overflowY': 'auto',
'background': 'rgba(0,0,0,0.1)'
};
var Popup = Module.extend({
popup constructor
init: function () {
this.wrapper = this.elem('div', styles.wrapper);
this.wrapper.className = 'oplata_popup_wrapper ipsp_popup_wrapper';
this.modal = this.elem('div', styles.modal);
this.modal.className = 'oplata_popup_modal ipsp_popup_modal';
this.toolbar = this.elem('div');
this.toolbar.className = 'oplata_popup_toolbar ipsp_popup_toolbar';
this.title = this.elem('div');
this.title.className = 'oplata_popup_title ipsp_popup_title';
this.addCss(this.title, styles.title);
this.closelink = this.elem('a');
this.closelink.className = 'oplata_popup_close ipsp_popup_close';
this.closelink.innerHTML = '×';
this.addEvent(this.closelink, 'click', this.proxy(function (ev) {
ev.preventDefault();
this.hide();
this.close();
}));
this.addCss(this.closelink, styles.button);
this.toolbar.appendChild(this.closelink);
this.toolbar.appendChild(this.title);
this.addCss(this.toolbar, {
'position': 'relative',
'zIndex': '5',
'overflow': 'hidden'
});
this.content = this.elem('div');
this.content.className = 'oplata_popup_content';
this.addCss(this.content, {
'position': 'relative',
'zIndex': '2'
});
this.modal.appendChild(this.toolbar);
this.modal.appendChild(this.content);
this.wrapper.appendChild(this.modal);
this.find('body').appendChild(this.wrapper);
},
element create helper
elem: function (tag, styles) {
var elem = document.createElement(tag);
if (styles)
this.addCss(elem, styles);
return elem;
},
setup modal options eq: width and height examples:
$ipsp('popup').config({ width : 500 , height: 800 });
config: function (config) {
this.addCss(this.modal, {
'top': '100px',
'left': '50%',
'marginLeft': -(parseInt(config.width, 10) / 2) + 'px',
'width': config.width || 'auto',
'height': config.height || 'auto'
});
},
show: function () {
this.addCss(this.wrapper, {
'display': 'block'
});
this.addCss(this.find('body'), {
'overflow': 'hidden'
});
this.addCss(this.find('html'), {
'overflow': 'hidden'
});
},
hide: function () {
this.addCss(this.wrapper, {
'display': 'none'
});
this.addCss(this.find('body'), {
'overflow': ''
});
this.addCss(this.find('html'), {
'overflow': ''
});
if (this.wrapper.parentNode) {
this.wrapper.parentNode.removeChild(this.wrapper);
}
},
close: function () {
}
});
Add popup class to ipsp modules
this.$ipsp.add('popup', Popup);
}).call(window || {});