recurly-js-rails 0.0.2
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.
- data/.gitignore +17 -0
- data/Gemfile +4 -0
- data/LICENSE +22 -0
- data/README.md +37 -0
- data/Rakefile +2 -0
- data/lib/recurly-js-rails.rb +6 -0
- data/lib/recurly-js-rails/engine.rb +6 -0
- data/lib/recurly-js-rails/version.rb +6 -0
- data/recurly-js-rails.gemspec +17 -0
- data/vendor/assets/javascripts/recurly.js +2243 -0
- data/vendor/assets/stylesheets/images/check.png +0 -0
- data/vendor/assets/stylesheets/images/coupon_check.png +0 -0
- data/vendor/assets/stylesheets/images/coupon_checking.gif +0 -0
- data/vendor/assets/stylesheets/images/coupon_invalid.png +0 -0
- data/vendor/assets/stylesheets/images/coupon_valid.png +0 -0
- data/vendor/assets/stylesheets/images/credit_cards/amex.png +0 -0
- data/vendor/assets/stylesheets/images/credit_cards/discover.png +0 -0
- data/vendor/assets/stylesheets/images/credit_cards/mastercard.png +0 -0
- data/vendor/assets/stylesheets/images/credit_cards/visa.png +0 -0
- data/vendor/assets/stylesheets/images/dash.png +0 -0
- data/vendor/assets/stylesheets/images/due_now.png +0 -0
- data/vendor/assets/stylesheets/images/error.png +0 -0
- data/vendor/assets/stylesheets/images/loading.gif +0 -0
- data/vendor/assets/stylesheets/images/submitting.gif +0 -0
- data/vendor/assets/stylesheets/images/uncheck.png +0 -0
- data/vendor/assets/stylesheets/recurly.css +701 -0
- metadata +71 -0
data/.gitignore
ADDED
data/Gemfile
ADDED
data/LICENSE
ADDED
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
Copyright (c) 2012 Chris McGrath
|
|
2
|
+
|
|
3
|
+
MIT License
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
|
6
|
+
a copy of this software and associated documentation files (the
|
|
7
|
+
"Software"), to deal in the Software without restriction, including
|
|
8
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
|
9
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
|
10
|
+
permit persons to whom the Software is furnished to do so, subject to
|
|
11
|
+
the following conditions:
|
|
12
|
+
|
|
13
|
+
The above copyright notice and this permission notice shall be
|
|
14
|
+
included in all copies or substantial portions of the Software.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
|
19
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
|
20
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
|
21
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
|
22
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.md
ADDED
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
# RecurlyJs::Rails
|
|
2
|
+
|
|
3
|
+
Early alpha version of a Rails 3.1+ asset gem for recurly-js
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
Add this line to your application's Gemfile:
|
|
8
|
+
|
|
9
|
+
gem 'recurly-js-rails'
|
|
10
|
+
|
|
11
|
+
And then execute:
|
|
12
|
+
|
|
13
|
+
$ bundle
|
|
14
|
+
|
|
15
|
+
Or install it yourself as:
|
|
16
|
+
|
|
17
|
+
$ gem install recurly-js-rails
|
|
18
|
+
|
|
19
|
+
## Usage
|
|
20
|
+
|
|
21
|
+
To include the js and css everywhere add:
|
|
22
|
+
|
|
23
|
+
`//= require recurly` to both your application.js and application.css
|
|
24
|
+
|
|
25
|
+
To just include on your subscription pages, add:
|
|
26
|
+
|
|
27
|
+
`config.assets.precompile += %w{recurly.css recurly.js}`
|
|
28
|
+
|
|
29
|
+
To your application.rb and use `stylesheet_link_tag "recurly"` and `javascript_include_tag "recurly"` where appropriate
|
|
30
|
+
|
|
31
|
+
## Contributing
|
|
32
|
+
|
|
33
|
+
1. Fork it
|
|
34
|
+
2. Create your feature branch (`git checkout -b my-new-feature`)
|
|
35
|
+
3. Commit your changes (`git commit -am 'Added some feature'`)
|
|
36
|
+
4. Push to the branch (`git push origin my-new-feature`)
|
|
37
|
+
5. Create new Pull Request
|
data/Rakefile
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
|
2
|
+
require File.expand_path('../lib/recurly-js-rails/version', __FILE__)
|
|
3
|
+
|
|
4
|
+
Gem::Specification.new do |gem|
|
|
5
|
+
gem.authors = ["Chris McGrath"]
|
|
6
|
+
gem.email = ["chris@octopod.info"]
|
|
7
|
+
gem.description = %q{Rails 3.1+ asset gem for recurly-js}
|
|
8
|
+
gem.summary = %q{Rails 3.1+ asset gem for recurly-js}
|
|
9
|
+
gem.homepage = ""
|
|
10
|
+
|
|
11
|
+
gem.executables = `git ls-files -- bin/*`.split("\n").map{ |f| File.basename(f) }
|
|
12
|
+
gem.files = `git ls-files`.split("\n")
|
|
13
|
+
gem.test_files = `git ls-files -- {test,spec,features}/*`.split("\n")
|
|
14
|
+
gem.name = "recurly-js-rails"
|
|
15
|
+
gem.require_paths = ["lib"]
|
|
16
|
+
gem.version = RecurlyJs::Rails::VERSION
|
|
17
|
+
end
|
|
@@ -0,0 +1,2243 @@
|
|
|
1
|
+
// Recurly.js - v2.1.3
|
|
2
|
+
//
|
|
3
|
+
// Communicates with Recurly <https://recurly.com> via a JSONP API,
|
|
4
|
+
// generates UI, handles user error, and passes control to the client
|
|
5
|
+
// to handle the successful events such as subscription creation.
|
|
6
|
+
//
|
|
7
|
+
// Example Site: https://js.recurly.com
|
|
8
|
+
//
|
|
9
|
+
// (MIT License)
|
|
10
|
+
//
|
|
11
|
+
// Copyright (C) 2012 by Recurly, Inc.
|
|
12
|
+
//
|
|
13
|
+
// Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
14
|
+
// of this software and associated documentation files (the "Software"), to deal
|
|
15
|
+
// in the Software without restriction, including without limitation the rights
|
|
16
|
+
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
17
|
+
// copies of the Software, and to permit persons to whom the Software is
|
|
18
|
+
// furnished to do so, subject to the following conditions:
|
|
19
|
+
//
|
|
20
|
+
// The above copyright notice and this permission notice shall be included in
|
|
21
|
+
// all copies or substantial portions of the Software.
|
|
22
|
+
//
|
|
23
|
+
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
24
|
+
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
25
|
+
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
26
|
+
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
27
|
+
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
28
|
+
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
|
29
|
+
// THE SOFTWARE.
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
(function($) {
|
|
33
|
+
"use strict";
|
|
34
|
+
|
|
35
|
+
//////////////////////////////////////////////////
|
|
36
|
+
// Compiled from src/js/core.js
|
|
37
|
+
//////////////////////////////////////////////////
|
|
38
|
+
|
|
39
|
+
// Non-intrusive Object.create
|
|
40
|
+
function createObject(o) {
|
|
41
|
+
function F() {}
|
|
42
|
+
F.prototype = o || this;
|
|
43
|
+
return new F();
|
|
44
|
+
};
|
|
45
|
+
|
|
46
|
+
var R = {};
|
|
47
|
+
R.settings = {
|
|
48
|
+
enableGeoIP: true
|
|
49
|
+
, acceptedCards: ['american_express', 'discover', 'mastercard', 'visa']
|
|
50
|
+
, oneErrorPerField: true
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
R.version = '2.1.3';
|
|
54
|
+
|
|
55
|
+
R.dom = {};
|
|
56
|
+
|
|
57
|
+
R.Error = {
|
|
58
|
+
toString: function() {
|
|
59
|
+
return 'RecurlyJS Error: ' + this.message;
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
|
|
63
|
+
R.raiseError = function(message) {
|
|
64
|
+
var e = createObject(R.Error);
|
|
65
|
+
e.message = message;
|
|
66
|
+
throw e;
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
|
|
70
|
+
R.config = function(settings) {
|
|
71
|
+
$.extend(true, R.settings, settings);
|
|
72
|
+
|
|
73
|
+
if(!settings.baseURL) {
|
|
74
|
+
R.settings.baseURL = 'https://api.recurly.com/jsonp/';
|
|
75
|
+
var subdomain = R.settings.subdomain || R.raiseError('company subdomain not configured');
|
|
76
|
+
R.settings.baseURL += subdomain + '/';
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
|
|
80
|
+
|
|
81
|
+
function pluralize(count, term) {
|
|
82
|
+
if(count == 1) {
|
|
83
|
+
return term.substr(0,term.length-1);
|
|
84
|
+
}
|
|
85
|
+
|
|
86
|
+
return '' + count + ' ' + term;
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
// Immutable currency-amount object
|
|
90
|
+
// This will eventually handle multi-currency
|
|
91
|
+
// where it will store a list of costs per currency
|
|
92
|
+
// and accessors will return the appropriate one
|
|
93
|
+
// based on the current currency
|
|
94
|
+
//
|
|
95
|
+
|
|
96
|
+
(R.Cost = function(cents) {
|
|
97
|
+
this._cents = cents || 0;
|
|
98
|
+
}).prototype = {
|
|
99
|
+
toString: function() {
|
|
100
|
+
return R.formatCurrency(this.dollars());
|
|
101
|
+
}
|
|
102
|
+
, cents: function(val) {
|
|
103
|
+
if(val === undefined)
|
|
104
|
+
return this._cents;
|
|
105
|
+
|
|
106
|
+
return new Cost(val);
|
|
107
|
+
}
|
|
108
|
+
, dollars: function(val) {
|
|
109
|
+
if(val === undefined)
|
|
110
|
+
return this._cents/100;
|
|
111
|
+
|
|
112
|
+
return new R.Cost(val*100);
|
|
113
|
+
}
|
|
114
|
+
, mult: function(n) {
|
|
115
|
+
return new R.Cost(this._cents * n);
|
|
116
|
+
}
|
|
117
|
+
, add: function(n) {
|
|
118
|
+
if(n.cents) n = n.cents();
|
|
119
|
+
return new R.Cost(this._cents + n);
|
|
120
|
+
}
|
|
121
|
+
, sub: function(n) {
|
|
122
|
+
if(n.cents) n = n.cents();
|
|
123
|
+
return new R.Cost(this._cents - n);
|
|
124
|
+
}
|
|
125
|
+
};
|
|
126
|
+
|
|
127
|
+
R.Cost.FREE = new R.Cost(0);
|
|
128
|
+
|
|
129
|
+
(R.TimePeriod = function(length,unit) {
|
|
130
|
+
this.length = length;
|
|
131
|
+
this.unit = unit;
|
|
132
|
+
}).prototype = {
|
|
133
|
+
toString: function() {
|
|
134
|
+
return '' + pluralize(this.length, this.unit);
|
|
135
|
+
}
|
|
136
|
+
, toDate: function() {
|
|
137
|
+
var d = new Date();
|
|
138
|
+
switch(this.unit) {
|
|
139
|
+
case 'month':
|
|
140
|
+
d.setMonth( d.getMonth() + this.length );
|
|
141
|
+
break;
|
|
142
|
+
case 'day':
|
|
143
|
+
d.setDay( d.getDay() + this.length );
|
|
144
|
+
break;
|
|
145
|
+
}
|
|
146
|
+
return d;
|
|
147
|
+
}
|
|
148
|
+
, clone: function() {
|
|
149
|
+
return new R.TimePeriod(this.length,this.unit);
|
|
150
|
+
}
|
|
151
|
+
};
|
|
152
|
+
|
|
153
|
+
(R.RecurringCost = function(cost,interval) {
|
|
154
|
+
this.cost = cost;
|
|
155
|
+
this.interval = interval;
|
|
156
|
+
}).prototype = {
|
|
157
|
+
toString: function() {
|
|
158
|
+
return '' + this.cost + ' every ' + this.interval;
|
|
159
|
+
}
|
|
160
|
+
, clone: function() {
|
|
161
|
+
return new R.TimePeriod(this.length,this.unit);
|
|
162
|
+
}
|
|
163
|
+
};
|
|
164
|
+
|
|
165
|
+
R.RecurringCost.FREE = new R.RecurringCost(0,null);
|
|
166
|
+
|
|
167
|
+
(R.RecurringCostStage = function(recurringCost, duration) {
|
|
168
|
+
this.recurringCost = recurringCost;
|
|
169
|
+
this.duration = duration;
|
|
170
|
+
}).prototype = {
|
|
171
|
+
toString: function() {
|
|
172
|
+
this.recurringCost.toString() + ' for ' + this.duration.toString();
|
|
173
|
+
}
|
|
174
|
+
};
|
|
175
|
+
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
|
|
179
|
+
//////////////////////////////////////////////////
|
|
180
|
+
// Compiled from src/js/locale.js
|
|
181
|
+
//////////////////////////////////////////////////
|
|
182
|
+
|
|
183
|
+
R.locale = {};
|
|
184
|
+
|
|
185
|
+
R.locale.errors = {
|
|
186
|
+
emptyField: 'Required field'
|
|
187
|
+
, missingFullAddress: 'Please enter your full address.'
|
|
188
|
+
, invalidEmail: 'Invalid'
|
|
189
|
+
, invalidCC: 'Invalid'
|
|
190
|
+
, invalidCVV: 'Invalid'
|
|
191
|
+
, invalidCoupon: 'Invalid'
|
|
192
|
+
, cardDeclined: 'Transaction declined'
|
|
193
|
+
, acceptTOS: 'Please accept the Terms of Service.'
|
|
194
|
+
, invalidQuantity: 'Invalid quantity'
|
|
195
|
+
};
|
|
196
|
+
|
|
197
|
+
R.locale.currencies = {};
|
|
198
|
+
|
|
199
|
+
R.locale.currency = {
|
|
200
|
+
format: "%u%n"
|
|
201
|
+
, separator: "."
|
|
202
|
+
, delimiter: ","
|
|
203
|
+
, precision: 2
|
|
204
|
+
};
|
|
205
|
+
|
|
206
|
+
function C(key, def) {
|
|
207
|
+
var c = R.locale.currencies[key] = createObject(R.locale.currency);
|
|
208
|
+
for(var p in def) {
|
|
209
|
+
c[p] = def[p];
|
|
210
|
+
}
|
|
211
|
+
};
|
|
212
|
+
|
|
213
|
+
C('USD', {
|
|
214
|
+
symbol: '$'
|
|
215
|
+
});
|
|
216
|
+
|
|
217
|
+
C('AUD', {
|
|
218
|
+
symbol: '$'
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
C('CAD', {
|
|
222
|
+
symbol: '$'
|
|
223
|
+
});
|
|
224
|
+
|
|
225
|
+
C('EUR', {
|
|
226
|
+
symbol: '\u20ac'
|
|
227
|
+
});
|
|
228
|
+
|
|
229
|
+
C('GBP', {
|
|
230
|
+
symbol: '\u00a3'
|
|
231
|
+
});
|
|
232
|
+
|
|
233
|
+
C('CZK', {
|
|
234
|
+
symbol: '\u004b'
|
|
235
|
+
});
|
|
236
|
+
|
|
237
|
+
C('DKK', {
|
|
238
|
+
symbol: '\u006b\u0072'
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
C('HUF', {
|
|
242
|
+
symbol: 'Ft'
|
|
243
|
+
});
|
|
244
|
+
|
|
245
|
+
C('JPY', {
|
|
246
|
+
symbol: '\u00a5'
|
|
247
|
+
});
|
|
248
|
+
|
|
249
|
+
C('NOK', {
|
|
250
|
+
symbol: 'kr'
|
|
251
|
+
});
|
|
252
|
+
|
|
253
|
+
C('NZD', {
|
|
254
|
+
symbol: '$'
|
|
255
|
+
});
|
|
256
|
+
|
|
257
|
+
C('PLN', {
|
|
258
|
+
symbol: '\u007a'
|
|
259
|
+
});
|
|
260
|
+
|
|
261
|
+
C('SGD', {
|
|
262
|
+
symbol: '$'
|
|
263
|
+
});
|
|
264
|
+
|
|
265
|
+
C('SEK', {
|
|
266
|
+
symbol: 'kr'
|
|
267
|
+
});
|
|
268
|
+
|
|
269
|
+
C('CHF', {
|
|
270
|
+
symbol: 'Fr'
|
|
271
|
+
});
|
|
272
|
+
|
|
273
|
+
C('ZAR', {
|
|
274
|
+
symbol: 'R'
|
|
275
|
+
});
|
|
276
|
+
|
|
277
|
+
|
|
278
|
+
|
|
279
|
+
R.settings.locale = R.locale;
|
|
280
|
+
|
|
281
|
+
|
|
282
|
+
//////////////////////////////////////////////////
|
|
283
|
+
// Compiled from src/js/utils.js
|
|
284
|
+
//////////////////////////////////////////////////
|
|
285
|
+
|
|
286
|
+
R.knownCards = {
|
|
287
|
+
'visa': {
|
|
288
|
+
prefixes: [4]
|
|
289
|
+
, name: 'Visa'
|
|
290
|
+
}
|
|
291
|
+
, 'mastercard': {
|
|
292
|
+
prefixes: [51, 52, 53, 54, 55]
|
|
293
|
+
, name: 'MasterCard'
|
|
294
|
+
}
|
|
295
|
+
, 'american_express': {
|
|
296
|
+
prefixes: [34, 37]
|
|
297
|
+
, name: 'American Express'
|
|
298
|
+
}
|
|
299
|
+
, 'discover': {
|
|
300
|
+
prefixes: [6011, 62, 64, 65]
|
|
301
|
+
, name: 'Discover'
|
|
302
|
+
}
|
|
303
|
+
, 'diners_club': {
|
|
304
|
+
prefixes: [305, 36, 38]
|
|
305
|
+
, name: 'Diners Club'
|
|
306
|
+
}
|
|
307
|
+
, 'carte_blanche': {
|
|
308
|
+
prefixes: [300, 301, 302, 303, 304, 305]
|
|
309
|
+
}
|
|
310
|
+
, 'jcb': {
|
|
311
|
+
prefixes: [35]
|
|
312
|
+
, name: 'JCB'
|
|
313
|
+
}
|
|
314
|
+
, 'enroute': {
|
|
315
|
+
prefixes: [2014, 2149]
|
|
316
|
+
, name: 'EnRoute'
|
|
317
|
+
}
|
|
318
|
+
, 'maestro': {
|
|
319
|
+
prefixes: [5018, 5020, 5038, 6304, 6759, 6761]
|
|
320
|
+
, name: 'Maestro'
|
|
321
|
+
}
|
|
322
|
+
, 'laser': {
|
|
323
|
+
prefixes: [6304, 6706, 6771, 6709]
|
|
324
|
+
, name: 'Laser'
|
|
325
|
+
}
|
|
326
|
+
};
|
|
327
|
+
|
|
328
|
+
// Credit card type functions
|
|
329
|
+
R.detectCardType = function(cardNumber) {
|
|
330
|
+
cardNumber = cardNumber.replace(/\D/g, '');
|
|
331
|
+
var cards = R.knownCards;
|
|
332
|
+
|
|
333
|
+
for(var ci in cards) {
|
|
334
|
+
if(cards.hasOwnProperty(ci)) {
|
|
335
|
+
var c = cards[ci];
|
|
336
|
+
for(var pi=0,pl=c.prefixes.length; pi < pl; ++pi) {
|
|
337
|
+
if(c.prefixes.hasOwnProperty(pi)) {
|
|
338
|
+
var p = c.prefixes[pi];
|
|
339
|
+
if (new RegExp('^' + p.toString()).test(cardNumber))
|
|
340
|
+
return ci;
|
|
341
|
+
}
|
|
342
|
+
}
|
|
343
|
+
}
|
|
344
|
+
}
|
|
345
|
+
|
|
346
|
+
return false;
|
|
347
|
+
};
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
// Formats currency amount in the current denomination or one provided
|
|
351
|
+
// based on R.locale.currencies rules
|
|
352
|
+
R.formatCurrency = function(num,denomination) {
|
|
353
|
+
|
|
354
|
+
if(num < 0) {
|
|
355
|
+
num = -num;
|
|
356
|
+
var negative = true;
|
|
357
|
+
}
|
|
358
|
+
else {
|
|
359
|
+
var negative = false;
|
|
360
|
+
}
|
|
361
|
+
|
|
362
|
+
denomination = denomination || R.settings.currency ||
|
|
363
|
+
R.raiseError('currency not configured');
|
|
364
|
+
|
|
365
|
+
var langspec = R.locale.currency;
|
|
366
|
+
var currencyspec = R.locale.currencies[denomination];
|
|
367
|
+
|
|
368
|
+
// Format to precision
|
|
369
|
+
var str = num.toFixed(currencyspec.precision);
|
|
370
|
+
|
|
371
|
+
// Replace default period with format separator
|
|
372
|
+
if(langspec.separator != '.') {
|
|
373
|
+
str = str.replace(/\./g, langspec.separator);
|
|
374
|
+
}
|
|
375
|
+
|
|
376
|
+
function insertDelimiters(str) {
|
|
377
|
+
var sRegExp = new RegExp('(-?[0-9]+)([0-9]{3})');
|
|
378
|
+
while(sRegExp.test(str)) {
|
|
379
|
+
str = str.replace(sRegExp, '$1'+langspec.delimiter+'$2');
|
|
380
|
+
}
|
|
381
|
+
return str;
|
|
382
|
+
}
|
|
383
|
+
|
|
384
|
+
// Apply thousands delimiter
|
|
385
|
+
str = insertDelimiters(str);
|
|
386
|
+
|
|
387
|
+
// Format unit/number order
|
|
388
|
+
var format = langspec.format;
|
|
389
|
+
format = format.replace(/%u/g, currencyspec.symbol);
|
|
390
|
+
format = format.replace(/%n/g, str);
|
|
391
|
+
str = format;
|
|
392
|
+
|
|
393
|
+
if(negative) {
|
|
394
|
+
str = '-' + str;
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
return str;
|
|
398
|
+
};
|
|
399
|
+
|
|
400
|
+
var euCountries = ["AT","BE","BG","CY","CZ","DK","EE","FI","FR","DE","GR","HU","IE","IT","LV","LT","LU","MT","NL","PL","PT","RO","SK","SI","ES","SE","GB"];
|
|
401
|
+
R.isCountryInEU = function(country) {
|
|
402
|
+
return $.inArray(country, euCountries) !== -1;
|
|
403
|
+
}
|
|
404
|
+
|
|
405
|
+
R.isVATNumberApplicable = function(buyerCountry, sellerCountry) {
|
|
406
|
+
if(!R.settings.VATPercent) return false;
|
|
407
|
+
|
|
408
|
+
if(!R.settings.country) {
|
|
409
|
+
R.raiseError('you must configure a country for VAT to work');
|
|
410
|
+
}
|
|
411
|
+
|
|
412
|
+
if(!R.isCountryInEU(R.settings.country)) {
|
|
413
|
+
R.raiseError('you cannot charge VAT outside of the EU');
|
|
414
|
+
}
|
|
415
|
+
|
|
416
|
+
// Outside of EU don't even show the number
|
|
417
|
+
if(!R.isCountryInEU(buyerCountry)) {
|
|
418
|
+
return false;
|
|
419
|
+
}
|
|
420
|
+
|
|
421
|
+
return true;
|
|
422
|
+
}
|
|
423
|
+
|
|
424
|
+
R.isVATChargeApplicable = function(buyerCountry, vatNumber) {
|
|
425
|
+
// We made it so the VAT Number is collectable in any case
|
|
426
|
+
// where it could be charged, so this is logically sound:
|
|
427
|
+
if(!R.isVATNumberApplicable(buyerCountry)) return false;
|
|
428
|
+
|
|
429
|
+
var sellerCountry = R.settings.country;
|
|
430
|
+
|
|
431
|
+
// 1) Outside EU never pays
|
|
432
|
+
// 2) Same country in EU always pays
|
|
433
|
+
// 3) Different countries in EU, pay only without vatNumber
|
|
434
|
+
return (sellerCountry == buyerCountry || !vatNumber);
|
|
435
|
+
};
|
|
436
|
+
|
|
437
|
+
R.flattenErrors = function(obj, attr) {
|
|
438
|
+
var arr = [];
|
|
439
|
+
|
|
440
|
+
var baseErrorKeys = ['base','account_id'];
|
|
441
|
+
|
|
442
|
+
var attr = attr || '';
|
|
443
|
+
|
|
444
|
+
if( typeof obj == 'string'
|
|
445
|
+
|| typeof obj == 'number'
|
|
446
|
+
|| typeof obj == 'boolean') {
|
|
447
|
+
|
|
448
|
+
/*
|
|
449
|
+
* erroneous code, commented out here in case similar logic is needed later
|
|
450
|
+
if($.inArray(baseErrorKeys, attr)) {
|
|
451
|
+
return [obj];
|
|
452
|
+
}
|
|
453
|
+
*/
|
|
454
|
+
|
|
455
|
+
return ['' + attr + ' ' + obj];
|
|
456
|
+
}
|
|
457
|
+
|
|
458
|
+
for(var k in obj) {
|
|
459
|
+
// console.log(k);
|
|
460
|
+
if(obj.hasOwnProperty(k)) {
|
|
461
|
+
// Inherit parent attribute names when property key
|
|
462
|
+
// is a numeric string; how we deal with arrays
|
|
463
|
+
attr = (parseInt(k).toString() == k) ? attr : k;
|
|
464
|
+
var children = R.flattenErrors(obj[k], attr);
|
|
465
|
+
for(var i=0, l=children.length; i < l; ++i) {
|
|
466
|
+
arr.push(children[i]);
|
|
467
|
+
}
|
|
468
|
+
}
|
|
469
|
+
}
|
|
470
|
+
|
|
471
|
+
return arr;
|
|
472
|
+
};
|
|
473
|
+
|
|
474
|
+
// Very small function, but defining for D.R.Y.ness
|
|
475
|
+
R.getToken = function(response) {
|
|
476
|
+
var token = response.token || 'INVALIDTOKEN';
|
|
477
|
+
return token;
|
|
478
|
+
}
|
|
479
|
+
|
|
480
|
+
// POST the results from Recurly to the merchant's webserver
|
|
481
|
+
R.postResult = function(url, originalResponse, options) {
|
|
482
|
+
var token = R.getToken(originalResponse);
|
|
483
|
+
|
|
484
|
+
var form = $('<form />').hide();
|
|
485
|
+
form.attr('action', url)
|
|
486
|
+
.attr('method', 'POST')
|
|
487
|
+
.attr('enctype', 'application/x-www-form-urlencoded');
|
|
488
|
+
|
|
489
|
+
$('<input type="hidden" />').attr({name: 'recurly_token', value: token}).appendTo(form);
|
|
490
|
+
|
|
491
|
+
$('body').append(form);
|
|
492
|
+
form.submit();
|
|
493
|
+
};
|
|
494
|
+
|
|
495
|
+
function jsonToSelect(obj) {
|
|
496
|
+
var $select = $('<select>');
|
|
497
|
+
|
|
498
|
+
for(var k in obj) {
|
|
499
|
+
if(obj.hasOwnProperty(k)) {
|
|
500
|
+
var v = obj[k];
|
|
501
|
+
$select.append('<option value='+k+'>'+v+'</option>');
|
|
502
|
+
}
|
|
503
|
+
}
|
|
504
|
+
|
|
505
|
+
return $select;
|
|
506
|
+
};
|
|
507
|
+
|
|
508
|
+
R.enforce = function(obj) {
|
|
509
|
+
return {
|
|
510
|
+
enforced: obj
|
|
511
|
+
, hidden: false
|
|
512
|
+
, hide: function() {
|
|
513
|
+
this.hidden = true;
|
|
514
|
+
return this;
|
|
515
|
+
}
|
|
516
|
+
};
|
|
517
|
+
};
|
|
518
|
+
|
|
519
|
+
|
|
520
|
+
function cc2lcu(obj) {
|
|
521
|
+
obj = obj || this;
|
|
522
|
+
|
|
523
|
+
if(typeof obj == 'string') {
|
|
524
|
+
return obj.replace(/([a-z])([A-Z])/g, function (a, l, u) {
|
|
525
|
+
return l+'_'+u;
|
|
526
|
+
}).toLowerCase();
|
|
527
|
+
}
|
|
528
|
+
else {
|
|
529
|
+
for(var k in obj) {
|
|
530
|
+
if(obj.hasOwnProperty(k)) {
|
|
531
|
+
|
|
532
|
+
}
|
|
533
|
+
}
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
|
|
537
|
+
|
|
538
|
+
R.ajax = function(options) {
|
|
539
|
+
options.data = $.extend({js_version: R.version}, options.data);
|
|
540
|
+
return $.ajax(options);
|
|
541
|
+
};
|
|
542
|
+
|
|
543
|
+
|
|
544
|
+
function errorDialog(message) {
|
|
545
|
+
$('body').append(R.dom.error_dialog);
|
|
546
|
+
}
|
|
547
|
+
|
|
548
|
+
|
|
549
|
+
//////////////////////////////////////////////////
|
|
550
|
+
// Compiled from src/js/validators.js
|
|
551
|
+
//////////////////////////////////////////////////
|
|
552
|
+
|
|
553
|
+
|
|
554
|
+
(R.isValidCC = function($input) {
|
|
555
|
+
var v = $input.val();
|
|
556
|
+
|
|
557
|
+
// Strip out all non digits
|
|
558
|
+
v = v.replace(/\D/g, "");
|
|
559
|
+
|
|
560
|
+
if(v == "") return false;
|
|
561
|
+
|
|
562
|
+
var nCheck = 0,
|
|
563
|
+
nDigit = 0,
|
|
564
|
+
bEven = false;
|
|
565
|
+
|
|
566
|
+
|
|
567
|
+
for (var n = v.length - 1; n >= 0; n--) {
|
|
568
|
+
var cDigit = v.charAt(n);
|
|
569
|
+
var nDigit = parseInt(cDigit, 10);
|
|
570
|
+
if (bEven) {
|
|
571
|
+
if ((nDigit *= 2) > 9)
|
|
572
|
+
nDigit -= 9;
|
|
573
|
+
}
|
|
574
|
+
nCheck += nDigit;
|
|
575
|
+
bEven = !bEven;
|
|
576
|
+
}
|
|
577
|
+
|
|
578
|
+
return (nCheck % 10) == 0;
|
|
579
|
+
}).defaultErrorKey = 'invalidCC';
|
|
580
|
+
|
|
581
|
+
(R.isValidEmail = function($input) {
|
|
582
|
+
var v = $input.val();
|
|
583
|
+
return /^((([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+(\.([a-z]|\d|[!#\$%&'\*\+\-\/=\?\^_`{\|}~]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])+)*)|((\x22)((((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(([\x01-\x08\x0b\x0c\x0e-\x1f\x7f]|\x21|[\x23-\x5b]|[\x5d-\x7e]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(\\([\x01-\x09\x0b\x0c\x0d-\x7f]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF]))))*(((\x20|\x09)*(\x0d\x0a))?(\x20|\x09)+)?(\x22)))@((([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|\d|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.)+(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])|(([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])([a-z]|\d|-|\.|_|~|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])*([a-z]|[\u00A0-\uD7FF\uF900-\uFDCF\uFDF0-\uFFEF])))\.?$/i.test(v);
|
|
584
|
+
}).defaultErrorKey = 'invalidEmail';
|
|
585
|
+
|
|
586
|
+
function wholeNumber(val) {
|
|
587
|
+
return /^[0-9]+$/.test(val);
|
|
588
|
+
}
|
|
589
|
+
|
|
590
|
+
(R.isValidCVV = function($input) {
|
|
591
|
+
var v = $input.val();
|
|
592
|
+
return (v.length == 3 || v.length == 4) && wholeNumber(v);
|
|
593
|
+
}).defaultErrorKey = 'invalidCVV';
|
|
594
|
+
|
|
595
|
+
(R.isNotEmpty = function($input) {
|
|
596
|
+
var v = $input.val();
|
|
597
|
+
if($input.is('select')) {
|
|
598
|
+
if(v == '-' || v == '--') return false;
|
|
599
|
+
}
|
|
600
|
+
return !!v;
|
|
601
|
+
}).defaultErrorKey = 'emptyField';
|
|
602
|
+
// State is required if its a dropdown, it is not required if it is an input box
|
|
603
|
+
(R.isNotEmptyState = function($input) {
|
|
604
|
+
var v = $input.val();
|
|
605
|
+
if($input.is('select')) {
|
|
606
|
+
if(v == '-' || v == '--') return false;
|
|
607
|
+
}
|
|
608
|
+
return true;
|
|
609
|
+
}).defaultErrorKey = 'emptyField';
|
|
610
|
+
|
|
611
|
+
(R.isChecked = function($input) {
|
|
612
|
+
return $input.is(':checked');
|
|
613
|
+
}).defaultErrorKey = 'acceptTOS';
|
|
614
|
+
|
|
615
|
+
(R.isValidQuantity = function($input) {
|
|
616
|
+
return /^[0-9]*$/.test($input.val());
|
|
617
|
+
}).defaultErrorKey = 'invalidQuantity';
|
|
618
|
+
|
|
619
|
+
|
|
620
|
+
|
|
621
|
+
//////////////////////////////////////////////////
|
|
622
|
+
// Compiled from src/js/plan.js
|
|
623
|
+
//////////////////////////////////////////////////
|
|
624
|
+
|
|
625
|
+
R.Plan = {
|
|
626
|
+
create: createObject
|
|
627
|
+
, fromJSON: function(json) {
|
|
628
|
+
var p = this.create();
|
|
629
|
+
|
|
630
|
+
p.name = json.name;
|
|
631
|
+
p.code = json.plan_code;
|
|
632
|
+
p.currency = json.currency;
|
|
633
|
+
p.cost = new R.Cost(json.unit_amount_in_cents);
|
|
634
|
+
|
|
635
|
+
p.displayQuantity = json.display_quantity;
|
|
636
|
+
|
|
637
|
+
p.interval = new R.TimePeriod(
|
|
638
|
+
json.plan_interval_length,
|
|
639
|
+
json.plan_interval_unit
|
|
640
|
+
);
|
|
641
|
+
|
|
642
|
+
if(json.trial_interval_length) {
|
|
643
|
+
p.trial = new R.TimePeriod(
|
|
644
|
+
json.trial_interval_length,
|
|
645
|
+
json.trial_interval_unit
|
|
646
|
+
);
|
|
647
|
+
}
|
|
648
|
+
|
|
649
|
+
if(json.setup_fee_in_cents) {
|
|
650
|
+
p.setupFee = new R.Cost(json.setup_fee_in_cents);
|
|
651
|
+
}
|
|
652
|
+
|
|
653
|
+
if (json.vat_percentage) {
|
|
654
|
+
R.settings.VATPercent = parseFloat(json.vat_percentage);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
if (json.merchant_country) {
|
|
658
|
+
R.settings.country = json.merchant_country;
|
|
659
|
+
}
|
|
660
|
+
|
|
661
|
+
p.addOns = [];
|
|
662
|
+
if(json.add_ons) {
|
|
663
|
+
for(var l=json.add_ons.length, i=0; i < l; ++i) {
|
|
664
|
+
var a = json.add_ons[i];
|
|
665
|
+
p.addOns.push(R.AddOn.fromJSON(a));
|
|
666
|
+
}
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
return p;
|
|
670
|
+
}
|
|
671
|
+
, get: function(plan_code, currency, callback) {
|
|
672
|
+
$.ajax({
|
|
673
|
+
url: R.settings.baseURL+'plans/'+plan_code+"?currency="+currency,
|
|
674
|
+
// data: params,
|
|
675
|
+
dataType: "jsonp",
|
|
676
|
+
jsonp: "callback",
|
|
677
|
+
timeout: 10000,
|
|
678
|
+
success: function(data) {
|
|
679
|
+
var plan = R.Plan.fromJSON(data);
|
|
680
|
+
callback(plan);
|
|
681
|
+
}
|
|
682
|
+
});
|
|
683
|
+
}
|
|
684
|
+
, createSubscription: function() {
|
|
685
|
+
var s = createObject(R.Subscription);
|
|
686
|
+
s.plan = createObject(this);
|
|
687
|
+
s.plan.quantity = 1;
|
|
688
|
+
s.addOns = [];
|
|
689
|
+
return s;
|
|
690
|
+
}
|
|
691
|
+
};
|
|
692
|
+
|
|
693
|
+
R.AddOn = {
|
|
694
|
+
fromJSON: function(json) {
|
|
695
|
+
var a = createObject(R.AddOn);
|
|
696
|
+
a.name = json.name;
|
|
697
|
+
a.code = json.add_on_code;
|
|
698
|
+
a.cost = new R.Cost(json.default_unit_amount_in_cents);
|
|
699
|
+
a.displayQuantity = json.display_quantity;
|
|
700
|
+
return a;
|
|
701
|
+
}
|
|
702
|
+
|
|
703
|
+
, toJSON: function() {
|
|
704
|
+
return {
|
|
705
|
+
name: this.name
|
|
706
|
+
, add_on_code: this.code
|
|
707
|
+
, default_unit_amount_in_cents: this.default_unit_amount_in_cents
|
|
708
|
+
};
|
|
709
|
+
}
|
|
710
|
+
};
|
|
711
|
+
|
|
712
|
+
|
|
713
|
+
//////////////////////////////////////////////////
|
|
714
|
+
// Compiled from src/js/account.js
|
|
715
|
+
//////////////////////////////////////////////////
|
|
716
|
+
|
|
717
|
+
R.Account = {
|
|
718
|
+
create: createObject
|
|
719
|
+
, toJSON: function() {
|
|
720
|
+
return {
|
|
721
|
+
first_name: this.firstName
|
|
722
|
+
, last_name: this.lastName
|
|
723
|
+
, company_name: this.companyName
|
|
724
|
+
, account_code: this.code
|
|
725
|
+
, email: this.email
|
|
726
|
+
};
|
|
727
|
+
}
|
|
728
|
+
};
|
|
729
|
+
|
|
730
|
+
|
|
731
|
+
|
|
732
|
+
//////////////////////////////////////////////////
|
|
733
|
+
// Compiled from src/js/billing_info.js
|
|
734
|
+
//////////////////////////////////////////////////
|
|
735
|
+
|
|
736
|
+
R.BillingInfo = {
|
|
737
|
+
create: createObject
|
|
738
|
+
, toJSON: function() {
|
|
739
|
+
return {
|
|
740
|
+
first_name: this.firstName
|
|
741
|
+
, last_name: this.lastName
|
|
742
|
+
, month: this.month
|
|
743
|
+
, year: this.year
|
|
744
|
+
, number: this.number
|
|
745
|
+
, verification_value: this.cvv
|
|
746
|
+
, address1: this.address1
|
|
747
|
+
, address2: this.address2
|
|
748
|
+
, city: this.city
|
|
749
|
+
, state: this.state
|
|
750
|
+
, zip: this.zip
|
|
751
|
+
, country: this.country
|
|
752
|
+
, phone: this.phone
|
|
753
|
+
, vat_number: this.vatNumber
|
|
754
|
+
};
|
|
755
|
+
}
|
|
756
|
+
, save: function(options) {
|
|
757
|
+
var json = {
|
|
758
|
+
billing_info: this.toJSON()
|
|
759
|
+
, signature: options.signature
|
|
760
|
+
};
|
|
761
|
+
|
|
762
|
+
// Save first/last name on the account
|
|
763
|
+
// if not distinguished
|
|
764
|
+
if(!options.distinguishContactFromBillingInfo) {
|
|
765
|
+
json.account = {
|
|
766
|
+
account_code: options.accountCode
|
|
767
|
+
, first_name: this.firstName
|
|
768
|
+
, last_name: this.lastName
|
|
769
|
+
};
|
|
770
|
+
}
|
|
771
|
+
|
|
772
|
+
R.ajax({
|
|
773
|
+
url: R.settings.baseURL+'accounts/'+options.accountCode+'/billing_info/update'
|
|
774
|
+
, data: json
|
|
775
|
+
, dataType: 'jsonp'
|
|
776
|
+
, jsonp: 'callback'
|
|
777
|
+
, timeout: 60000
|
|
778
|
+
, success: function(data) {
|
|
779
|
+
if(data.success && options.success) {
|
|
780
|
+
options.success(data.success);
|
|
781
|
+
}
|
|
782
|
+
else if(data.errors && options.error) {
|
|
783
|
+
options.error( R.flattenErrors(data.errors) );
|
|
784
|
+
}
|
|
785
|
+
}
|
|
786
|
+
, error: function() {
|
|
787
|
+
if(options.error) {
|
|
788
|
+
options.error(['Unknown error processing transaction. Please try again later.']);
|
|
789
|
+
}
|
|
790
|
+
}
|
|
791
|
+
, complete: options.complete || $.noop
|
|
792
|
+
});
|
|
793
|
+
}
|
|
794
|
+
};
|
|
795
|
+
|
|
796
|
+
|
|
797
|
+
|
|
798
|
+
//////////////////////////////////////////////////
|
|
799
|
+
// Compiled from src/js/subscription.js
|
|
800
|
+
//////////////////////////////////////////////////
|
|
801
|
+
|
|
802
|
+
// Base Subscription prototype
|
|
803
|
+
R.Subscription = {
|
|
804
|
+
create: createObject
|
|
805
|
+
, plan: R.Plan
|
|
806
|
+
, addOns: []
|
|
807
|
+
|
|
808
|
+
, calculateTotals: function() {
|
|
809
|
+
var totals = {
|
|
810
|
+
stages: {}
|
|
811
|
+
};
|
|
812
|
+
|
|
813
|
+
// PLAN
|
|
814
|
+
totals.plan = this.plan.cost.mult(this.plan.quantity);
|
|
815
|
+
|
|
816
|
+
// ADD-ONS
|
|
817
|
+
totals.allAddOns = new R.Cost(0);
|
|
818
|
+
totals.addOns = {};
|
|
819
|
+
for(var l=this.addOns.length, i=0; i < l; ++i) {
|
|
820
|
+
var a = this.addOns[i],
|
|
821
|
+
c = a.cost.mult(a.quantity);
|
|
822
|
+
totals.addOns[a.code] = c;
|
|
823
|
+
totals.allAddOns = totals.allAddOns.add(c);
|
|
824
|
+
}
|
|
825
|
+
|
|
826
|
+
totals.stages.recurring = totals.plan.add(totals.allAddOns);
|
|
827
|
+
|
|
828
|
+
totals.stages.now = totals.plan.add(totals.allAddOns);
|
|
829
|
+
|
|
830
|
+
// FREE TRIAL
|
|
831
|
+
if(this.plan.trial) {
|
|
832
|
+
totals.stages.now = R.Cost.FREE;
|
|
833
|
+
}
|
|
834
|
+
|
|
835
|
+
// COUPON
|
|
836
|
+
if(this.coupon) {
|
|
837
|
+
var beforeDiscount = totals.stages.now;
|
|
838
|
+
var afterDiscount = totals.stages.now.discount(this.coupon);
|
|
839
|
+
totals.coupon = afterDiscount.sub(beforeDiscount);
|
|
840
|
+
totals.stages.now = afterDiscount;
|
|
841
|
+
}
|
|
842
|
+
|
|
843
|
+
// SETUP FEE
|
|
844
|
+
if(this.plan.setupFee) {
|
|
845
|
+
totals.stages.now = totals.stages.now.add(this.plan.setupFee);
|
|
846
|
+
}
|
|
847
|
+
|
|
848
|
+
// VAT
|
|
849
|
+
if(this.billingInfo && R.isVATChargeApplicable(this.billingInfo.country,this.billingInfo.vatNumber)) {
|
|
850
|
+
totals.vat = totals.stages.now.mult( (R.settings.VATPercent/100) );
|
|
851
|
+
totals.stages.now = totals.stages.now.add(totals.vat);
|
|
852
|
+
}
|
|
853
|
+
|
|
854
|
+
return totals;
|
|
855
|
+
}
|
|
856
|
+
, redeemAddOn: function(addOn) {
|
|
857
|
+
var redemption = addOn.createRedemption();
|
|
858
|
+
this.addOns.push(redemption);
|
|
859
|
+
return redemption;
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
, removeAddOn: function(code) {
|
|
863
|
+
for(var a=this.addOns, l=a.length, i=0; i < l; ++i) {
|
|
864
|
+
if(a[i].code == code) {
|
|
865
|
+
return a.splice(i,1);
|
|
866
|
+
}
|
|
867
|
+
}
|
|
868
|
+
}
|
|
869
|
+
|
|
870
|
+
, findAddOnByCode: function(code) {
|
|
871
|
+
for(var l=this.addOns.length, i=0; i < l; ++i) {
|
|
872
|
+
if(this.addOns[i].code == code) {
|
|
873
|
+
return this.addOns[i];
|
|
874
|
+
}
|
|
875
|
+
}
|
|
876
|
+
return false;
|
|
877
|
+
}
|
|
878
|
+
|
|
879
|
+
, toJSON: function() {
|
|
880
|
+
var json = {
|
|
881
|
+
plan_code: this.plan.code
|
|
882
|
+
, quantity: this.plan.quantity
|
|
883
|
+
, currency: this.plan.currency
|
|
884
|
+
, coupon_code: this.coupon ? this.coupon.code : undefined
|
|
885
|
+
, add_ons: []
|
|
886
|
+
};
|
|
887
|
+
|
|
888
|
+
for(var i=0, l=this.addOns.length, a=json.add_ons, b=this.addOns; i < l; ++i) {
|
|
889
|
+
a.push({
|
|
890
|
+
add_on_code: b[i].code
|
|
891
|
+
, quantity: b[i].quantity
|
|
892
|
+
});
|
|
893
|
+
}
|
|
894
|
+
|
|
895
|
+
return json;
|
|
896
|
+
}
|
|
897
|
+
|
|
898
|
+
, save: function(options) {
|
|
899
|
+
var json = {
|
|
900
|
+
subscription: this.toJSON()
|
|
901
|
+
, account: this.account.toJSON()
|
|
902
|
+
, billing_info: this.billingInfo.toJSON()
|
|
903
|
+
, signature: options.signature
|
|
904
|
+
};
|
|
905
|
+
|
|
906
|
+
R.ajax({
|
|
907
|
+
url: R.settings.baseURL+'subscribe',
|
|
908
|
+
data: json,
|
|
909
|
+
dataType: "jsonp",
|
|
910
|
+
jsonp: "callback",
|
|
911
|
+
timeout: 60000,
|
|
912
|
+
success: function(data) {
|
|
913
|
+
if(data.success && options.success) {
|
|
914
|
+
options.success(data.success);
|
|
915
|
+
}
|
|
916
|
+
else if(data.errors && options.error) {
|
|
917
|
+
var errorCode = data.errors.error_code;
|
|
918
|
+
delete data.errors.error_code;
|
|
919
|
+
options.error( R.flattenErrors(data.errors), errorCode );
|
|
920
|
+
}
|
|
921
|
+
},
|
|
922
|
+
error: function() {
|
|
923
|
+
if(options.error) {
|
|
924
|
+
options.error(['Unknown error processing transaction. Please try again later.']);
|
|
925
|
+
}
|
|
926
|
+
},
|
|
927
|
+
complete: options.complete
|
|
928
|
+
});
|
|
929
|
+
|
|
930
|
+
}
|
|
931
|
+
};
|
|
932
|
+
|
|
933
|
+
R.AddOn.createRedemption = function(qty) {
|
|
934
|
+
var r = createObject(this);
|
|
935
|
+
r.quantity = qty || 1;
|
|
936
|
+
return r;
|
|
937
|
+
};
|
|
938
|
+
|
|
939
|
+
R.Coupon = {
|
|
940
|
+
fromJSON: function(json) {
|
|
941
|
+
var c = createObject(R.Coupon);
|
|
942
|
+
|
|
943
|
+
if(json.discount_in_cents)
|
|
944
|
+
c.discountCost = new R.Cost(-json.discount_in_cents);
|
|
945
|
+
else if(json.discount_percent)
|
|
946
|
+
c.discountRatio = json.discount_percent/100;
|
|
947
|
+
|
|
948
|
+
c.description = json.description;
|
|
949
|
+
|
|
950
|
+
return c;
|
|
951
|
+
}
|
|
952
|
+
|
|
953
|
+
, toJSON: function() {
|
|
954
|
+
}
|
|
955
|
+
};
|
|
956
|
+
|
|
957
|
+
R.Cost.prototype.discount = function(coupon){
|
|
958
|
+
if(coupon.discountCost)
|
|
959
|
+
return this.add(coupon.discountCost);
|
|
960
|
+
|
|
961
|
+
var ret = this.sub( this.mult(coupon.discountRatio) );
|
|
962
|
+
if(ret.cents() < 0) {
|
|
963
|
+
return R.Cost.FREE;
|
|
964
|
+
}
|
|
965
|
+
|
|
966
|
+
return ret;
|
|
967
|
+
};
|
|
968
|
+
|
|
969
|
+
R.Subscription.getCoupon = function(couponCode, successCallback, errorCallback) {
|
|
970
|
+
|
|
971
|
+
if(!R.settings.baseURL) { R.raiseError('Company subdomain not configured'); }
|
|
972
|
+
|
|
973
|
+
var couponCurrencyQuery = (R.settings.currency !== undefined ? '?currency='+R.settings.currency : '');
|
|
974
|
+
|
|
975
|
+
return R.ajax({
|
|
976
|
+
url: R.settings.baseURL+'plans/'+this.plan.code+'/coupons/'+couponCode+couponCurrencyQuery,
|
|
977
|
+
// data: params,
|
|
978
|
+
dataType: "jsonp",
|
|
979
|
+
jsonp: "callback",
|
|
980
|
+
timeout: 10000,
|
|
981
|
+
success: function(data) {
|
|
982
|
+
if(data.valid) {
|
|
983
|
+
var coupon = R.Coupon.fromJSON(data);
|
|
984
|
+
coupon.code = couponCode;
|
|
985
|
+
successCallback(coupon);
|
|
986
|
+
}
|
|
987
|
+
else {
|
|
988
|
+
errorCallback();
|
|
989
|
+
}
|
|
990
|
+
},
|
|
991
|
+
error: function() {
|
|
992
|
+
errorCallback();
|
|
993
|
+
}
|
|
994
|
+
});
|
|
995
|
+
};
|
|
996
|
+
|
|
997
|
+
|
|
998
|
+
|
|
999
|
+
//////////////////////////////////////////////////
|
|
1000
|
+
// Compiled from src/js/transaction.js
|
|
1001
|
+
//////////////////////////////////////////////////
|
|
1002
|
+
|
|
1003
|
+
|
|
1004
|
+
R.Transaction = {
|
|
1005
|
+
// Note - No toJSON function for this object, all parameters must be signed.
|
|
1006
|
+
create: createObject
|
|
1007
|
+
, save: function(options) {
|
|
1008
|
+
var json = {
|
|
1009
|
+
account: this.account ? this.account.toJSON() : undefined
|
|
1010
|
+
, billing_info: this.billingInfo.toJSON()
|
|
1011
|
+
, signature: options.signature
|
|
1012
|
+
};
|
|
1013
|
+
|
|
1014
|
+
R.ajax({
|
|
1015
|
+
url: R.settings.baseURL+'transactions/create'
|
|
1016
|
+
, data: json
|
|
1017
|
+
, dataType: 'jsonp'
|
|
1018
|
+
, jsonp: 'callback'
|
|
1019
|
+
, timeout: 60000
|
|
1020
|
+
, success: function(data) {
|
|
1021
|
+
if(data.success && options.success) {
|
|
1022
|
+
options.success(data.success);
|
|
1023
|
+
}
|
|
1024
|
+
else if(data.errors && options.error) {
|
|
1025
|
+
options.error( R.flattenErrors(data.errors) );
|
|
1026
|
+
}
|
|
1027
|
+
}
|
|
1028
|
+
, error: function() {
|
|
1029
|
+
if(options.error) {
|
|
1030
|
+
options.error(['Unknown error processing transaction. Please try again later.']);
|
|
1031
|
+
}
|
|
1032
|
+
}
|
|
1033
|
+
, complete: options.complete || $.noop
|
|
1034
|
+
});
|
|
1035
|
+
}
|
|
1036
|
+
};
|
|
1037
|
+
|
|
1038
|
+
|
|
1039
|
+
|
|
1040
|
+
|
|
1041
|
+
//////////////////////////////////////////////////
|
|
1042
|
+
// Compiled from src/js/ui.js
|
|
1043
|
+
//////////////////////////////////////////////////
|
|
1044
|
+
|
|
1045
|
+
R.UserError = {};
|
|
1046
|
+
|
|
1047
|
+
function raiseUserError(validation, elem) {
|
|
1048
|
+
var e = createObject(R.UserError);
|
|
1049
|
+
e.validation = validation;
|
|
1050
|
+
e.element = elem;
|
|
1051
|
+
throw e;
|
|
1052
|
+
}
|
|
1053
|
+
|
|
1054
|
+
function invalidMode(e) {
|
|
1055
|
+
var $input = e.element;
|
|
1056
|
+
var message = R.locale.errors[e.validation.errorKey];
|
|
1057
|
+
var validator = e.validation.validator;
|
|
1058
|
+
|
|
1059
|
+
var $e = $('<div class="error">');
|
|
1060
|
+
$e.text(message);
|
|
1061
|
+
$e.appendTo($input.parent());
|
|
1062
|
+
|
|
1063
|
+
$input.addClass('invalid');
|
|
1064
|
+
$input.bind('change keyup', function handler(e) {
|
|
1065
|
+
|
|
1066
|
+
if(validator($input)) {
|
|
1067
|
+
$input.removeClass('invalid');
|
|
1068
|
+
$e.remove();
|
|
1069
|
+
$input.unbind(e);
|
|
1070
|
+
}
|
|
1071
|
+
});
|
|
1072
|
+
}
|
|
1073
|
+
|
|
1074
|
+
function validationGroup(pull,success) {
|
|
1075
|
+
var anyErrors = false;
|
|
1076
|
+
var puller = {
|
|
1077
|
+
field: function($form, fieldSel, validations) {
|
|
1078
|
+
validations = Array.prototype.slice.call(arguments, 2);
|
|
1079
|
+
return pullField($form, fieldSel, validations, function onError(error) {
|
|
1080
|
+
if(!anyErrors) error.element.focus();
|
|
1081
|
+
invalidMode(error);
|
|
1082
|
+
anyErrors = true;
|
|
1083
|
+
|
|
1084
|
+
if(R.settings.oneErrorPerForm)
|
|
1085
|
+
throw {stopPulling:true};
|
|
1086
|
+
});
|
|
1087
|
+
}
|
|
1088
|
+
};
|
|
1089
|
+
|
|
1090
|
+
|
|
1091
|
+
try {
|
|
1092
|
+
pull(puller);
|
|
1093
|
+
}
|
|
1094
|
+
catch(e) {
|
|
1095
|
+
if(!e.stopPulling) {
|
|
1096
|
+
throw e;
|
|
1097
|
+
}
|
|
1098
|
+
}
|
|
1099
|
+
|
|
1100
|
+
if(!anyErrors) {
|
|
1101
|
+
success();
|
|
1102
|
+
}
|
|
1103
|
+
}
|
|
1104
|
+
|
|
1105
|
+
|
|
1106
|
+
function pullField($form, fieldSel, validations, onError) {
|
|
1107
|
+
// Try text input
|
|
1108
|
+
var $input = $form.find(fieldSel + ' input');
|
|
1109
|
+
|
|
1110
|
+
// Try as select
|
|
1111
|
+
if($input.length == 0) {
|
|
1112
|
+
$input = $form.find(fieldSel + ' select');
|
|
1113
|
+
}
|
|
1114
|
+
|
|
1115
|
+
// Treat nonexistence as removed deliberately
|
|
1116
|
+
if($input.length == 0) return undefined;
|
|
1117
|
+
|
|
1118
|
+
var val = $input.val();
|
|
1119
|
+
|
|
1120
|
+
for(var i=0,l=validations.length; i < l; ++i) {
|
|
1121
|
+
var v = validations[i];
|
|
1122
|
+
|
|
1123
|
+
if(!v.validator($input)) {
|
|
1124
|
+
onError({
|
|
1125
|
+
element: $input
|
|
1126
|
+
, validation: v
|
|
1127
|
+
});
|
|
1128
|
+
|
|
1129
|
+
if(R.settings.oneErrorPerField)
|
|
1130
|
+
break;
|
|
1131
|
+
}
|
|
1132
|
+
}
|
|
1133
|
+
|
|
1134
|
+
return val;
|
|
1135
|
+
}
|
|
1136
|
+
|
|
1137
|
+
|
|
1138
|
+
// Make a 'validation' from validator / errorKey
|
|
1139
|
+
function V(v,k) {
|
|
1140
|
+
return {
|
|
1141
|
+
validator: v,
|
|
1142
|
+
errorKey: k || v.defaultErrorKey
|
|
1143
|
+
};
|
|
1144
|
+
}
|
|
1145
|
+
|
|
1146
|
+
|
|
1147
|
+
// == SERVER ERROR UI METHODS
|
|
1148
|
+
|
|
1149
|
+
function clearServerErrors($form) {
|
|
1150
|
+
var $serverErrors = $form.find('.server_errors');
|
|
1151
|
+
$serverErrors.removeClass('any').addClass('none');
|
|
1152
|
+
$serverErrors.empty();
|
|
1153
|
+
}
|
|
1154
|
+
|
|
1155
|
+
function displayServerErrors($form, errors) {
|
|
1156
|
+
var $serverErrors = $form.find('.server_errors');
|
|
1157
|
+
clearServerErrors($form);
|
|
1158
|
+
|
|
1159
|
+
var l = errors.length;
|
|
1160
|
+
if(l) {
|
|
1161
|
+
$serverErrors.removeClass('none').addClass('any');
|
|
1162
|
+
for(var i=0; i < l; ++i) {
|
|
1163
|
+
var $e = $('<div class="error">');
|
|
1164
|
+
$e.text(errors[i]);
|
|
1165
|
+
$serverErrors.append($e);
|
|
1166
|
+
}
|
|
1167
|
+
}
|
|
1168
|
+
}
|
|
1169
|
+
|
|
1170
|
+
|
|
1171
|
+
var preFillMap = {
|
|
1172
|
+
account: {
|
|
1173
|
+
firstName: '.contact_info > .full_name > .first_name > input'
|
|
1174
|
+
, lastName: '.contact_info > .full_name > .last_name > input'
|
|
1175
|
+
, email: '.contact_info > .email > input'
|
|
1176
|
+
, phone: '.contact_info > .phone > input'
|
|
1177
|
+
, companyName: '.contact_info > .company_name > input'
|
|
1178
|
+
}
|
|
1179
|
+
, billingInfo: {
|
|
1180
|
+
firstName: '.billing_info > .credit_card > .first_name > input'
|
|
1181
|
+
, lastName: '.billing_info > .credit_card > .last_name > input'
|
|
1182
|
+
, address1: '.billing_info > .address > .address1 > input'
|
|
1183
|
+
, address2: '.billing_info > .address > .address2 > input'
|
|
1184
|
+
, country: '.billing_info > .address > .country > select'
|
|
1185
|
+
, city: '.billing_info > .address > .city > input'
|
|
1186
|
+
, state: '.billing_info > .address > .state_zip > .state > input'
|
|
1187
|
+
, zip: '.billing_info > .address > .state_zip > .zip > input'
|
|
1188
|
+
, vatNumber: '.billing_info > .vat_number > input'
|
|
1189
|
+
|
|
1190
|
+
, cardNumber: '.billing_info .card_number > input'
|
|
1191
|
+
, CVV: '.billing_info .cvv > input'
|
|
1192
|
+
}
|
|
1193
|
+
, subscription: {
|
|
1194
|
+
couponCode: '.subscription > .coupon > .coupon_code > input'
|
|
1195
|
+
}
|
|
1196
|
+
};
|
|
1197
|
+
|
|
1198
|
+
function preFillValues($form, options, mapObject) {
|
|
1199
|
+
|
|
1200
|
+
(function recurse(preFill,mapObject,keypath) {
|
|
1201
|
+
|
|
1202
|
+
if(!preFill) return;
|
|
1203
|
+
|
|
1204
|
+
for(var k in preFill) {
|
|
1205
|
+
if(preFill.hasOwnProperty(k) && mapObject.hasOwnProperty(k)) {
|
|
1206
|
+
|
|
1207
|
+
var v = preFill[k];
|
|
1208
|
+
var selectorOrNested = mapObject[k];
|
|
1209
|
+
var lcuk = cc2lcu(k);
|
|
1210
|
+
var keypath2 = keypath ? (keypath+'.'+lcuk) : lcuk;
|
|
1211
|
+
|
|
1212
|
+
|
|
1213
|
+
// jquery selector
|
|
1214
|
+
if(typeof selectorOrNested == 'string') {
|
|
1215
|
+
|
|
1216
|
+
var $input = $form.find(selectorOrNested);
|
|
1217
|
+
$input.val(v).change();
|
|
1218
|
+
}
|
|
1219
|
+
// nested mapping
|
|
1220
|
+
else if(typeof selectorOrNested == 'object') {
|
|
1221
|
+
recurse(v, selectorOrNested, keypath2);
|
|
1222
|
+
}
|
|
1223
|
+
}
|
|
1224
|
+
}
|
|
1225
|
+
})(options,mapObject);
|
|
1226
|
+
}
|
|
1227
|
+
|
|
1228
|
+
|
|
1229
|
+
function initCommonForm($form, options) {
|
|
1230
|
+
|
|
1231
|
+
if(!options.collectPhone) {
|
|
1232
|
+
$form.find('.phone').remove();
|
|
1233
|
+
}
|
|
1234
|
+
|
|
1235
|
+
if(!options.collectCompany) {
|
|
1236
|
+
$form.find('.company_name').remove();
|
|
1237
|
+
}
|
|
1238
|
+
|
|
1239
|
+
$form.delegate('.placeholder', 'click', function() {
|
|
1240
|
+
var $label = $(this);
|
|
1241
|
+
var $li = $(this).parent();
|
|
1242
|
+
$li.find('input').focus();
|
|
1243
|
+
});
|
|
1244
|
+
|
|
1245
|
+
$form.delegate('input', 'change keyup', function() {
|
|
1246
|
+
var $input = $(this);
|
|
1247
|
+
var $li = $(this).parent();
|
|
1248
|
+
|
|
1249
|
+
if($input.val().length > 0) {
|
|
1250
|
+
$li.find('.placeholder').hide();
|
|
1251
|
+
}
|
|
1252
|
+
else {
|
|
1253
|
+
$li.find('.placeholder').show();
|
|
1254
|
+
}
|
|
1255
|
+
});
|
|
1256
|
+
|
|
1257
|
+
|
|
1258
|
+
$form.delegate('input', 'focus', function() {
|
|
1259
|
+
$(this).parent().addClass('focus');
|
|
1260
|
+
});
|
|
1261
|
+
|
|
1262
|
+
$form.delegate('input', 'blur', function() {
|
|
1263
|
+
$(this).parent().removeClass('focus');
|
|
1264
|
+
});
|
|
1265
|
+
|
|
1266
|
+
$form.delegate('input', 'keydown', function(e) {
|
|
1267
|
+
if(e.keyCode >= 48 && e.keyCode <= 90) {
|
|
1268
|
+
$(this).parent().find('.placeholder').hide();
|
|
1269
|
+
}
|
|
1270
|
+
});
|
|
1271
|
+
|
|
1272
|
+
preFillValues($form, options, preFillMap);
|
|
1273
|
+
}
|
|
1274
|
+
|
|
1275
|
+
function initContactInfoForm($form, options) {
|
|
1276
|
+
|
|
1277
|
+
// == FIRSTNAME / LASTNAME REDUNDANCY
|
|
1278
|
+
if(options.distinguishContactFromBillingInfo) {
|
|
1279
|
+
var $contactFirstName = $form.find('.contact_info .first_name input');
|
|
1280
|
+
var $contactLastName = $form.find('.contact_info .last_name input');
|
|
1281
|
+
var prevFirstName = $contactFirstName.val();
|
|
1282
|
+
var prevLastName = $contactLastName.val();
|
|
1283
|
+
$form.find('.contact_info .first_name input').change(function() {
|
|
1284
|
+
var $billingFirstName = $form.find('.billing_info .first_name input');
|
|
1285
|
+
if($billingFirstName.val() == prevFirstName) {
|
|
1286
|
+
$billingFirstName.val( $(this).val() ).change();
|
|
1287
|
+
}
|
|
1288
|
+
prevFirstName = $contactFirstName.val();
|
|
1289
|
+
});
|
|
1290
|
+
$form.find('.contact_info .last_name input').change(function() {
|
|
1291
|
+
var $billingLastName = $form.find('.billing_info .last_name input');
|
|
1292
|
+
if($billingLastName.val() == prevLastName) {
|
|
1293
|
+
$billingLastName.val( $(this).val() ).change();
|
|
1294
|
+
}
|
|
1295
|
+
prevLastName = $contactLastName.val();
|
|
1296
|
+
});
|
|
1297
|
+
|
|
1298
|
+
}
|
|
1299
|
+
else {
|
|
1300
|
+
$form.find('.billing_info .first_name, .billing_info .last_name').remove();
|
|
1301
|
+
}
|
|
1302
|
+
|
|
1303
|
+
}
|
|
1304
|
+
|
|
1305
|
+
function initBillingInfoForm($form, options) {
|
|
1306
|
+
|
|
1307
|
+
// == SWAPPING OF STATE INPUT WITH SELECT
|
|
1308
|
+
var $countrySelect = $form.find('.country select');
|
|
1309
|
+
var $state = $form.find('.state');
|
|
1310
|
+
var $stateInput = $state.find('input');
|
|
1311
|
+
var $manualStateInput = $state.children();
|
|
1312
|
+
var $savedStateSelect = {};
|
|
1313
|
+
var knownStates = R.states;
|
|
1314
|
+
var prevCountry = $countrySelect.val();
|
|
1315
|
+
|
|
1316
|
+
function matchKnownStateWithInput(country, stateStr) {
|
|
1317
|
+
var ref = knownStates[country];
|
|
1318
|
+
// Normalize stateStr
|
|
1319
|
+
stateStr = $.trim(stateStr.toUpperCase());
|
|
1320
|
+
|
|
1321
|
+
// Is a state code
|
|
1322
|
+
if(ref.hasOwnProperty(stateStr)) {
|
|
1323
|
+
return stateStr;
|
|
1324
|
+
}
|
|
1325
|
+
|
|
1326
|
+
// Search through state names to find the code
|
|
1327
|
+
for(var k in ref) {
|
|
1328
|
+
if(ref.hasOwnProperty(k)) {
|
|
1329
|
+
var v = ref[k];
|
|
1330
|
+
if(stateStr == v.toUpperCase()) {
|
|
1331
|
+
return k;
|
|
1332
|
+
}
|
|
1333
|
+
}
|
|
1334
|
+
}
|
|
1335
|
+
|
|
1336
|
+
return false;
|
|
1337
|
+
}
|
|
1338
|
+
|
|
1339
|
+
function swapStateSelectOrInput(country, state) {
|
|
1340
|
+
var inSelectMode = $state.hasClass('select_mode');
|
|
1341
|
+
if(country == 'US' || country == 'CA') {
|
|
1342
|
+
if(!inSelectMode || prevCountry != country) {
|
|
1343
|
+
var manualVal = $state.find('input').val();
|
|
1344
|
+
|
|
1345
|
+
if(manualVal != undefined && manualVal != '') {
|
|
1346
|
+
state = matchKnownStateWithInput(country, manualVal);
|
|
1347
|
+
|
|
1348
|
+
if(!state) return false;
|
|
1349
|
+
}
|
|
1350
|
+
|
|
1351
|
+
// Change to select mode
|
|
1352
|
+
$state.addClass('select_mode');
|
|
1353
|
+
// Detatch manual-input children from field
|
|
1354
|
+
$state.children().detach();
|
|
1355
|
+
// Instantiate HTML DOM only now, and cache it
|
|
1356
|
+
$savedStateSelect[country] = $savedStateSelect[country] || jsonToSelect(knownStates[country]);
|
|
1357
|
+
// Insert select into field
|
|
1358
|
+
$state.append($savedStateSelect[country]);
|
|
1359
|
+
// Set known state, if provided
|
|
1360
|
+
if(state) $state.find('select').val(state);
|
|
1361
|
+
}
|
|
1362
|
+
|
|
1363
|
+
}
|
|
1364
|
+
else if(inSelectMode) {
|
|
1365
|
+
// Restore original manual state input field
|
|
1366
|
+
$state.empty().append($manualStateInput).removeClass('select_mode');
|
|
1367
|
+
}
|
|
1368
|
+
}
|
|
1369
|
+
|
|
1370
|
+
$stateInput.bind('change keyup', function() {
|
|
1371
|
+
swapStateSelectOrInput(prevCountry);
|
|
1372
|
+
});
|
|
1373
|
+
|
|
1374
|
+
$countrySelect.change(function() {
|
|
1375
|
+
var country = $(this).val();
|
|
1376
|
+
swapStateSelectOrInput(country);
|
|
1377
|
+
prevCountry = country;
|
|
1378
|
+
});
|
|
1379
|
+
|
|
1380
|
+
// == GEOIP
|
|
1381
|
+
function niceSet($jq, v) {
|
|
1382
|
+
var cur = $jq.val();
|
|
1383
|
+
if(!v || v == '') return false;
|
|
1384
|
+
if(cur && cur != '' && cur != '-') return false;
|
|
1385
|
+
|
|
1386
|
+
return $jq.val(v);
|
|
1387
|
+
}
|
|
1388
|
+
|
|
1389
|
+
if(options.enableGeoIP) {
|
|
1390
|
+
$.ajax({
|
|
1391
|
+
url: R.settings.baseURL+'location',
|
|
1392
|
+
dataType: "jsonp",
|
|
1393
|
+
jsonp: "callback",
|
|
1394
|
+
success: function(data) {
|
|
1395
|
+
if(data.country) {
|
|
1396
|
+
niceSet($countrySelect, data.country);
|
|
1397
|
+
swapStateSelectOrInput(data.country, data.state);
|
|
1398
|
+
}
|
|
1399
|
+
}
|
|
1400
|
+
});
|
|
1401
|
+
}
|
|
1402
|
+
else {
|
|
1403
|
+
// == DEFAULT BUYER TO SELLER COUNTRY
|
|
1404
|
+
if(R.settings.country) {
|
|
1405
|
+
var $countryOpt = $form.find('.country option[value='+R.settings.country+']');
|
|
1406
|
+
if($countryOpt.length) {
|
|
1407
|
+
$countryOpt.attr('selected', true).change();
|
|
1408
|
+
}
|
|
1409
|
+
}
|
|
1410
|
+
}
|
|
1411
|
+
|
|
1412
|
+
var now = new Date();
|
|
1413
|
+
var year = now.getFullYear();
|
|
1414
|
+
var month = now.getMonth();
|
|
1415
|
+
var $yearSelect = $form.find('.year select');
|
|
1416
|
+
var $monthSelect = $form.find('.month select');
|
|
1417
|
+
|
|
1418
|
+
// == GENERATE YEAR SELECT OPTIONS
|
|
1419
|
+
for(var i=year; i <= year+10; ++i) {
|
|
1420
|
+
var $yearOpt = $('<option name="'+i+'">'+i+'</option>');
|
|
1421
|
+
$yearOpt.appendTo($yearSelect);
|
|
1422
|
+
}
|
|
1423
|
+
$yearSelect.val(year+1);
|
|
1424
|
+
|
|
1425
|
+
|
|
1426
|
+
// == DISABLE INVALID MONTHS, SELECT CURRENT
|
|
1427
|
+
function updateMonths() {
|
|
1428
|
+
if($yearSelect.val() == year) {
|
|
1429
|
+
var foundSelected = false; // If we've set a selection yet
|
|
1430
|
+
|
|
1431
|
+
if($monthSelect.val() > month) {
|
|
1432
|
+
// We know the current selection is already valid
|
|
1433
|
+
foundSelected = true;
|
|
1434
|
+
}
|
|
1435
|
+
|
|
1436
|
+
$monthSelect.find('option').each(function(){
|
|
1437
|
+
if($(this).val() <= month) {
|
|
1438
|
+
$(this).attr('disabled', true);
|
|
1439
|
+
}
|
|
1440
|
+
else {
|
|
1441
|
+
$(this).removeAttr('disabled');
|
|
1442
|
+
|
|
1443
|
+
if(!foundSelected) {
|
|
1444
|
+
$(this).attr('selected', true);
|
|
1445
|
+
foundSelected = true;
|
|
1446
|
+
}
|
|
1447
|
+
}
|
|
1448
|
+
});
|
|
1449
|
+
}
|
|
1450
|
+
else {
|
|
1451
|
+
$monthSelect.find('option').removeAttr('disabled');
|
|
1452
|
+
}
|
|
1453
|
+
};
|
|
1454
|
+
updateMonths();
|
|
1455
|
+
$yearSelect.change(updateMonths);
|
|
1456
|
+
|
|
1457
|
+
|
|
1458
|
+
// == HIDE UNNECESSARY ADDRESS FIELDS
|
|
1459
|
+
|
|
1460
|
+
if(options.addressRequirement == 'none') {
|
|
1461
|
+
$form.find('.address').remove();
|
|
1462
|
+
}
|
|
1463
|
+
else if(options.addressRequirement == 'zip') {
|
|
1464
|
+
$form.find('.address').addClass('only_zip');
|
|
1465
|
+
$form.find('.address1, .address2, .city, .state').remove();
|
|
1466
|
+
|
|
1467
|
+
// Only remove country if no VAT support
|
|
1468
|
+
if(!R.settings.VATPercent) {
|
|
1469
|
+
$form.find('.country').remove();
|
|
1470
|
+
}
|
|
1471
|
+
}
|
|
1472
|
+
else if(options.addressRequirement == 'zipstreet') {
|
|
1473
|
+
$form.find('.address').addClass('only_zipstreet');
|
|
1474
|
+
$form.find('.city, .state').remove();
|
|
1475
|
+
|
|
1476
|
+
// Only remove country if no VAT support
|
|
1477
|
+
if(!R.settings.VATPercent) {
|
|
1478
|
+
$form.find('.country').remove();
|
|
1479
|
+
}
|
|
1480
|
+
}
|
|
1481
|
+
else if(options.addressRequirement == 'full') {
|
|
1482
|
+
$form.find('.address').addClass('full');
|
|
1483
|
+
}
|
|
1484
|
+
// == BUILD ACCEPTED CARDS DOM
|
|
1485
|
+
var $acceptedCards = $form.find('.accepted_cards');
|
|
1486
|
+
|
|
1487
|
+
if(options.acceptedCards) {
|
|
1488
|
+
var a = options.acceptedCards
|
|
1489
|
+
, l = a.length;
|
|
1490
|
+
|
|
1491
|
+
for(var i=0; i < l; ++i) {
|
|
1492
|
+
var cardId = a[i];
|
|
1493
|
+
var $card = $('<div class="card '+cardId+'">');
|
|
1494
|
+
var card = R.knownCards[cardId];
|
|
1495
|
+
if(card && card.name) {
|
|
1496
|
+
$card.text(card.name);
|
|
1497
|
+
}
|
|
1498
|
+
$acceptedCards.append($card);
|
|
1499
|
+
}
|
|
1500
|
+
}
|
|
1501
|
+
|
|
1502
|
+
// == SHOW/HIDE CARD TYPES
|
|
1503
|
+
$form.find('.card_number input').bind('change keyup', function() {
|
|
1504
|
+
var type = R.detectCardType( $(this).val() );
|
|
1505
|
+
if(type) {
|
|
1506
|
+
$acceptedCards.find('.card').each(function(){
|
|
1507
|
+
$(this).toggleClass('match', $(this).hasClass(type));
|
|
1508
|
+
$(this).toggleClass('no_match', !$(this).hasClass(type));
|
|
1509
|
+
});
|
|
1510
|
+
}
|
|
1511
|
+
else {
|
|
1512
|
+
$acceptedCards.find('.card').removeClass('match no_match');
|
|
1513
|
+
}
|
|
1514
|
+
});
|
|
1515
|
+
}
|
|
1516
|
+
|
|
1517
|
+
|
|
1518
|
+
function pullAccountFields($form, account, options, pull) {
|
|
1519
|
+
account.firstName = pull.field($form, '.contact_info .first_name', V(R.isNotEmpty));
|
|
1520
|
+
account.lastName = pull.field($form, '.contact_info .last_name', V(R.isNotEmpty));
|
|
1521
|
+
account.companyName = pull.field($form, '.contact_info .company_name');
|
|
1522
|
+
account.email = pull.field($form, '.email', V(R.isNotEmpty), V(R.isValidEmail));
|
|
1523
|
+
account.code = options.accountCode;
|
|
1524
|
+
}
|
|
1525
|
+
|
|
1526
|
+
|
|
1527
|
+
function pullBillingInfoFields($form, billingInfo, options, pull) {
|
|
1528
|
+
billingInfo.firstName = pull.field($form, '.billing_info .first_name', V(R.isNotEmpty));
|
|
1529
|
+
billingInfo.lastName = pull.field($form, '.billing_info .last_name', V(R.isNotEmpty));
|
|
1530
|
+
billingInfo.number = pull.field($form, '.card_number', V(R.isNotEmpty), V(R.isValidCC));
|
|
1531
|
+
billingInfo.cvv = pull.field($form, '.cvv', V(R.isNotEmpty), V(R.isValidCVV));
|
|
1532
|
+
|
|
1533
|
+
billingInfo.month = pull.field($form, '.month');
|
|
1534
|
+
billingInfo.year = pull.field($form, '.year');
|
|
1535
|
+
|
|
1536
|
+
billingInfo.phone = pull.field($form, '.phone');
|
|
1537
|
+
billingInfo.address1 = pull.field($form, '.address1', V(R.isNotEmpty));
|
|
1538
|
+
billingInfo.address2 = pull.field($form, '.address2');
|
|
1539
|
+
billingInfo.city = pull.field($form, '.city', V(R.isNotEmpty));
|
|
1540
|
+
billingInfo.state = pull.field($form, '.state', V(R.isNotEmptyState));
|
|
1541
|
+
billingInfo.zip = pull.field($form, '.zip', V(R.isNotEmpty));
|
|
1542
|
+
billingInfo.country = pull.field($form, '.country', V(R.isNotEmpty));
|
|
1543
|
+
}
|
|
1544
|
+
|
|
1545
|
+
|
|
1546
|
+
function pullPlanQuantity($form, plan, options, pull) {
|
|
1547
|
+
var qty = pull.field($form, '.plan .quantity', V(R.isValidQuantity));
|
|
1548
|
+
// An empty quantity field indicates 1
|
|
1549
|
+
plan.quantity = qty || 1;
|
|
1550
|
+
}
|
|
1551
|
+
|
|
1552
|
+
|
|
1553
|
+
function verifyTOSChecked($form, pull) {
|
|
1554
|
+
pull.field($form, '.accept_tos', V(R.isChecked));
|
|
1555
|
+
}
|
|
1556
|
+
|
|
1557
|
+
|
|
1558
|
+
R.buildBillingInfoUpdateForm = function(options) {
|
|
1559
|
+
var defaults = {
|
|
1560
|
+
addressRequirement: 'full'
|
|
1561
|
+
, distinguishContactFromBillingInfo: true
|
|
1562
|
+
};
|
|
1563
|
+
|
|
1564
|
+
options = $.extend(createObject(R.settings), defaults, options);
|
|
1565
|
+
|
|
1566
|
+
if(!options.accountCode) R.raiseError('accountCode missing');
|
|
1567
|
+
if(!options.signature) R.raiseError('signature missing');
|
|
1568
|
+
|
|
1569
|
+
var billingInfo = R.BillingInfo.create();
|
|
1570
|
+
|
|
1571
|
+
var $form = $(R.dom.update_billing_info_form);
|
|
1572
|
+
$form.find('.billing_info').html(R.dom.billing_info_fields);
|
|
1573
|
+
|
|
1574
|
+
|
|
1575
|
+
initCommonForm($form, options);
|
|
1576
|
+
initBillingInfoForm($form, options);
|
|
1577
|
+
|
|
1578
|
+
|
|
1579
|
+
$form.submit(function(e) {
|
|
1580
|
+
e.preventDefault();
|
|
1581
|
+
|
|
1582
|
+
clearServerErrors($form);
|
|
1583
|
+
|
|
1584
|
+
$form.find('.error').remove();
|
|
1585
|
+
$form.find('.invalid').removeClass('invalid');
|
|
1586
|
+
|
|
1587
|
+
validationGroup(function(puller) {
|
|
1588
|
+
pullBillingInfoFields($form, billingInfo, options, puller);
|
|
1589
|
+
}
|
|
1590
|
+
, function() {
|
|
1591
|
+
$form.addClass('submitting');
|
|
1592
|
+
$form.find('button.submit').attr('disabled', true).text('Please Wait');
|
|
1593
|
+
|
|
1594
|
+
billingInfo.save({
|
|
1595
|
+
signature: options.signature
|
|
1596
|
+
, distinguishContactFromBillingInfo: options.distinguishContactFromBillingInfo
|
|
1597
|
+
, accountCode: options.accountCode
|
|
1598
|
+
, success: function(response) {
|
|
1599
|
+
if(options.successHandler) {
|
|
1600
|
+
options.successHandler(R.getToken(response));
|
|
1601
|
+
}
|
|
1602
|
+
|
|
1603
|
+
if(options.successURL) {
|
|
1604
|
+
var url = options.successURL;
|
|
1605
|
+
R.postResult(url, response, options);
|
|
1606
|
+
}
|
|
1607
|
+
}
|
|
1608
|
+
, error: function(errors) {
|
|
1609
|
+
if(!options.onError || !options.onError(errors)) {
|
|
1610
|
+
displayServerErrors($form, errors);
|
|
1611
|
+
}
|
|
1612
|
+
}
|
|
1613
|
+
, complete: function() {
|
|
1614
|
+
$form.removeClass('submitting');
|
|
1615
|
+
$form.find('button.submit').removeAttr('disabled').text('Update');
|
|
1616
|
+
}
|
|
1617
|
+
});
|
|
1618
|
+
});
|
|
1619
|
+
});
|
|
1620
|
+
|
|
1621
|
+
if(options.beforeInject) {
|
|
1622
|
+
options.beforeInject($form.get(0));
|
|
1623
|
+
}
|
|
1624
|
+
|
|
1625
|
+
$(function() {
|
|
1626
|
+
var $container = $(options.target);
|
|
1627
|
+
$container.html($form);
|
|
1628
|
+
|
|
1629
|
+
if(options.afterInject) {
|
|
1630
|
+
options.afterInject($form.get(0));
|
|
1631
|
+
}
|
|
1632
|
+
});
|
|
1633
|
+
|
|
1634
|
+
};
|
|
1635
|
+
|
|
1636
|
+
|
|
1637
|
+
function initTOSCheck($form, options) {
|
|
1638
|
+
|
|
1639
|
+
if(options.termsOfServiceURL || options.privacyPolicyURL) {
|
|
1640
|
+
var $tos = $form.find('.accept_tos').html(R.dom.terms_of_service);
|
|
1641
|
+
|
|
1642
|
+
// If only one, remove 'and'
|
|
1643
|
+
if(!(options.termsOfServiceURL && options.privacyPolicyURL)) {
|
|
1644
|
+
$tos.find('span.and').remove();
|
|
1645
|
+
}
|
|
1646
|
+
|
|
1647
|
+
// set href or remove tos_link
|
|
1648
|
+
if(options.termsOfServiceURL) {
|
|
1649
|
+
$tos.find('a.tos_link').attr('href', options.termsOfServiceURL);
|
|
1650
|
+
}
|
|
1651
|
+
else {
|
|
1652
|
+
$tos.find('a.tos_link').remove();
|
|
1653
|
+
}
|
|
1654
|
+
|
|
1655
|
+
// set href or remove pp_link
|
|
1656
|
+
if(options.privacyPolicyURL) {
|
|
1657
|
+
$tos.find('a.pp_link').attr('href', options.privacyPolicyURL);
|
|
1658
|
+
}
|
|
1659
|
+
else {
|
|
1660
|
+
$tos.find('a.pp_link').remove();
|
|
1661
|
+
}
|
|
1662
|
+
|
|
1663
|
+
}
|
|
1664
|
+
else {
|
|
1665
|
+
$form.find('.accept_tos').remove();
|
|
1666
|
+
}
|
|
1667
|
+
|
|
1668
|
+
}
|
|
1669
|
+
|
|
1670
|
+
R.buildTransactionForm = function(options) {
|
|
1671
|
+
var defaults = {
|
|
1672
|
+
addressRequirement: 'full'
|
|
1673
|
+
, distinguishContactFromBillingInfo: true
|
|
1674
|
+
, collectContactInfo: true
|
|
1675
|
+
};
|
|
1676
|
+
|
|
1677
|
+
options = $.extend(createObject(R.settings), defaults, options);
|
|
1678
|
+
|
|
1679
|
+
|
|
1680
|
+
if(!options.collectContactInfo && !options.accountCode) {
|
|
1681
|
+
R.raiseError('collectContactInfo is false, but no accountCode provided');
|
|
1682
|
+
}
|
|
1683
|
+
|
|
1684
|
+
if(!options.signature) R.raiseError('signature missing');
|
|
1685
|
+
|
|
1686
|
+
|
|
1687
|
+
var billingInfo = R.BillingInfo.create()
|
|
1688
|
+
, account = R.Account.create()
|
|
1689
|
+
, transaction = R.Transaction.create();
|
|
1690
|
+
|
|
1691
|
+
|
|
1692
|
+
transaction.account = account;
|
|
1693
|
+
transaction.billingInfo = billingInfo;
|
|
1694
|
+
transaction.currency = options.currency;
|
|
1695
|
+
transaction.cost = new R.Cost(options.amountInCents);
|
|
1696
|
+
|
|
1697
|
+
var $form = $(R.dom.one_time_transaction_form);
|
|
1698
|
+
$form.find('.billing_info').html(R.dom.billing_info_fields);
|
|
1699
|
+
|
|
1700
|
+
if(options.collectContactInfo) {
|
|
1701
|
+
$form.find('.contact_info').html(R.dom.contact_info_fields);
|
|
1702
|
+
}
|
|
1703
|
+
else {
|
|
1704
|
+
$form.find('.contact_info').remove();
|
|
1705
|
+
}
|
|
1706
|
+
|
|
1707
|
+
|
|
1708
|
+
initCommonForm($form, options);
|
|
1709
|
+
initContactInfoForm($form, options);
|
|
1710
|
+
initBillingInfoForm($form, options);
|
|
1711
|
+
initTOSCheck($form, options);
|
|
1712
|
+
|
|
1713
|
+
$form.submit(function(e) {
|
|
1714
|
+
e.preventDefault();
|
|
1715
|
+
|
|
1716
|
+
clearServerErrors($form);
|
|
1717
|
+
|
|
1718
|
+
$form.find('.error').remove();
|
|
1719
|
+
$form.find('.invalid').removeClass('invalid');
|
|
1720
|
+
|
|
1721
|
+
validationGroup(function(puller) {
|
|
1722
|
+
pullAccountFields($form, account, options, puller);
|
|
1723
|
+
pullBillingInfoFields($form, billingInfo, options, puller);
|
|
1724
|
+
verifyTOSChecked($form, puller);
|
|
1725
|
+
}
|
|
1726
|
+
, function() {
|
|
1727
|
+
$form.addClass('submitting');
|
|
1728
|
+
$form.find('button.submit').attr('disabled', true).text('Please Wait');
|
|
1729
|
+
|
|
1730
|
+
transaction.save({
|
|
1731
|
+
signature: options.signature
|
|
1732
|
+
, accountCode: options.accountCode
|
|
1733
|
+
, success: function(response) {
|
|
1734
|
+
if(options.successHandler) {
|
|
1735
|
+
options.successHandler(R.getToken(response));
|
|
1736
|
+
}
|
|
1737
|
+
|
|
1738
|
+
if(options.successURL) {
|
|
1739
|
+
var url = options.successURL;
|
|
1740
|
+
R.postResult(url, response, options);
|
|
1741
|
+
}
|
|
1742
|
+
}
|
|
1743
|
+
, error: function(errors) {
|
|
1744
|
+
if(!options.onError || !options.onError(errors)) {
|
|
1745
|
+
displayServerErrors($form, errors);
|
|
1746
|
+
}
|
|
1747
|
+
}
|
|
1748
|
+
, complete: function() {
|
|
1749
|
+
$form.removeClass('submitting');
|
|
1750
|
+
$form.find('button.submit').removeAttr('disabled').text('Pay');
|
|
1751
|
+
}
|
|
1752
|
+
});
|
|
1753
|
+
});
|
|
1754
|
+
});
|
|
1755
|
+
|
|
1756
|
+
if(options.beforeInject) {
|
|
1757
|
+
options.beforeInject($form.get(0));
|
|
1758
|
+
}
|
|
1759
|
+
|
|
1760
|
+
$(function() {
|
|
1761
|
+
var $container = $(options.target);
|
|
1762
|
+
$container.html($form);
|
|
1763
|
+
|
|
1764
|
+
if(options.afterInject) {
|
|
1765
|
+
options.afterInject($form.get(0));
|
|
1766
|
+
}
|
|
1767
|
+
});
|
|
1768
|
+
|
|
1769
|
+
};
|
|
1770
|
+
|
|
1771
|
+
|
|
1772
|
+
R.buildSubscriptionForm = function(options) {
|
|
1773
|
+
var defaults = {
|
|
1774
|
+
enableAddOns: true
|
|
1775
|
+
, enableCoupons: true
|
|
1776
|
+
, addressRequirement: 'full'
|
|
1777
|
+
, distinguishContactFromBillingInfo: false
|
|
1778
|
+
};
|
|
1779
|
+
|
|
1780
|
+
options = $.extend(createObject(R.settings), defaults, options);
|
|
1781
|
+
|
|
1782
|
+
if(!options.signature) R.raiseError('signature missing');
|
|
1783
|
+
|
|
1784
|
+
var $form = $(R.dom.subscribe_form);
|
|
1785
|
+
$form.find('.contact_info').html(R.dom.contact_info_fields);
|
|
1786
|
+
$form.find('.billing_info').html(R.dom.billing_info_fields);
|
|
1787
|
+
|
|
1788
|
+
|
|
1789
|
+
if(options.planCode)
|
|
1790
|
+
R.Plan.get(options.planCode, options.currency, gotPlan);
|
|
1791
|
+
else if(options.plan) {
|
|
1792
|
+
// this should never be called
|
|
1793
|
+
// the api does not have it, nor does anywhere else in the program refer to it
|
|
1794
|
+
gotPlan(options.plan);
|
|
1795
|
+
}
|
|
1796
|
+
|
|
1797
|
+
initCommonForm($form, options);
|
|
1798
|
+
initContactInfoForm($form, options);
|
|
1799
|
+
initBillingInfoForm($form, options);
|
|
1800
|
+
initTOSCheck($form, options);
|
|
1801
|
+
|
|
1802
|
+
function gotPlan(plan) {
|
|
1803
|
+
|
|
1804
|
+
if(options.filterPlan)
|
|
1805
|
+
plan = options.filterPlan(plan) || plan;
|
|
1806
|
+
|
|
1807
|
+
|
|
1808
|
+
var subscription = plan.createSubscription(),
|
|
1809
|
+
account = R.Account.create(),
|
|
1810
|
+
billingInfo = R.BillingInfo.create();
|
|
1811
|
+
|
|
1812
|
+
subscription.account = account;
|
|
1813
|
+
subscription.billingInfo = billingInfo;
|
|
1814
|
+
|
|
1815
|
+
if(options.filterSubscription)
|
|
1816
|
+
subscription = options.filterSubscription(subscription) || subscription;
|
|
1817
|
+
|
|
1818
|
+
// == EDITABLE PLAN QUANTITY
|
|
1819
|
+
if(!plan.displayQuantity) {
|
|
1820
|
+
$form.find('.plan .quantity').remove();
|
|
1821
|
+
}
|
|
1822
|
+
|
|
1823
|
+
// == SETUP FEE
|
|
1824
|
+
if(plan.setupFee) {
|
|
1825
|
+
$form.find('.subscription').addClass('with_setup_fee');
|
|
1826
|
+
$form.find('.plan .setup_fee .cost').text('' + plan.setupFee);
|
|
1827
|
+
}
|
|
1828
|
+
else {
|
|
1829
|
+
$form.find('.plan .setup_fee').remove();
|
|
1830
|
+
}
|
|
1831
|
+
|
|
1832
|
+
// == FREE TRIAL
|
|
1833
|
+
if(plan.trial) {
|
|
1834
|
+
$form.find('.subscription').addClass('with_trial');
|
|
1835
|
+
|
|
1836
|
+
$form.find('.plan .free_trial').text('First ' + plan.trial + ' free');
|
|
1837
|
+
}
|
|
1838
|
+
else {
|
|
1839
|
+
$form.find('.plan .free_trial').remove();
|
|
1840
|
+
}
|
|
1841
|
+
|
|
1842
|
+
|
|
1843
|
+
// == UPDATE ALL UI TOTALS via subscription.calculateTotals() results
|
|
1844
|
+
function updateTotals() {
|
|
1845
|
+
var totals = subscription.calculateTotals();
|
|
1846
|
+
|
|
1847
|
+
$form.find('.plan .recurring_cost .cost').text('' + totals.plan);
|
|
1848
|
+
$form.find('.due_now .cost').text('' + totals.stages.now);
|
|
1849
|
+
$form.find('.coupon .discount').text('' + (totals.coupon || ''));
|
|
1850
|
+
$form.find('.vat .cost').text('' + (totals.vat || ''));
|
|
1851
|
+
|
|
1852
|
+
$form.find('.add_ons .add_on').each(function() {
|
|
1853
|
+
var addOn = $(this).data('add_on');
|
|
1854
|
+
if($(this).hasClass('selected')) {
|
|
1855
|
+
var cost = totals.addOns[addOn.code];
|
|
1856
|
+
$(this).find('.cost').text('+ '+cost);
|
|
1857
|
+
}
|
|
1858
|
+
else {
|
|
1859
|
+
$(this).find('.cost').text('+ '+addOn.cost);
|
|
1860
|
+
}
|
|
1861
|
+
});
|
|
1862
|
+
}
|
|
1863
|
+
|
|
1864
|
+
$form.find('.plan .quantity input').bind('change keyup', function() {
|
|
1865
|
+
subscription.plan.quantity = parseInt($(this).val(), 10) || 1;
|
|
1866
|
+
updateTotals();
|
|
1867
|
+
});
|
|
1868
|
+
|
|
1869
|
+
// == SUBSCRIPTION PLAN GENERAL
|
|
1870
|
+
$form.find('.plan .name').text(plan.name);
|
|
1871
|
+
$form.find('.plan .recurring_cost .cost').text(''+plan.cost);
|
|
1872
|
+
$form.find('.plan .recurring_cost .interval').text('every '+plan.interval);
|
|
1873
|
+
|
|
1874
|
+
|
|
1875
|
+
// == GENERATE ADD-ONS
|
|
1876
|
+
var $addOnsList = $form.find('.add_ons');
|
|
1877
|
+
if(options.enableAddOns) {
|
|
1878
|
+
var l = plan.addOns.length;
|
|
1879
|
+
if(l) {
|
|
1880
|
+
$addOnsList.removeClass('none').addClass('any');
|
|
1881
|
+
for(var i=0; i < l; ++i) {
|
|
1882
|
+
var addOn = plan.addOns[i];
|
|
1883
|
+
|
|
1884
|
+
var classAttr = 'add_on add_on_'+ addOn.code + (i % 2 ? ' even' : ' odd');
|
|
1885
|
+
if(i == 0) classAttr += ' first';
|
|
1886
|
+
if(i == l-1) classAttr += ' last';
|
|
1887
|
+
|
|
1888
|
+
var $addOn = $('<div class="'+classAttr+'">' +
|
|
1889
|
+
'<div class="name">'+addOn.name+'</div>' +
|
|
1890
|
+
'<div class="field quantity">' +
|
|
1891
|
+
'<div class="placeholder">Qty</div>' +
|
|
1892
|
+
'<input type="text">' +
|
|
1893
|
+
'</div>' +
|
|
1894
|
+
'<div class="cost"/>' +
|
|
1895
|
+
'</div>');
|
|
1896
|
+
if(!addOn.displayQuantity) {
|
|
1897
|
+
$addOn.find('.quantity').remove();
|
|
1898
|
+
}
|
|
1899
|
+
$addOn.data('add_on', addOn);
|
|
1900
|
+
$addOn.appendTo($addOnsList);
|
|
1901
|
+
}
|
|
1902
|
+
|
|
1903
|
+
// Quantity Change
|
|
1904
|
+
$addOnsList.delegate('.add_ons .quantity input', 'change keyup', function(e) {
|
|
1905
|
+
var $addOn = $(this).closest('.add_on');
|
|
1906
|
+
var addOn = $addOn.data('add_on');
|
|
1907
|
+
var newQty = parseInt($(this).val(),10) || 1;
|
|
1908
|
+
subscription.findAddOnByCode(addOn.code).quantity = newQty;
|
|
1909
|
+
updateTotals();
|
|
1910
|
+
});
|
|
1911
|
+
|
|
1912
|
+
$addOnsList.bind('selectstart', function(e) {
|
|
1913
|
+
if($(e.target).is('.add_on')) {
|
|
1914
|
+
e.preventDefault();
|
|
1915
|
+
}
|
|
1916
|
+
});
|
|
1917
|
+
|
|
1918
|
+
// Add-on click
|
|
1919
|
+
$addOnsList.delegate('.add_ons .add_on', 'click', function(e) {
|
|
1920
|
+
if($(e.target).closest('.quantity').length) return;
|
|
1921
|
+
|
|
1922
|
+
var selected = !$(this).hasClass('selected');
|
|
1923
|
+
$(this).toggleClass('selected', selected);
|
|
1924
|
+
|
|
1925
|
+
var addOn = $(this).data('add_on');
|
|
1926
|
+
|
|
1927
|
+
if(selected) {
|
|
1928
|
+
// add
|
|
1929
|
+
var sa = subscription.redeemAddOn(addOn);
|
|
1930
|
+
var $qty = $(this).find('.quantity input');
|
|
1931
|
+
sa.quantity = parseInt($qty.val(),10) || 1;
|
|
1932
|
+
$qty.focus();
|
|
1933
|
+
}
|
|
1934
|
+
else {
|
|
1935
|
+
// remove
|
|
1936
|
+
subscription.removeAddOn(addOn.code);
|
|
1937
|
+
}
|
|
1938
|
+
|
|
1939
|
+
updateTotals();
|
|
1940
|
+
});
|
|
1941
|
+
}
|
|
1942
|
+
}
|
|
1943
|
+
else {
|
|
1944
|
+
$addOnsList.remove();
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
// == COUPON REDEEMER
|
|
1948
|
+
var $coupon = $form.find('.coupon');
|
|
1949
|
+
var lastCode = null;
|
|
1950
|
+
|
|
1951
|
+
function updateCoupon() {
|
|
1952
|
+
|
|
1953
|
+
var code = $coupon.find('input').val();
|
|
1954
|
+
if(code == lastCode) {
|
|
1955
|
+
return;
|
|
1956
|
+
}
|
|
1957
|
+
|
|
1958
|
+
lastCode = code;
|
|
1959
|
+
|
|
1960
|
+
if(!code) {
|
|
1961
|
+
$coupon.removeClass('invalid').removeClass('valid');
|
|
1962
|
+
$coupon.find('.description').text('');
|
|
1963
|
+
subscription.coupon = undefined;
|
|
1964
|
+
updateTotals();
|
|
1965
|
+
return;
|
|
1966
|
+
}
|
|
1967
|
+
|
|
1968
|
+
$coupon.addClass('checking');
|
|
1969
|
+
subscription.getCoupon(code, function(coupon) {
|
|
1970
|
+
|
|
1971
|
+
$coupon.removeClass('checking');
|
|
1972
|
+
|
|
1973
|
+
subscription.coupon = coupon;
|
|
1974
|
+
$coupon.removeClass('invalid').addClass('valid');
|
|
1975
|
+
$coupon.find('.description').text(coupon.description);
|
|
1976
|
+
|
|
1977
|
+
updateTotals();
|
|
1978
|
+
}, function() {
|
|
1979
|
+
|
|
1980
|
+
subscription.coupon = undefined;
|
|
1981
|
+
|
|
1982
|
+
$coupon.removeClass('checking');
|
|
1983
|
+
$coupon.removeClass('valid').addClass('invalid');
|
|
1984
|
+
$coupon.find('.description').text('Not Found');
|
|
1985
|
+
|
|
1986
|
+
updateTotals();
|
|
1987
|
+
});
|
|
1988
|
+
}
|
|
1989
|
+
|
|
1990
|
+
if(options.enableCoupons) {
|
|
1991
|
+
$coupon.find('input').bind('keyup change', function(e) {
|
|
1992
|
+
});
|
|
1993
|
+
|
|
1994
|
+
$coupon.find('input').keypress(function(e) {
|
|
1995
|
+
if(e.charCode == 13) {
|
|
1996
|
+
e.preventDefault();
|
|
1997
|
+
updateCoupon();
|
|
1998
|
+
}
|
|
1999
|
+
});
|
|
2000
|
+
|
|
2001
|
+
|
|
2002
|
+
$coupon.find('.check').click(function() {
|
|
2003
|
+
updateCoupon();
|
|
2004
|
+
});
|
|
2005
|
+
|
|
2006
|
+
$coupon.find('input').blur(function() { $coupon.find('.check').click(); });
|
|
2007
|
+
}
|
|
2008
|
+
else {
|
|
2009
|
+
$coupon.remove();
|
|
2010
|
+
}
|
|
2011
|
+
|
|
2012
|
+
|
|
2013
|
+
// == VAT
|
|
2014
|
+
var $vat = $form.find('.vat');
|
|
2015
|
+
var $vatNumber = $form.find('.vat_number');
|
|
2016
|
+
var $vatNumberInput = $vatNumber.find('input');
|
|
2017
|
+
|
|
2018
|
+
$vat.find('.title').text('VAT at ' + R.settings.VATPercent + '%');
|
|
2019
|
+
function showHideVAT() {
|
|
2020
|
+
var buyerCountry = $form.find('.country select').val();
|
|
2021
|
+
var vatNumberApplicable = R.isVATNumberApplicable(buyerCountry);
|
|
2022
|
+
|
|
2023
|
+
// VAT Number is applicable to collection in any EU country
|
|
2024
|
+
$vatNumber.toggleClass('applicable', vatNumberApplicable);
|
|
2025
|
+
$vatNumber.toggleClass('inapplicable', !vatNumberApplicable);
|
|
2026
|
+
|
|
2027
|
+
var vatNumber = $vatNumberInput.val();
|
|
2028
|
+
|
|
2029
|
+
// Only applicable to charge if isVATApplicable()
|
|
2030
|
+
var chargeApplicable = R.isVATChargeApplicable(buyerCountry, vatNumber);
|
|
2031
|
+
$vat.toggleClass('applicable', chargeApplicable);
|
|
2032
|
+
$vat.toggleClass('inapplicable', !chargeApplicable);
|
|
2033
|
+
}
|
|
2034
|
+
// showHideVAT();
|
|
2035
|
+
$form.find('.country select').change(function() {
|
|
2036
|
+
billingInfo.country = $(this).val();
|
|
2037
|
+
updateTotals();
|
|
2038
|
+
showHideVAT();
|
|
2039
|
+
}).change();
|
|
2040
|
+
$vatNumberInput.bind('keyup change', function() {
|
|
2041
|
+
billingInfo.vatNumber = $(this).val();
|
|
2042
|
+
updateTotals();
|
|
2043
|
+
showHideVAT();
|
|
2044
|
+
});
|
|
2045
|
+
|
|
2046
|
+
// SUBMIT HANDLER
|
|
2047
|
+
$form.submit(function(e) {
|
|
2048
|
+
e.preventDefault();
|
|
2049
|
+
|
|
2050
|
+
clearServerErrors($form);
|
|
2051
|
+
|
|
2052
|
+
|
|
2053
|
+
$form.find('.error').remove();
|
|
2054
|
+
$form.find('.invalid').removeClass('invalid');
|
|
2055
|
+
|
|
2056
|
+
validationGroup(function(puller) {
|
|
2057
|
+
pullPlanQuantity($form, subscription.plan, options, puller);
|
|
2058
|
+
pullAccountFields($form, account, options, puller);
|
|
2059
|
+
pullBillingInfoFields($form, billingInfo, options, puller);
|
|
2060
|
+
verifyTOSChecked($form, puller);
|
|
2061
|
+
}, function() {
|
|
2062
|
+
|
|
2063
|
+
$form.addClass('submitting');
|
|
2064
|
+
$form.find('button.submit').attr('disabled', true).text('Please Wait');
|
|
2065
|
+
|
|
2066
|
+
subscription.save({
|
|
2067
|
+
|
|
2068
|
+
signature: options.signature
|
|
2069
|
+
, success: function(response) {
|
|
2070
|
+
if(options.successHandler) {
|
|
2071
|
+
options.successHandler(R.getToken(response));
|
|
2072
|
+
}
|
|
2073
|
+
if(options.successURL) {
|
|
2074
|
+
var url = options.successURL;
|
|
2075
|
+
R.postResult(url, response, options);
|
|
2076
|
+
}
|
|
2077
|
+
}
|
|
2078
|
+
, error: function(errors) {
|
|
2079
|
+
if(!options.onError || !options.onError(errors)) {
|
|
2080
|
+
displayServerErrors($form, errors);
|
|
2081
|
+
}
|
|
2082
|
+
}
|
|
2083
|
+
, complete: function() {
|
|
2084
|
+
$form.removeClass('submitting');
|
|
2085
|
+
$form.find('button.submit').removeAttr('disabled').text('Subscribe');
|
|
2086
|
+
}
|
|
2087
|
+
});
|
|
2088
|
+
});
|
|
2089
|
+
|
|
2090
|
+
});
|
|
2091
|
+
|
|
2092
|
+
// FINALLY - UPDATE INITIAL TOTALS AND INJECT INTO DOM
|
|
2093
|
+
updateTotals();
|
|
2094
|
+
|
|
2095
|
+
if(options.beforeInject) {
|
|
2096
|
+
options.beforeInject($form.get(0));
|
|
2097
|
+
}
|
|
2098
|
+
|
|
2099
|
+
$(function() {
|
|
2100
|
+
var $container = $(options.target);
|
|
2101
|
+
$container.html($form);
|
|
2102
|
+
|
|
2103
|
+
if(options.afterInject) {
|
|
2104
|
+
options.afterInject($form.get(0));
|
|
2105
|
+
}
|
|
2106
|
+
});
|
|
2107
|
+
|
|
2108
|
+
}
|
|
2109
|
+
|
|
2110
|
+
};
|
|
2111
|
+
|
|
2112
|
+
|
|
2113
|
+
|
|
2114
|
+
//////////////////////////////////////////////////
|
|
2115
|
+
// Compiled from src/js/states.js
|
|
2116
|
+
//////////////////////////////////////////////////
|
|
2117
|
+
|
|
2118
|
+
R.states = {};
|
|
2119
|
+
R.states.US = {
|
|
2120
|
+
"-": "Select State"
|
|
2121
|
+
, "--": "------------"
|
|
2122
|
+
, "AK": "Alaska"
|
|
2123
|
+
, "AL": "Alabama"
|
|
2124
|
+
, "AP": "Armed Forces Pacific"
|
|
2125
|
+
, "AR": "Arkansas"
|
|
2126
|
+
, "AS": "American Samoa"
|
|
2127
|
+
, "AZ": "Arizona"
|
|
2128
|
+
, "CA": "California"
|
|
2129
|
+
, "CO": "Colorado"
|
|
2130
|
+
, "CT": "Connecticut"
|
|
2131
|
+
, "DC": "District of Columbia"
|
|
2132
|
+
, "DE": "Delaware"
|
|
2133
|
+
, "FL": "Florida"
|
|
2134
|
+
, "FM": "Federated States of Micronesia"
|
|
2135
|
+
, "GA": "Georgia"
|
|
2136
|
+
, "GU": "Guam"
|
|
2137
|
+
, "HI": "Hawaii"
|
|
2138
|
+
, "IA": "Iowa"
|
|
2139
|
+
, "ID": "Idaho"
|
|
2140
|
+
, "IL": "Illinois"
|
|
2141
|
+
, "IN": "Indiana"
|
|
2142
|
+
, "KS": "Kansas"
|
|
2143
|
+
, "KY": "Kentucky"
|
|
2144
|
+
, "LA": "Louisiana"
|
|
2145
|
+
, "MA": "Massachusetts"
|
|
2146
|
+
, "MD": "Maryland"
|
|
2147
|
+
, "ME": "Maine"
|
|
2148
|
+
, "MH": "Marshall Islands"
|
|
2149
|
+
, "MI": "Michigan"
|
|
2150
|
+
, "MN": "Minnesota"
|
|
2151
|
+
, "MO": "Missouri"
|
|
2152
|
+
, "MP": "Northern Mariana Islands"
|
|
2153
|
+
, "MS": "Mississippi"
|
|
2154
|
+
, "MT": "Montana"
|
|
2155
|
+
, "NC": "North Carolina"
|
|
2156
|
+
, "ND": "North Dakota"
|
|
2157
|
+
, "NE": "Nebraska"
|
|
2158
|
+
, "NH": "New Hampshire"
|
|
2159
|
+
, "NJ": "New Jersey"
|
|
2160
|
+
, "NM": "New Mexico"
|
|
2161
|
+
, "NV": "Nevada"
|
|
2162
|
+
, "NY": "New York"
|
|
2163
|
+
, "OH": "Ohio"
|
|
2164
|
+
, "OK": "Oklahoma"
|
|
2165
|
+
, "OR": "Oregon"
|
|
2166
|
+
, "PA": "Pennsylvania"
|
|
2167
|
+
, "PR": "Puerto Rico"
|
|
2168
|
+
, "PW": "Palau"
|
|
2169
|
+
, "RI": "Rhode Island"
|
|
2170
|
+
, "SC": "South Carolina"
|
|
2171
|
+
, "SD": "South Dakota"
|
|
2172
|
+
, "TN": "Tennessee"
|
|
2173
|
+
, "TX": "Texas"
|
|
2174
|
+
, "UT": "Utah"
|
|
2175
|
+
, "VA": "Virginia"
|
|
2176
|
+
, "VI": "Virgin Islands"
|
|
2177
|
+
, "VT": "Vermont"
|
|
2178
|
+
, "WA": "Washington"
|
|
2179
|
+
, "WV": "West Virginia"
|
|
2180
|
+
, "WI": "Wisconsin"
|
|
2181
|
+
, "WY": "Wyoming"
|
|
2182
|
+
};
|
|
2183
|
+
|
|
2184
|
+
R.states.CA = {
|
|
2185
|
+
"-": "Select State"
|
|
2186
|
+
, "--": "------------"
|
|
2187
|
+
, "AB": "Alberta"
|
|
2188
|
+
, "BC": "British Columbia"
|
|
2189
|
+
, "MB": "Manitoba"
|
|
2190
|
+
, "NB": "New Brunswick"
|
|
2191
|
+
, "NL": "Newfoundland"
|
|
2192
|
+
, "NS": "Nova Scotia"
|
|
2193
|
+
, "NU": "Nunavut"
|
|
2194
|
+
, "ON": "Ontario"
|
|
2195
|
+
, "PE": "Prince Edward Island"
|
|
2196
|
+
, "QC": "Quebec"
|
|
2197
|
+
, "SK": "Saskatchewan"
|
|
2198
|
+
, "NT": "Northwest Territories"
|
|
2199
|
+
, "YT": "Yukon Territory"
|
|
2200
|
+
, "AA": "Armed Forces Americas"
|
|
2201
|
+
, "AE": "Armed Forces Europe, Middle East, & Canada"
|
|
2202
|
+
};
|
|
2203
|
+
|
|
2204
|
+
|
|
2205
|
+
|
|
2206
|
+
|
|
2207
|
+
//////////////////////////////////////////////////
|
|
2208
|
+
// Compiled from src/dom/contact_info_fields.jade
|
|
2209
|
+
//////////////////////////////////////////////////
|
|
2210
|
+
|
|
2211
|
+
R.dom['contact_info_fields'] = '<div class="title">Contact Info</div><div class="full_name"><div class="field first_name"><div class="placeholder">First Name </div><input type="text"/></div><div class="field last_name"><div class="placeholder">Last Name </div><input type="text"/></div></div><div class="field email"><div class="placeholder">Email </div><input type="text"/></div><div class="field phone"><div class="placeholder">Phone Number</div><input type="text"/></div><div class="field company_name"><div class="placeholder">Company/Organization Name</div><input type="text"/></div>';
|
|
2212
|
+
|
|
2213
|
+
//////////////////////////////////////////////////
|
|
2214
|
+
// Compiled from src/dom/billing_info_fields.jade
|
|
2215
|
+
//////////////////////////////////////////////////
|
|
2216
|
+
|
|
2217
|
+
R.dom['billing_info_fields'] = '<div class="title">Billing Info</div><div class="accepted_cards"></div><div class="credit_card"><div class="field first_name"><div class="placeholder">First Name </div><input type="text"/></div><div class="field last_name"><div class="placeholder">Last Name </div><input type="text"/></div><div class="card_cvv"><div class="field card_number"><div class="placeholder">Credit Card Number </div><input type="text"/></div><div class="field cvv"><div class="placeholder">CVV </div><input type="text"/></div></div><div class="field expires"><div class="title">Expires </div><div class="month"><select><option value="1">01 - January</option><option value="2">02 - February</option><option value="3">03 - March</option><option value="4">04 - April</option><option value="5">05 - May</option><option value="6">06 - June</option><option value="7">07 - July</option><option value="8">08 - August</option><option value="9">09 - September</option><option value="10">10 - October</option><option value="11">11 - November</option><option value="12">12 - December</option></select></div><div class="year"><select></select></div></div></div><div class="address"><div class="field address1"><div class="placeholder">Address</div><input type="text"/></div><div class="field address2"><div class="placeholder">Apt/Suite</div><input type="text"/></div><div class="field city"><div class="placeholder">City</div><input type="text"/></div><div class="state_zip"><div class="field state"><div class="placeholder">State/Province</div><input type="text"/></div><div class="field zip"><div class="placeholder">Zip/Postal</div><input type="text"/></div></div><div class="field country"><select><option value="-">Select Country</option><option value="-">--------------</option><option value="AF">Afghanistan</option><option value="AL">Albania</option><option value="DZ">Algeria</option><option value="AS">American Samoa</option><option value="AD">Andorra</option><option value="AO">Angola</option><option value="AI">Anguilla</option><option value="AQ">Antarctica</option><option value="AG">Antigua and Barbuda</option><option value="AR">Argentina</option><option value="AM">Armenia</option><option value="AW">Aruba</option><option value="AC">Ascension Island</option><option value="AU">Australia</option><option value="AT">Austria</option><option value="AZ">Azerbaijan</option><option value="BS">Bahamas</option><option value="BH">Bahrain</option><option value="BD">Bangladesh</option><option value="BB">Barbados</option><option value="BE">Belgium</option><option value="BZ">Belize</option><option value="BJ">Benin</option><option value="BM">Bermuda</option><option value="BT">Bhutan</option><option value="BO">Bolivia</option><option value="BA">Bosnia and Herzegovina</option><option value="BW">Botswana</option><option value="BV">Bouvet Island</option><option value="BR">Brazil</option><option value="BQ">British Antarctic Territory</option><option value="IO">British Indian Ocean Territory</option><option value="VG">British Virgin Islands</option><option value="BN">Brunei</option><option value="BG">Bulgaria</option><option value="BF">Burkina Faso</option><option value="BI">Burundi</option><option value="KH">Cambodia</option><option value="CM">Cameroon</option><option value="CA">Canada</option><option value="IC">Canary Islands</option><option value="CT">Canton and Enderbury Islands</option><option value="CV">Cape Verde</option><option value="KY">Cayman Islands</option><option value="CF">Central African Republic</option><option value="EA">Ceuta and Melilla</option><option value="TD">Chad</option><option value="CL">Chile</option><option value="CN">China</option><option value="CX">Christmas Island</option><option value="CP">Clipperton Island</option><option value="CC">Cocos [Keeling] Islands</option><option value="CO">Colombia</option><option value="KM">Comoros</option><option value="CD">Congo [DRC]</option><option value="CK">Cook Islands</option><option value="CR">Costa Rica</option><option value="HR">Croatia</option><option value="CU">Cuba</option><option value="CY">Cyprus</option><option value="CZ">Czech Republic</option><option value="DK">Denmark</option><option value="DG">Diego Garcia</option><option value="DJ">Djibouti</option><option value="DM">Dominica</option><option value="DO">Dominican Republic</option><option value="NQ">Dronning Maud Land</option><option value="DD">East Germany</option><option value="TL">East Timor</option><option value="EC">Ecuador</option><option value="EG">Egypt</option><option value="SV">El Salvador</option><option value="EE">Estonia</option><option value="ET">Ethiopia</option><option value="EU">European Union</option><option value="FK">Falkland Islands [Islas Malvinas]</option><option value="FO">Faroe Islands</option><option value="FJ">Fiji</option><option value="FI">Finland</option><option value="FR">France</option><option value="GF">French Guiana</option><option value="PF">French Polynesia</option><option value="TF">French Southern Territories</option><option value="FQ">French Southern and Antarctic Territories</option><option value="GA">Gabon</option><option value="GM">Gambia</option><option value="GE">Georgia</option><option value="DE">Germany</option><option value="GH">Ghana</option><option value="GI">Gibraltar</option><option value="GR">Greece</option><option value="GL">Greenland</option><option value="GD">Grenada</option><option value="GP">Guadeloupe</option><option value="GU">Guam</option><option value="GT">Guatemala</option><option value="GG">Guernsey</option><option value="GW">Guinea-Bissau</option><option value="GY">Guyana</option><option value="HT">Haiti</option><option value="HM">Heard Island and McDonald Islands</option><option value="HN">Honduras</option><option value="HK">Hong Kong</option><option value="HU">Hungary</option><option value="IS">Iceland</option><option value="IN">India</option><option value="ID">Indonesia</option><option value="IE">Ireland</option><option value="IM">Isle of Man</option><option value="IL">Israel</option><option value="IT">Italy</option><option value="JM">Jamaica</option><option value="JP">Japan</option><option value="JE">Jersey</option><option value="JT">Johnston Island</option><option value="JO">Jordan</option><option value="KZ">Kazakhstan</option><option value="KE">Kenya</option><option value="KI">Kiribati</option><option value="KW">Kuwait</option><option value="KG">Kyrgyzstan</option><option value="LA">Laos</option><option value="LV">Latvia</option><option value="LS">Lesotho</option><option value="LY">Libya</option><option value="LI">Liechtenstein</option><option value="LT">Lithuania</option><option value="LU">Luxembourg</option><option value="MO">Macau</option><option value="MK">Macedonia [FYROM]</option><option value="MG">Madagascar</option><option value="MW">Malawi</option><option value="MY">Malaysia</option><option value="MV">Maldives</option><option value="ML">Mali</option><option value="MT">Malta</option><option value="MH">Marshall Islands</option><option value="MQ">Martinique</option><option value="MR">Mauritania</option><option value="MU">Mauritius</option><option value="YT">Mayotte</option><option value="FX">Metropolitan France</option><option value="MX">Mexico</option><option value="FM">Micronesia</option><option value="MI">Midway Islands</option><option value="MD">Moldova</option><option value="MC">Monaco</option><option value="MN">Mongolia</option><option value="ME">Montenegro</option><option value="MS">Montserrat</option><option value="MA">Morocco</option><option value="MZ">Mozambique</option><option value="NA">Namibia</option><option value="NR">Nauru</option><option value="NP">Nepal</option><option value="NL">Netherlands</option><option value="AN">Netherlands Antilles</option><option value="NT">Neutral Zone</option><option value="NC">New Caledonia</option><option value="NZ">New Zealand</option><option value="NI">Nicaragua</option><option value="NE">Niger</option><option value="NG">Nigeria</option><option value="NU">Niue</option><option value="NF">Norfolk Island</option><option value="VD">North Vietnam</option><option value="MP">Northern Mariana Islands</option><option value="NO">Norway</option><option value="OM">Oman</option><option value="QO">Outlying Oceania</option><option value="PC">Pacific Islands Trust Territory</option><option value="PK">Pakistan</option><option value="PW">Palau</option><option value="PS">Palestinian Territories</option><option value="PA">Panama</option><option value="PZ">Panama Canal Zone</option><option value="PY">Paraguay</option><option value="YD">People\'s Democratic Republic of Yemen</option><option value="PE">Peru</option><option value="PH">Philippines</option><option value="PN">Pitcairn Islands</option><option value="PL">Poland</option><option value="PT">Portugal</option><option value="PR">Puerto Rico</option><option value="QA">Qatar</option><option value="RO">Romania</option><option value="RU">Russia</option><option value="RW">Rwanda</option><option value="RE">R\u00e9union</option><option value="BL">Saint Barth\u00e9lemy</option><option value="SH">Saint Helena</option><option value="KN">Saint Kitts and Nevis</option><option value="LC">Saint Lucia</option><option value="MF">Saint Martin</option><option value="PM">Saint Pierre and Miquelon</option><option value="VC">Saint Vincent and the Grenadines</option><option value="WS">Samoa</option><option value="SM">San Marino</option><option value="SA">Saudi Arabia</option><option value="SN">Senegal</option><option value="RS">Serbia</option><option value="CS">Serbia and Montenegro</option><option value="SC">Seychelles</option><option value="SL">Sierra Leone</option><option value="SG">Singapore</option><option value="SK">Slovakia</option><option value="SI">Slovenia</option><option value="SB">Solomon Islands</option><option value="ZA">South Africa</option><option value="GS">South Georgia and the South Sandwich Islands</option><option value="KR">South Korea</option><option value="ES">Spain</option><option value="LK">Sri Lanka</option><option value="SR">Suriname</option><option value="SJ">Svalbard and Jan Mayen</option><option value="SZ">Swaziland</option><option value="SE">Sweden</option><option value="CH">Switzerland</option><option value="ST">S\u00e3o Tom\u00e9 and Pr\u00edncipe</option><option value="TW">Taiwan</option><option value="TJ">Tajikistan</option><option value="TZ">Tanzania</option><option value="TH">Thailand</option><option value="TG">Togo</option><option value="TK">Tokelau</option><option value="TO">Tonga</option><option value="TT">Trinidad and Tobago</option><option value="TA">Tristan da Cunha</option><option value="TN">Tunisia</option><option value="TR">Turkey</option><option value="TM">Turkmenistan</option><option value="TC">Turks and Caicos Islands</option><option value="TV">Tuvalu</option><option value="UM">U.S. Minor Outlying Islands</option><option value="PU">U.S. Miscellaneous Pacific Islands</option><option value="VI">U.S. Virgin Islands</option><option value="UG">Uganda</option><option value="UA">Ukraine</option><option value="AE">United Arab Emirates</option><option value="GB">United Kingdom</option><option value="US">United States</option><option value="UY">Uruguay</option><option value="UZ">Uzbekistan</option><option value="VU">Vanuatu</option><option value="VA">Vatican City</option><option value="VE">Venezuela</option><option value="VN">Vietnam</option><option value="WK">Wake Island</option><option value="WF">Wallis and Futuna</option><option value="EH">Western Sahara</option><option value="YE">Yemen</option><option value="ZM">Zambia</option><option value="AX">\u00c5land Islands</option></select></div></div><div class="field vat_number"><div class="placeholder">VAT Number</div><input type="text"/></div>';
|
|
2218
|
+
|
|
2219
|
+
//////////////////////////////////////////////////
|
|
2220
|
+
// Compiled from src/dom/subscribe_form.jade
|
|
2221
|
+
//////////////////////////////////////////////////
|
|
2222
|
+
|
|
2223
|
+
R.dom['subscribe_form'] = '<form class="recurly subscribe"><!--[if lt IE 7]><div class="iefail"><div class="chromeframe"><p class="blast">Your browser is not supported by Recurly.js.</p><p><a href="http://browsehappy.com/">Upgrade to a different browser</a></p><p>or</p><p><a href="http://www.google.com/chromeframe/?redirect=true">install Google Chrome Frame</a></p><p>to use this site.</p></div></div><![endif]--><div class="subscription"><div class="plan"><div class="name"></div><div class="field quantity"><div class="placeholder">Qty</div><input type="text"/></div><div class="recurring_cost"><div class="cost"></div><div class="interval"></div></div><div class="free_trial"></div><div class="setup_fee"><div class="title">Setup Fee</div><div class="cost"></div></div></div><div class="add_ons none"></div><div class="coupon"><div class="coupon_code field"><div class="placeholder">Coupon Code</div><input type="text" class="coupon_code"/></div><div class="check"></div><div class="description"></div><div class="discount"></div></div><div class="vat"><div class="title">VAT</div><div class="cost"></div></div></div><div class="due_now"><div class="title">Order Total</div><div class="cost"></div></div><div class="server_errors none"></div><div class="contact_info"></div><div class="billing_info"></div><div class="accept_tos"></div><div class="footer"><button type="submit" class="submit">Subscribe</button></div></form>';
|
|
2224
|
+
|
|
2225
|
+
//////////////////////////////////////////////////
|
|
2226
|
+
// Compiled from src/dom/update_billing_info_form.jade
|
|
2227
|
+
//////////////////////////////////////////////////
|
|
2228
|
+
|
|
2229
|
+
R.dom['update_billing_info_form'] = '<form class="recurly update_billing_info"><div class="server_errors none"></div><div class="billing_info"></div><div class="footer"><button type="submit" class="submit">Update</button></div></form>';
|
|
2230
|
+
|
|
2231
|
+
//////////////////////////////////////////////////
|
|
2232
|
+
// Compiled from src/dom/one_time_transaction_form.jade
|
|
2233
|
+
//////////////////////////////////////////////////
|
|
2234
|
+
|
|
2235
|
+
R.dom['one_time_transaction_form'] = '<form class="recurly update_billing_info"><div class="server_errors none"></div><div class="contact_info"></div><div class="billing_info"></div><div class="accept_tos"></div><div class="footer"><button type="submit" class="submit">Pay</button></div></form>';
|
|
2236
|
+
|
|
2237
|
+
//////////////////////////////////////////////////
|
|
2238
|
+
// Compiled from src/dom/terms_of_service.jade
|
|
2239
|
+
//////////////////////////////////////////////////
|
|
2240
|
+
|
|
2241
|
+
R.dom['terms_of_service'] = '<input id="tos_check" type="checkbox"/><label id="accept_tos" for="tos_check">I accept the <a target="_blank" class="tos_link">Terms of Service</a><span class="and"> and </span><a target="_blank" class="pp_link">Privacy Policy</a></label>';
|
|
2242
|
+
window.Recurly = R;
|
|
2243
|
+
})(jQuery);
|