Skip to content

Commit 3a60f15

Browse files
author
Jeff Harrell
committed
Adding support for editable buttons
1 parent 3eaf206 commit 3a60f15

3 files changed

Lines changed: 138 additions & 64 deletions

File tree

README.md

Lines changed: 24 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
Integrating with our HTML payment buttons are as easy as including a snippet of code. [Try it out and configure your own](http://paypal.github.com/JavaScriptButtons/).
44

5-
We have two flavors of buttons for you to use:
5+
We have a few flavors of buttons for you to use:
66

77
### Buy Now
88
Buy Now buttons are for single item purchases.
@@ -51,32 +51,39 @@ All of PayPal's [HTML button variables](https://cms.paypal.com/us/cgi-bin/?cmd=_
5151
* `data-size` For button images: `small` and `large` work. For QR codes enter the pixel length of the longest side.
5252
* `data-id` The hosted ID of the button (if applicable).
5353

54+
## Editable fields
55+
Creating editable fields is easy! Just add `-editable` to the name of your variable, e.g. `data-quantity-editable`, and an input field will magically appear for your users.
5456

55-
## Getting your Merchant ID
56-
Your merchant ID needs to be added to the URL of the referenced script. This ID can either be your Secure Merchant ID, which can be found by logging into your PayPal account and visiting your profile, or your email address.
57-
58-
59-
## Download
60-
To download the production-ready JavaScript you'll need to save one of these files:
61-
62-
* [JavaScript Buttons](https://github.com/paypal/JavaScriptButtons/blob/master/dist/paypal-button.min.js)
63-
* [JavaScript Buttons + MiniCart](https://github.com/paypal/JavaScriptButtons/blob/master/dist/paypal-button-minicart.min.js)
6457

65-
The first file gives you support for PayPal's JavaScript buttons. The second file has the same code from the first, but also contains functionality for the [PayPal Mini Cart](https://github.com/jeffharrell/MiniCart).
66-
67-
To see the un-minified code you can take a peek at [paypal-button.js](https://github.com/paypal/JavaScriptButtons/blob/master/src/paypal-button.js).
58+
## Localization
59+
* Changing the default language of a button can be done by setting the variable `data-lc` with the correct locale code, e.g. es_ES.
60+
* Changing the default input labels of editable buttons can be done by overriding the default configuration, e.g. PAYPAL.apps.ButtonFactory.config.labels.
6861

6962

7063
## JavaScript API
7164
There's even a fancy JavaScript API if you'd like to pragmatically create your buttons.
7265

66+
**PAYPAL.apps.ButtonFactory.config**
67+
This can be overridden to change the default behavior of the buttons.
68+
7369
**PAYPAL.apps.ButtonFactory.create(data, type, parentNode)**
7470
Creates and returns an HTML element that contains the button code.
7571
> **data** - A JavaScript object containing the button variables
7672
> **type** - The button type, e.g. "buynow", "cart", "qr"
7773
> **parentNode** - An HTML element to add the newly created button to (Optional)
7874
7975

76+
## Download
77+
To download the production-ready JavaScript you'll need to save one of these files:
78+
79+
* [JavaScript Buttons](https://github.com/paypal/JavaScriptButtons/blob/master/dist/paypal-button.min.js)
80+
* [JavaScript Buttons + MiniCart](https://github.com/paypal/JavaScriptButtons/blob/master/dist/paypal-button-minicart.min.js)
81+
82+
The first file gives you support for PayPal's JavaScript buttons. The second file has the same code from the first, but also contains functionality for the [PayPal Mini Cart](https://github.com/jeffharrell/MiniCart).
83+
84+
To see the un-minified code you can take a peek at [paypal-button.js](https://github.com/paypal/JavaScriptButtons/blob/master/src/paypal-button.js).
85+
86+
8087
## Browser support
8188
The JavaScript buttons have been tested and work in all modern browsers including:
8289

@@ -86,6 +93,10 @@ The JavaScript buttons have been tested and work in all modern browsers includin
8693
* Internet Explorer 7+.
8794

8895

96+
## Getting your Merchant ID
97+
Your merchant ID needs to be added to the URL of the referenced script. This ID can either be your Secure Merchant ID, which can be found by logging into your PayPal account and visiting your profile, or your email address.
98+
99+
89100
## Contributing [![Build Status](https://travis-ci.org/paypal/JavaScriptButtons.png)](https://travis-ci.org/paypal/JavaScriptButtons)
90101

91102
We love contributions! If you'd like to contribute please submit a pull request via Github.

src/paypal-button.js

Lines changed: 99 additions & 46 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,6 @@
11
if (typeof PAYPAL === 'undefined' || !PAYPAL) {
22
var PAYPAL = {};
33
}
4-
if (typeof module === 'object' && typeof module.exports === 'object') {
5-
module.exports = PAYPAL;
6-
}
74

85
PAYPAL.apps = PAYPAL.apps || {};
96

@@ -24,20 +21,31 @@ PAYPAL.apps = PAYPAL.apps || {};
2421
},
2522
buttonImgs = {
2623
buynow: '//www.paypalobjects.com/{locale}/i/btn/btn_buynow_{size}.gif',
27-
cart: '//www.paypalobjects.com/{locale}/i/btn/btn_cart_{size}.gif',
28-
basic: '//www.paypalobjects.com/{locale}/i/btn/btn_buynow_{size}.gif'
24+
cart: '//www.paypalobjects.com/{locale}/i/btn/btn_cart_{size}.gif'
2925
};
3026

3127
if (!PAYPAL.apps.ButtonFactory) {
3228

29+
/**
30+
* Initial config for the app
31+
*/
32+
app.config = {
33+
labels: {
34+
item_name: 'Item',
35+
item_number: 'Number',
36+
amount: 'Amount',
37+
quantity: 'Quantity'
38+
}
39+
};
40+
3341
/**
3442
* A count of each type of button on the page
3543
*/
3644
app.buttons = {
3745
buynow: 0,
3846
cart: 0,
39-
qr: 0,
40-
api: 0
47+
hosted: 0,
48+
qr: 0
4149
};
4250

4351
/**
@@ -49,42 +57,41 @@ PAYPAL.apps = PAYPAL.apps || {};
4957
* @return {HTMLElement}
5058
*/
5159
app.create = function (raw, type, parent) {
52-
var data = {}, button, key, size;
60+
var data = new DataStore(), button, key;
5361

5462
// Don't render without the correct data
5563
if (!raw || !raw.business) {
5664
return false;
5765
}
5866

59-
// Normalize the data's keys
67+
// Normalize the data's keys and add to a data store
6068
for (key in raw) {
61-
data[prettyParams[key] || key] = raw[key];
69+
data.add(prettyParams[key] || key, raw[key].value, raw[key].isEditable);
6270
}
6371

6472
// Setup defaults
65-
type = type || 'basic';
73+
type = type || 'buynow';
6674

6775
// Hosted buttons
6876
if (data.hosted_button_id) {
69-
data.cmd = '_s-xclick';
77+
type = 'hosted';
78+
data.add('cmd', '_s-xclick');
7079
// Cart buttons
7180
} else if (type === 'cart') {
72-
data.cmd = '_cart';
73-
data.add = true;
81+
data.add('cmd', '_cart');
82+
data.add('add', true);
7483
// Plain text buttons
7584
} else {
76-
data.cmd = '_xclick';
85+
data.add('cmd', '_xclick');
7786
}
7887

7988
// Create the button name
80-
data.bn = bnCode.replace(/\{type\}/, type);
89+
data.add('bn', bnCode.replace(/\{type\}/, type));
8190

8291
// Build the UI components
8392
if (type === 'qr') {
84-
size = data.size;
85-
delete data.size;
86-
87-
button = buildQR(data, size);
93+
button = buildQR(data, data.items.size);
94+
data.remove('size');
8895
} else {
8996
button = buildForm(type, data);
9097
}
@@ -116,24 +123,42 @@ PAYPAL.apps = PAYPAL.apps || {};
116123
var form = document.createElement('form'),
117124
btn = document.createElement('input'),
118125
hidden = document.createElement('input'),
119-
input, key;
126+
items = data.items,
127+
item, child, label, input, key;
120128

121129
btn.type = 'image';
122130
hidden.type = 'hidden';
123131
form.method = 'post';
124132
form.action = paypalURL;
125-
form.appendChild(btn);
133+
form.className = 'paypal-button';
126134

127-
btn.src = getButtonImg(type, data.size, data.lc);
135+
for (key in items) {
136+
item = items[key];
137+
138+
input = child = hidden.cloneNode(true);
139+
input.name = item.key;
140+
input.value = item.value;
141+
142+
if (item.isEditable) {
143+
input.type = 'text';
144+
input.className = 'paypal-input';
128145

129-
for (key in data) {
130-
input = hidden.cloneNode(true);
131-
input.name = key;
132-
input.value = data[key];
146+
label = document.createElement('label');
147+
label.className = 'paypal-label';
148+
label.appendChild(document.createTextNode(app.config.labels[item.key] + ' ' || ''));
149+
label.appendChild(input);
133150

134-
form.appendChild(input);
151+
child = document.createElement('p');
152+
child.className = 'paypal-group';
153+
child.appendChild(label);
154+
}
155+
156+
form.appendChild(child);
135157
}
136158

159+
form.appendChild(btn);
160+
btn.src = getButtonImg(type, data.size, data.lc);
161+
137162
// If the Mini Cart is present then register the form
138163
if (PAYPAL.apps.MiniCart && data.cmd === '_cart') {
139164
var MiniCart = PAYPAL.apps.MiniCart;
@@ -161,18 +186,21 @@ PAYPAL.apps = PAYPAL.apps || {};
161186
var img = document.createElement('img'),
162187
url = paypalURL + '?',
163188
pattern = 13,
164-
key;
189+
items = data.items,
190+
item, key;
165191

166192
// QR defaults
167193
size = size || 250;
168194

169-
for (key in data) {
170-
url += key + '=' + encodeURIComponent(data[key]) + '&';
195+
for (key in items) {
196+
item = items[key];
197+
198+
url += item.key + '=' + encodeURIComponent(item.value) + '&';
171199
}
172200

173201
url = encodeURIComponent(url);
174202

175-
img.src = 'https://www.paypal.com/webapps/ppint/qrcode?data=' + url + '&pattern=' + pattern + '&' + url + '&height=' + size;
203+
img.src = 'https://www.paypal.com/webapps/ppint/qrcode?data=' + url + '&pattern=' + pattern + '&' + url + '&height=' + size;
176204

177205
return img;
178206
}
@@ -187,7 +215,7 @@ PAYPAL.apps = PAYPAL.apps || {};
187215
* @return {String}
188216
*/
189217
function getButtonImg(type, size, locale) {
190-
var img = buttonImgs[type] || buttonImgs.basic;
218+
var img = buttonImgs[type] || buttonImgs.buynow;
191219

192220
// Image defaults
193221
locale = locale || 'en_US';
@@ -198,25 +226,23 @@ PAYPAL.apps = PAYPAL.apps || {};
198226

199227

200228
/**
201-
* Utility function to polyfill dataset functionality for browsers
229+
* Utility function to polyfill dataset functionality with a bit of a spin
202230
*
203231
* @param el {HTMLElement} The element to check
204232
* @return {Object}
205233
*/
206234
function getDataSet(el) {
207-
var dataset = el.dataset,
208-
attrs, attr, matches, len, i;
209-
210-
if (!dataset) {
211-
dataset = {};
235+
var dataset = {}, attrs, attr, matches, len, i;
212236

213-
if ((attrs = el.attributes)) {
214-
for (i = 0, len = attrs.length; i < len; i++) {
215-
attr = attrs[i];
237+
if ((attrs = el.attributes)) {
238+
for (i = 0, len = attrs.length; i < len; i++) {
239+
attr = attrs[i];
216240

217-
if ((matches = /^data-(.+)/.exec(attr.name))) {
218-
dataset[matches[1]] = attr.value;
219-
}
241+
if ((matches = /^data-([a-z]+)(-editable)?/i.exec(attr.name))) {
242+
dataset[matches[1]] = {
243+
value: attr.value,
244+
isEditable: !!matches[2]
245+
};
220246
}
221247
}
222248
}
@@ -225,6 +251,26 @@ PAYPAL.apps = PAYPAL.apps || {};
225251
}
226252

227253

254+
/**
255+
* A storage object to create structured methods around a button's data
256+
*/
257+
function DataStore() {
258+
this.items = {};
259+
260+
this.add = function (key, value, isEditable) {
261+
this.items[key] = {
262+
key: key,
263+
value: value,
264+
isEditable: isEditable
265+
};
266+
};
267+
268+
this.remove = function (key) {
269+
delete this.items[key];
270+
};
271+
}
272+
273+
228274
// Init the buttons
229275
if (typeof document !== 'undefined') {
230276
var ButtonFactory = PAYPAL.apps.ButtonFactory,
@@ -233,7 +279,8 @@ PAYPAL.apps = PAYPAL.apps || {};
233279

234280
for (i = 0, len = nodes.length; i < len; i++) {
235281
node = nodes[i];
236-
if (!node || !node.src) continue;
282+
283+
if (!node || !node.src) { continue; }
237284

238285
data = node && getDataSet(node);
239286
button = data && data.button;
@@ -250,3 +297,9 @@ PAYPAL.apps = PAYPAL.apps || {};
250297

251298

252299
}());
300+
301+
302+
// Export for CommonJS environments
303+
if (typeof module === 'object' && typeof module.exports === 'object') {
304+
module.exports = PAYPAL;
305+
}

0 commit comments

Comments
 (0)