simplecart-rails 0.0.1

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.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: dd03690b2e47ee14265094444e173df523b569d8
4
+ data.tar.gz: fe2209d2d1f3f60f278eb4762909d95177170e87
5
+ SHA512:
6
+ metadata.gz: dc2d929a06cb7f6c49986fe0ef154fdfd54775a139ea99798509531b703640653515a248fbe8615222bff0d8db115c30485b99cf0fa6376c77619f4ae76dfba6
7
+ data.tar.gz: e75908585be6733bb95f3486bd51a8098e9e5d838cca26483d5b408d97c0978fb1441a5f1108c1c3474acc0f671a22574e2a9bcb4238b1add058e290648fa09f
@@ -0,0 +1,2 @@
1
+ simplecart-rails
2
+ ================
@@ -0,0 +1,2 @@
1
+ require 'bundler'
2
+ Bundler::GemHelper.install_tasks
@@ -0,0 +1,2 @@
1
+ require "simplecart-rails/version"
2
+ require "simplecart-rails/engine" if defined?(::Rails)
@@ -0,0 +1,6 @@
1
+ module SimplecartRails
2
+ module Rails
3
+ class Engine < ::Rails::Engine
4
+ end
5
+ end
6
+ end
@@ -0,0 +1,5 @@
1
+ module SimplecartRails
2
+ module Rails
3
+ VERSION = "0.0.1"
4
+ end
5
+ end
@@ -0,0 +1,1931 @@
1
+ /*~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~
2
+ Copyright (c) 2012 Brett Wejrowski
3
+
4
+ wojodesign.com
5
+ simplecartjs.org
6
+ http://github.com/wojodesign/simplecart-js
7
+
8
+ VERSION 3.0.5
9
+
10
+ Dual licensed under the MIT or GPL licenses.
11
+ ~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~-~*/
12
+ /*jslint browser: true, unparam: true, white: true, nomen: true, regexp: true, maxerr: 50, indent: 4 */
13
+
14
+ (function (window, document) {
15
+ /*global HTMLElement */
16
+
17
+ var typeof_string = typeof "",
18
+ typeof_undefined = typeof undefined,
19
+ typeof_function = typeof function () {},
20
+ typeof_object = typeof {},
21
+ isTypeOf = function (item, type) { return typeof item === type; },
22
+ isString = function (item) { return isTypeOf(item, typeof_string); },
23
+ isUndefined = function (item) { return isTypeOf(item, typeof_undefined); },
24
+ isFunction = function (item) { return isTypeOf(item, typeof_function); },
25
+
26
+ isObject = function (item) { return isTypeOf(item, typeof_object); },
27
+ //Returns true if it is a DOM element
28
+ isElement = function (o) {
29
+ return typeof HTMLElement === "object" ? o instanceof HTMLElement : typeof o === "object" && o.nodeType === 1 && typeof o.nodeName === "string";
30
+ },
31
+
32
+
33
+
34
+ generateSimpleCart = function (space) {
35
+
36
+ // stealing this from selectivizr
37
+ var selectorEngines = {
38
+ "MooTools" : "$$",
39
+ "Prototype" : "$$",
40
+ "jQuery" : "*"
41
+ },
42
+
43
+
44
+ // local variables for internal use
45
+ item_id = 0,
46
+ item_id_namespace = "SCI-",
47
+ sc_items = {},
48
+ namespace = space || "simpleCart",
49
+ selectorFunctions = {},
50
+ eventFunctions = {},
51
+ baseEvents = {},
52
+
53
+ // local references
54
+ localStorage = window.localStorage,
55
+ console = window.console || { msgs: [], log: function (msg) { console.msgs.push(msg); } },
56
+
57
+ // used in views
58
+ _VALUE_ = 'value',
59
+ _TEXT_ = 'text',
60
+ _HTML_ = 'html',
61
+ _CLICK_ = 'click',
62
+
63
+ // Currencies
64
+ currencies = {
65
+ "USD": { code: "USD", symbol: "&#36;", name: "US Dollar" },
66
+ "AUD": { code: "AUD", symbol: "&#36;", name: "Australian Dollar" },
67
+ "BRL": { code: "BRL", symbol: "R&#36;", name: "Brazilian Real" },
68
+ "CAD": { code: "CAD", symbol: "&#36;", name: "Canadian Dollar" },
69
+ "CZK": { code: "CZK", symbol: "&nbsp;&#75;&#269;", name: "Czech Koruna", after: true },
70
+ "DKK": { code: "DKK", symbol: "DKK&nbsp;", name: "Danish Krone" },
71
+ "EUR": { code: "EUR", symbol: "&euro;", name: "Euro" },
72
+ "HKD": { code: "HKD", symbol: "&#36;", name: "Hong Kong Dollar" },
73
+ "HUF": { code: "HUF", symbol: "&#70;&#116;", name: "Hungarian Forint" },
74
+ "ILS": { code: "ILS", symbol: "&#8362;", name: "Israeli New Sheqel" },
75
+ "JPY": { code: "JPY", symbol: "&yen;", name: "Japanese Yen", accuracy: 0 },
76
+ "MXN": { code: "MXN", symbol: "&#36;", name: "Mexican Peso" },
77
+ "NOK": { code: "NOK", symbol: "NOK&nbsp;", name: "Norwegian Krone" },
78
+ "NZD": { code: "NZD", symbol: "&#36;", name: "New Zealand Dollar" },
79
+ "PLN": { code: "PLN", symbol: "PLN&nbsp;", name: "Polish Zloty" },
80
+ "GBP": { code: "GBP", symbol: "&pound;", name: "Pound Sterling" },
81
+ "SGD": { code: "SGD", symbol: "&#36;", name: "Singapore Dollar" },
82
+ "SEK": { code: "SEK", symbol: "SEK&nbsp;", name: "Swedish Krona" },
83
+ "CHF": { code: "CHF", symbol: "CHF&nbsp;", name: "Swiss Franc" },
84
+ "THB": { code: "THB", symbol: "&#3647;", name: "Thai Baht" },
85
+ "BTC": { code: "BTC", symbol: " BTC", name: "Bitcoin", accuracy: 4, after: true }
86
+ },
87
+
88
+ // default options
89
+ settings = {
90
+ checkout : { type: "PayPal", email: "you@yours.com" },
91
+ currency : "USD",
92
+ language : "english-us",
93
+
94
+ cartStyle : "div",
95
+ cartColumns : [
96
+ { attr: "name", label: "Name" },
97
+ { attr: "price", label: "Price", view: 'currency' },
98
+ { view: "decrement", label: false },
99
+ { attr: "quantity", label: "Qty" },
100
+ { view: "increment", label: false },
101
+ { attr: "total", label: "SubTotal", view: 'currency' },
102
+ { view: "remove", text: "Remove", label: false }
103
+ ],
104
+
105
+ excludeFromCheckout : ['thumb'],
106
+
107
+ shippingFlatRate : 0,
108
+ shippingQuantityRate : 0,
109
+ shippingTotalRate : 0,
110
+ shippingCustom : null,
111
+
112
+ taxRate : 0,
113
+
114
+ taxShipping : false,
115
+
116
+ data : {}
117
+
118
+ },
119
+
120
+
121
+ // main simpleCart object, function call is used for setting options
122
+ simpleCart = function (options) {
123
+ // shortcut for simpleCart.ready
124
+ if (isFunction(options)) {
125
+ return simpleCart.ready(options);
126
+ }
127
+
128
+ // set options
129
+ if (isObject(options)) {
130
+ return simpleCart.extend(settings, options);
131
+ }
132
+ },
133
+
134
+ // selector engine
135
+ $engine,
136
+
137
+ // built in cart views for item cells
138
+ cartColumnViews;
139
+
140
+ // function for extending objects
141
+ simpleCart.extend = function (target, opts) {
142
+ var next;
143
+
144
+ if (isUndefined(opts)) {
145
+ opts = target;
146
+ target = simpleCart;
147
+ }
148
+
149
+ for (next in opts) {
150
+ if (Object.prototype.hasOwnProperty.call(opts, next)) {
151
+ target[next] = opts[next];
152
+ }
153
+ }
154
+ return target;
155
+ };
156
+
157
+ // create copy function
158
+ simpleCart.extend({
159
+ copy: function (n) {
160
+ var cp = generateSimpleCart(n);
161
+ cp.init();
162
+ return cp;
163
+ }
164
+ });
165
+
166
+ // add in the core functionality
167
+ simpleCart.extend({
168
+
169
+ isReady: false,
170
+
171
+ // this is where the magic happens, the add function
172
+ add: function (values, opt_quiet) {
173
+ var info = values || {},
174
+ newItem = new simpleCart.Item(info),
175
+ addItem = true,
176
+ // optionally supress event triggers
177
+ quiet = opt_quiet === true ? opt_quiet : false,
178
+ oldItem;
179
+
180
+ // trigger before add event
181
+ if (!quiet) {
182
+ addItem = simpleCart.trigger('beforeAdd', [newItem]);
183
+
184
+ if (addItem === false) {
185
+ return false;
186
+ }
187
+ }
188
+
189
+ // if the new item already exists, increment the value
190
+ oldItem = simpleCart.has(newItem);
191
+ if (oldItem) {
192
+ oldItem.increment(newItem.quantity());
193
+ newItem = oldItem;
194
+
195
+ // otherwise add the item
196
+ } else {
197
+ sc_items[newItem.id()] = newItem;
198
+ }
199
+
200
+ // update the cart
201
+ simpleCart.update();
202
+
203
+ if (!quiet) {
204
+ // trigger after add event
205
+ simpleCart.trigger('afterAdd', [newItem, isUndefined(oldItem)]);
206
+ }
207
+
208
+ // return a reference to the added item
209
+ return newItem;
210
+ },
211
+
212
+
213
+ // iteration function
214
+ each: function (array, callback) {
215
+ var next,
216
+ x = 0,
217
+ result,
218
+ cb,
219
+ items;
220
+
221
+ if (isFunction(array)) {
222
+ cb = array;
223
+ items = sc_items;
224
+ } else if (isFunction(callback)) {
225
+ cb = callback;
226
+ items = array;
227
+ } else {
228
+ return;
229
+ }
230
+
231
+ for (next in items) {
232
+ if (Object.prototype.hasOwnProperty.call(items, next)) {
233
+ result = cb.call(simpleCart, items[next], x, next);
234
+ if (result === false) {
235
+ return;
236
+ }
237
+ x += 1;
238
+ }
239
+ }
240
+ },
241
+
242
+ find: function (id) {
243
+ var items = [];
244
+
245
+ // return object for id if it exists
246
+ if (isObject(sc_items[id])) {
247
+ return sc_items[id];
248
+ }
249
+ // search through items with the given criteria
250
+ if (isObject(id)) {
251
+ simpleCart.each(function (item) {
252
+ var match = true;
253
+ simpleCart.each(id, function (val, x, attr) {
254
+
255
+ if (isString(val)) {
256
+ // less than or equal to
257
+ if (val.match(/<=.*/)) {
258
+ val = parseFloat(val.replace('<=', ''));
259
+ if (!(item.get(attr) && parseFloat(item.get(attr)) <= val)) {
260
+ match = false;
261
+ }
262
+
263
+ // less than
264
+ } else if (val.match(/</)) {
265
+ val = parseFloat(val.replace('<', ''));
266
+ if (!(item.get(attr) && parseFloat(item.get(attr)) < val)) {
267
+ match = false;
268
+ }
269
+
270
+ // greater than or equal to
271
+ } else if (val.match(/>=/)) {
272
+ val = parseFloat(val.replace('>=', ''));
273
+ if (!(item.get(attr) && parseFloat(item.get(attr)) >= val)) {
274
+ match = false;
275
+ }
276
+
277
+ // greater than
278
+ } else if (val.match(/>/)) {
279
+ val = parseFloat(val.replace('>', ''));
280
+ if (!(item.get(attr) && parseFloat(item.get(attr)) > val)) {
281
+ match = false;
282
+ }
283
+
284
+ // equal to
285
+ } else if (!(item.get(attr) && item.get(attr) === val)) {
286
+ match = false;
287
+ }
288
+
289
+ // equal to non string
290
+ } else if (!(item.get(attr) && item.get(attr) === val)) {
291
+ match = false;
292
+ }
293
+
294
+ return match;
295
+ });
296
+
297
+ // add the item if it matches
298
+ if (match) {
299
+ items.push(item);
300
+ }
301
+ });
302
+ return items;
303
+ }
304
+
305
+ // if no criteria is given we return all items
306
+ if (isUndefined(id)) {
307
+
308
+ // use a new array so we don't give a reference to the
309
+ // cart's item array
310
+ simpleCart.each(function (item) {
311
+ items.push(item);
312
+ });
313
+ return items;
314
+ }
315
+
316
+ // return empty array as default
317
+ return items;
318
+ },
319
+
320
+ // return all items
321
+ items: function () {
322
+ return this.find();
323
+ },
324
+
325
+ // check to see if item is in the cart already
326
+ has: function (item) {
327
+ var match = false;
328
+
329
+ simpleCart.each(function (testItem) {
330
+ if (testItem.equals(item)) {
331
+ match = testItem;
332
+ }
333
+ });
334
+ return match;
335
+ },
336
+
337
+ // empty the cart
338
+ empty: function () {
339
+ // remove each item individually so we see the remove events
340
+ var newItems = {};
341
+ simpleCart.each(function (item) {
342
+ // send a param of true to make sure it doesn't
343
+ // update after every removal
344
+ // keep the item if the function returns false,
345
+ // because we know it has been prevented
346
+ // from being removed
347
+ if (item.remove(true) === false) {
348
+ newItems[item.id()] = item
349
+ }
350
+ });
351
+ sc_items = newItems;
352
+ simpleCart.update();
353
+ },
354
+
355
+
356
+ // functions for accessing cart info
357
+ quantity: function () {
358
+ var quantity = 0;
359
+ simpleCart.each(function (item) {
360
+ quantity += item.quantity();
361
+ });
362
+ return quantity;
363
+ },
364
+
365
+ total: function () {
366
+ var total = 0;
367
+ simpleCart.each(function (item) {
368
+ total += item.total();
369
+ });
370
+ return total;
371
+ },
372
+
373
+ grandTotal: function () {
374
+ return simpleCart.total() + simpleCart.tax() + simpleCart.shipping();
375
+ },
376
+
377
+
378
+ // updating functions
379
+ update: function () {
380
+ simpleCart.save();
381
+ simpleCart.trigger("update");
382
+ },
383
+
384
+ init: function () {
385
+ simpleCart.load();
386
+ simpleCart.update();
387
+ simpleCart.ready();
388
+ },
389
+
390
+ // view management
391
+ $: function (selector) {
392
+ return new simpleCart.ELEMENT(selector);
393
+ },
394
+
395
+ $create: function (tag) {
396
+ return simpleCart.$(document.createElement(tag));
397
+ },
398
+
399
+ setupViewTool: function () {
400
+ var members, member, context = window, engine;
401
+
402
+ // Determine the "best fit" selector engine
403
+ for (engine in selectorEngines) {
404
+ if (Object.prototype.hasOwnProperty.call(selectorEngines, engine) && window[engine]) {
405
+ members = selectorEngines[engine].replace("*", engine).split(".");
406
+ member = members.shift();
407
+ if (member) {
408
+ context = context[member];
409
+ }
410
+ if (typeof context === "function") {
411
+ // set the selector engine and extend the prototype of our
412
+ // element wrapper class
413
+ $engine = context;
414
+ simpleCart.extend(simpleCart.ELEMENT._, selectorFunctions[engine]);
415
+ return;
416
+ }
417
+ }
418
+ }
419
+ },
420
+
421
+ // return a list of id's in the cart
422
+ ids: function () {
423
+ var ids = [];
424
+ simpleCart.each(function (item) {
425
+ ids.push(item.id());
426
+ });
427
+ return ids;
428
+
429
+ },
430
+
431
+
432
+ // storage
433
+ save: function () {
434
+ simpleCart.trigger('beforeSave');
435
+
436
+ var items = {};
437
+
438
+ // save all the items
439
+ simpleCart.each(function (item) {
440
+ items[item.id()] = simpleCart.extend(item.fields(), item.options());
441
+ });
442
+
443
+ localStorage.setItem(namespace + "_items", JSON.stringify(items));
444
+
445
+ simpleCart.trigger('afterSave');
446
+ },
447
+
448
+ load: function () {
449
+
450
+ // empty without the update
451
+ sc_items = {};
452
+
453
+ var items = localStorage.getItem(namespace + "_items");
454
+
455
+ if (!items) {
456
+ return;
457
+ }
458
+
459
+ // we wrap this in a try statement so we can catch
460
+ // any json parsing errors. no more stick and we
461
+ // have a playing card pluckin the spokes now...
462
+ // soundin like a harley.
463
+ try {
464
+ simpleCart.each(JSON.parse(items), function (item) {
465
+ simpleCart.add(item, true);
466
+ });
467
+ } catch (e){
468
+ simpleCart.error( "Error Loading data: " + e );
469
+ }
470
+
471
+
472
+ simpleCart.trigger('load');
473
+ },
474
+
475
+ // ready function used as a shortcut for bind('ready',fn)
476
+ ready: function (fn) {
477
+
478
+ if (isFunction(fn)) {
479
+ // call function if already ready already
480
+ if (simpleCart.isReady) {
481
+ fn.call(simpleCart);
482
+
483
+ // bind if not ready
484
+ } else {
485
+ simpleCart.bind('ready', fn);
486
+ }
487
+
488
+ // trigger ready event
489
+ } else if (isUndefined(fn) && !simpleCart.isReady) {
490
+ simpleCart.trigger('ready');
491
+ simpleCart.isReady = true;
492
+ }
493
+
494
+ },
495
+
496
+
497
+ error: function (message) {
498
+ var msg = "";
499
+ if (isString(message)) {
500
+ msg = message;
501
+ } else if (isObject(message) && isString(message.message)) {
502
+ msg = message.message;
503
+ }
504
+ try { console.log("simpleCart(js) Error: " + msg); } catch (e) {}
505
+ simpleCart.trigger('error', [message]);
506
+ }
507
+ });
508
+
509
+
510
+ /*******************************************************************
511
+ * TAX AND SHIPPING
512
+ *******************************************************************/
513
+ simpleCart.extend({
514
+
515
+ // TODO: tax and shipping
516
+ tax: function () {
517
+ var totalToTax = settings.taxShipping ? simpleCart.total() + simpleCart.shipping() : simpleCart.total(),
518
+ cost = simpleCart.taxRate() * totalToTax;
519
+
520
+ simpleCart.each(function (item) {
521
+ if (item.get('tax')) {
522
+ cost += item.get('tax');
523
+ } else if (item.get('taxRate')) {
524
+ cost += item.get('taxRate') * item.total();
525
+ }
526
+ });
527
+ return parseFloat(cost);
528
+ },
529
+
530
+ taxRate: function () {
531
+ return settings.taxRate || 0;
532
+ },
533
+
534
+ shipping: function (opt_custom_function) {
535
+
536
+ // shortcut to extend options with custom shipping
537
+ if (isFunction(opt_custom_function)) {
538
+ simpleCart({
539
+ shippingCustom: opt_custom_function
540
+ });
541
+ return;
542
+ }
543
+
544
+ var cost = settings.shippingQuantityRate * simpleCart.quantity() +
545
+ settings.shippingTotalRate * simpleCart.total() +
546
+ settings.shippingFlatRate;
547
+
548
+ if (isFunction(settings.shippingCustom)) {
549
+ cost += settings.shippingCustom.call(simpleCart);
550
+ }
551
+
552
+ simpleCart.each(function (item) {
553
+ cost += parseFloat(item.get('shipping') || 0);
554
+ });
555
+ return parseFloat(cost);
556
+ }
557
+
558
+ });
559
+
560
+ /*******************************************************************
561
+ * CART VIEWS
562
+ *******************************************************************/
563
+
564
+ // built in cart views for item cells
565
+ cartColumnViews = {
566
+ attr: function (item, column) {
567
+ return item.get(column.attr) || "";
568
+ },
569
+
570
+ currency: function (item, column) {
571
+ return simpleCart.toCurrency(item.get(column.attr) || 0);
572
+ },
573
+
574
+ link: function (item, column) {
575
+ return "<a href='" + item.get(column.attr) + "'>" + column.text + "</a>";
576
+ },
577
+
578
+ decrement: function (item, column) {
579
+ return "<a href='javascript:;' class='" + namespace + "_decrement'>" + (column.text || "-") + "</a>";
580
+ },
581
+
582
+ increment: function (item, column) {
583
+ return "<a href='javascript:;' class='" + namespace + "_increment'>" + (column.text || "+") + "</a>";
584
+ },
585
+
586
+ image: function (item, column) {
587
+ return "<img src='" + item.get(column.attr) + "'/>";
588
+ },
589
+
590
+ input: function (item, column) {
591
+ return "<input type='text' value='" + item.get(column.attr) + "' class='" + namespace + "_input'/>";
592
+ },
593
+
594
+ remove: function (item, column) {
595
+ return "<a href='javascript:;' class='" + namespace + "_remove'>" + (column.text || "X") + "</a>";
596
+ }
597
+ };
598
+
599
+ // cart column wrapper class and functions
600
+ function cartColumn(opts) {
601
+ var options = opts || {};
602
+ return simpleCart.extend({
603
+ attr : "",
604
+ label : "",
605
+ view : "attr",
606
+ text : "",
607
+ className : "",
608
+ hide : false
609
+ }, options);
610
+ }
611
+
612
+ function cartCellView(item, column) {
613
+ var viewFunc = isFunction(column.view) ? column.view : isString(column.view) && isFunction(cartColumnViews[column.view]) ? cartColumnViews[column.view] : cartColumnViews.attr;
614
+
615
+ return viewFunc.call(simpleCart, item, column);
616
+ }
617
+
618
+
619
+ simpleCart.extend({
620
+
621
+ // write out cart
622
+ writeCart: function (selector) {
623
+ var TABLE = settings.cartStyle.toLowerCase(),
624
+ isTable = TABLE === 'table',
625
+ TR = isTable ? "tr" : "div",
626
+ TH = isTable ? 'th' : 'div',
627
+ TD = isTable ? 'td' : 'div',
628
+ THEAD = isTable ? 'thead' : 'div',
629
+ cart_container = simpleCart.$create(TABLE),
630
+ thead_container = simpleCart.$create(THEAD),
631
+ header_container = simpleCart.$create(TR).addClass('headerRow'),
632
+ container = simpleCart.$(selector),
633
+ column,
634
+ klass,
635
+ label,
636
+ x,
637
+ xlen;
638
+
639
+ container.html(' ').append(cart_container);
640
+
641
+ cart_container.append(thead_container);
642
+
643
+ thead_container.append(header_container);
644
+
645
+
646
+ // create header
647
+ for (x = 0, xlen = settings.cartColumns.length; x < xlen; x += 1) {
648
+ column = cartColumn(settings.cartColumns[x]);
649
+ klass = "item-" + (column.attr || column.view || column.label || column.text || "cell") + " " + column.className;
650
+ label = column.label || "";
651
+
652
+ // append the header cell
653
+ header_container.append(
654
+ simpleCart.$create(TH).addClass(klass).html(label)
655
+ );
656
+ }
657
+
658
+ // cycle through the items
659
+ simpleCart.each(function (item, y) {
660
+ simpleCart.createCartRow(item, y, TR, TD, cart_container);
661
+ });
662
+
663
+ return cart_container;
664
+ },
665
+
666
+ // generate a cart row from an item
667
+ createCartRow: function (item, y, TR, TD, container) {
668
+ var row = simpleCart.$create(TR)
669
+ .addClass('itemRow row-' + y + " " + (y % 2 ? "even" : "odd"))
670
+ .attr('id', "cartItem_" + item.id()),
671
+ j,
672
+ jlen,
673
+ column,
674
+ klass,
675
+ content,
676
+ cell;
677
+
678
+ container.append(row);
679
+
680
+ // cycle through the columns to create each cell for the item
681
+ for (j = 0, jlen = settings.cartColumns.length; j < jlen; j += 1) {
682
+ column = cartColumn(settings.cartColumns[j]);
683
+ klass = "item-" + (column.attr || (isString(column.view) ? column.view : column.label || column.text || "cell")) + " " + column.className;
684
+ content = cartCellView(item, column);
685
+ cell = simpleCart.$create(TD).addClass(klass).html(content);
686
+
687
+ row.append(cell);
688
+ }
689
+ return row;
690
+ }
691
+
692
+ });
693
+
694
+ /*******************************************************************
695
+ * CART ITEM CLASS MANAGEMENT
696
+ *******************************************************************/
697
+
698
+ simpleCart.Item = function (info) {
699
+
700
+ // we use the data object to track values for the item
701
+ var _data = {},
702
+ me = this;
703
+
704
+ // cycle through given attributes and set them to the data object
705
+ if (isObject(info)) {
706
+ simpleCart.extend(_data, info);
707
+ }
708
+
709
+ // set the item id
710
+ item_id += 1;
711
+ _data.id = _data.id || item_id_namespace + item_id;
712
+ while (!isUndefined(sc_items[_data.id])) {
713
+ item_id += 1;
714
+ _data.id = item_id_namespace + item_id;
715
+ }
716
+
717
+ function checkQuantityAndPrice() {
718
+
719
+ // check to make sure price is valid
720
+ if (isString(_data.price)) {
721
+ // trying to remove all chars that aren't numbers or '.'
722
+ _data.price = parseFloat(_data.price.replace(simpleCart.currency().decimal, ".").replace(/[^0-9\.]+/ig, ""));
723
+
724
+ }
725
+ if (isNaN(_data.price)) {
726
+ _data.price = 0;
727
+ }
728
+ if (_data.price < 0) {
729
+ _data.price = 0;
730
+ }
731
+
732
+ // check to make sure quantity is valid
733
+ if (isString(_data.quantity)) {
734
+ _data.quantity = parseInt(_data.quantity.replace(simpleCart.currency().delimiter, ""), 10);
735
+ }
736
+ if (isNaN(_data.quantity)) {
737
+ _data.quantity = 1;
738
+ }
739
+ if (_data.quantity <= 0) {
740
+ me.remove();
741
+ }
742
+
743
+ }
744
+
745
+ // getter and setter methods to access private variables
746
+ me.get = function (name, skipPrototypes) {
747
+
748
+ var usePrototypes = !skipPrototypes;
749
+
750
+ if (isUndefined(name)) {
751
+ return name;
752
+ }
753
+
754
+ // return the value in order of the data object and then the prototype
755
+ return isFunction(_data[name]) ? _data[name].call(me) :
756
+ !isUndefined(_data[name]) ? _data[name] :
757
+
758
+ isFunction(me[name]) && usePrototypes ? me[name].call(me) :
759
+ !isUndefined(me[name]) && usePrototypes ? me[name] :
760
+ _data[name];
761
+ };
762
+ me.set = function (name, value) {
763
+ if (!isUndefined(name)) {
764
+ _data[name.toLowerCase()] = value;
765
+ if (name.toLowerCase() === 'price' || name.toLowerCase() === 'quantity') {
766
+ checkQuantityAndPrice();
767
+ }
768
+ }
769
+ return me;
770
+ };
771
+ me.equals = function (item) {
772
+ for( var label in _data ){
773
+ if (Object.prototype.hasOwnProperty.call(_data, label)) {
774
+ if (label !== 'quantity' && label !== 'id') {
775
+ if (item.get(label) !== _data[label]) {
776
+ return false;
777
+ }
778
+ }
779
+ }
780
+ }
781
+ return true;
782
+ };
783
+ me.options = function () {
784
+ var data = {};
785
+ simpleCart.each(_data,function (val, x, label) {
786
+ var add = true;
787
+ simpleCart.each(me.reservedFields(), function (field) {
788
+ if (field === label) {
789
+ add = false;
790
+ }
791
+ return add;
792
+ });
793
+
794
+ if (add) {
795
+ data[label] = me.get(label);
796
+ }
797
+ });
798
+ return data;
799
+ };
800
+
801
+
802
+ checkQuantityAndPrice();
803
+ };
804
+
805
+ simpleCart.Item._ = simpleCart.Item.prototype = {
806
+
807
+ // editing the item quantity
808
+ increment: function (amount) {
809
+ var diff = amount || 1;
810
+ diff = parseInt(diff, 10);
811
+
812
+ this.quantity(this.quantity() + diff);
813
+ if (this.quantity() < 1) {
814
+ this.remove();
815
+ return null;
816
+ }
817
+ return this;
818
+
819
+ },
820
+ decrement: function (amount) {
821
+ var diff = amount || 1;
822
+ return this.increment(-parseInt(diff, 10));
823
+ },
824
+ remove: function (skipUpdate) {
825
+ var removeItemBool = simpleCart.trigger("beforeRemove", [sc_items[this.id()]]);
826
+ if (removeItemBool === false ) {
827
+ return false;
828
+ }
829
+ delete sc_items[this.id()];
830
+ if (!skipUpdate) {
831
+ simpleCart.update();
832
+ }
833
+ return null;
834
+ },
835
+
836
+ // special fields for items
837
+ reservedFields: function () {
838
+ return ['quantity', 'id', 'item_number', 'price', 'name', 'shipping', 'tax', 'taxRate'];
839
+ },
840
+
841
+ // return values for all reserved fields if they exist
842
+ fields: function () {
843
+ var data = {},
844
+ me = this;
845
+ simpleCart.each(me.reservedFields(), function (field) {
846
+ if (me.get(field)) {
847
+ data[field] = me.get(field);
848
+ }
849
+ });
850
+ return data;
851
+ },
852
+
853
+
854
+ // shortcuts for getter/setters. can
855
+ // be overwritten for customization
856
+ // btw, we are hiring at wojo design, and could
857
+ // use a great web designer. if thats you, you can
858
+ // get more info at http://wojodesign.com/now-hiring/
859
+ // or email me directly: brett@wojodesign.com
860
+ quantity: function (val) {
861
+ return isUndefined(val) ? parseInt(this.get("quantity", true) || 1, 10) : this.set("quantity", val);
862
+ },
863
+ price: function (val) {
864
+ return isUndefined(val) ?
865
+ parseFloat((this.get("price",true).toString()).replace(simpleCart.currency().symbol,"").replace(simpleCart.currency().delimiter,"") || 1) :
866
+ this.set("price", parseFloat((val).toString().replace(simpleCart.currency().symbol,"").replace(simpleCart.currency().delimiter,"")));
867
+ },
868
+ id: function () {
869
+ return this.get('id',false);
870
+ },
871
+ total:function () {
872
+ return this.quantity()*this.price();
873
+ }
874
+
875
+ };
876
+
877
+
878
+
879
+
880
+ /*******************************************************************
881
+ * CHECKOUT MANAGEMENT
882
+ *******************************************************************/
883
+
884
+ simpleCart.extend({
885
+ checkout: function () {
886
+ if (settings.checkout.type.toLowerCase() === 'custom' && isFunction(settings.checkout.fn)) {
887
+ settings.checkout.fn.call(simpleCart,settings.checkout);
888
+ } else if (isFunction(simpleCart.checkout[settings.checkout.type])) {
889
+ var checkoutData = simpleCart.checkout[settings.checkout.type].call(simpleCart,settings.checkout);
890
+
891
+ // if the checkout method returns data, try to send the form
892
+ if( checkoutData.data && checkoutData.action && checkoutData.method ){
893
+ // if no one has any objections, send the checkout form
894
+ if( false !== simpleCart.trigger('beforeCheckout', [checkoutData.data]) ){
895
+ simpleCart.generateAndSendForm( checkoutData );
896
+ }
897
+ }
898
+
899
+ } else {
900
+ simpleCart.error("No Valid Checkout Method Specified");
901
+ }
902
+ },
903
+ extendCheckout: function (methods) {
904
+ return simpleCart.extend(simpleCart.checkout, methods);
905
+ },
906
+ generateAndSendForm: function (opts) {
907
+ var form = simpleCart.$create("form");
908
+ form.attr('style', 'display:none;');
909
+ form.attr('action', opts.action);
910
+ form.attr('method', opts.method);
911
+ simpleCart.each(opts.data, function (val, x, name) {
912
+ form.append(
913
+ simpleCart.$create("input").attr("type","hidden").attr("name",name).val(val)
914
+ );
915
+ });
916
+ simpleCart.$("body").append(form);
917
+ form.el.submit();
918
+ form.remove();
919
+ }
920
+ });
921
+
922
+ simpleCart.extendCheckout({
923
+ PayPal: function (opts) {
924
+ // account email is required
925
+ if (!opts.email) {
926
+ return simpleCart.error("No email provided for PayPal checkout");
927
+ }
928
+
929
+ // build basic form options
930
+ var data = {
931
+ cmd : "_cart"
932
+ , upload : "1"
933
+ , currency_code : simpleCart.currency().code
934
+ , business : opts.email
935
+ , rm : opts.method === "GET" ? "0" : "2"
936
+ , tax_cart : (simpleCart.tax()*1).toFixed(2)
937
+ , handling_cart : (simpleCart.shipping()*1).toFixed(2)
938
+ , charset : "utf-8"
939
+ },
940
+ action = opts.sandbox ? "https://www.sandbox.paypal.com/cgi-bin/webscr" : "https://www.paypal.com/cgi-bin/webscr",
941
+ method = opts.method === "GET" ? "GET" : "POST";
942
+
943
+
944
+ // check for return and success URLs in the options
945
+ if (opts.success) {
946
+ data['return'] = opts.success;
947
+ }
948
+ if (opts.cancel) {
949
+ data.cancel_return = opts.cancel;
950
+ }
951
+ if (opts.notify) {
952
+ data.notify_url = opts.notify;
953
+ }
954
+
955
+
956
+ // add all the items to the form data
957
+ simpleCart.each(function (item,x) {
958
+ var counter = x+1,
959
+ item_options = item.options(),
960
+ optionCount = 0,
961
+ send;
962
+
963
+ // basic item data
964
+ data["item_name_" + counter] = item.get("name");
965
+ data["quantity_" + counter] = item.quantity();
966
+ data["amount_" + counter] = (item.price()*1).toFixed(2);
967
+ data["item_number_" + counter] = item.get("item_number") || counter;
968
+
969
+
970
+ // add the options
971
+ simpleCart.each(item_options, function (val,k,attr) {
972
+ // paypal limits us to 10 options
973
+ if (k < 10) {
974
+
975
+ // check to see if we need to exclude this from checkout
976
+ send = true;
977
+ simpleCart.each(settings.excludeFromCheckout, function (field_name) {
978
+ if (field_name === attr) { send = false; }
979
+ });
980
+ if (send) {
981
+ optionCount += 1;
982
+ data["on" + k + "_" + counter] = attr;
983
+ data["os" + k + "_" + counter] = val;
984
+ }
985
+
986
+ }
987
+ });
988
+
989
+ // options count
990
+ data["option_index_"+ x] = Math.min(10, optionCount);
991
+ });
992
+
993
+
994
+ // return the data for the checkout form
995
+ return {
996
+ action : action
997
+ , method : method
998
+ , data : data
999
+ };
1000
+
1001
+ },
1002
+
1003
+
1004
+ GoogleCheckout: function (opts) {
1005
+ // account id is required
1006
+ if (!opts.merchantID) {
1007
+ return simpleCart.error("No merchant id provided for GoogleCheckout");
1008
+ }
1009
+
1010
+ // google only accepts USD and GBP
1011
+ if (simpleCart.currency().code !== "USD" && simpleCart.currency().code !== "GBP") {
1012
+ return simpleCart.error("Google Checkout only accepts USD and GBP");
1013
+ }
1014
+
1015
+ // build basic form options
1016
+ var data = {
1017
+ // TODO: better shipping support for this google
1018
+ ship_method_name_1 : "Shipping"
1019
+ , ship_method_price_1 : simpleCart.shipping()
1020
+ , ship_method_currency_1: simpleCart.currency().code
1021
+ , _charset_ : ''
1022
+ },
1023
+ action = "https://checkout.google.com/api/checkout/v2/checkoutForm/Merchant/" + opts.merchantID,
1024
+ method = opts.method === "GET" ? "GET" : "POST";
1025
+
1026
+
1027
+ // add items to data
1028
+ simpleCart.each(function (item,x) {
1029
+ var counter = x+1,
1030
+ options_list = [],
1031
+ send;
1032
+ data['item_name_' + counter] = item.get('name');
1033
+ data['item_quantity_' + counter] = item.quantity();
1034
+ data['item_price_' + counter] = item.price();
1035
+ data['item_currency_ ' + counter] = simpleCart.currency().code;
1036
+ data['item_tax_rate' + counter] = item.get('taxRate') || simpleCart.taxRate();
1037
+
1038
+ // create array of extra options
1039
+ simpleCart.each(item.options(), function (val,x,attr) {
1040
+ // check to see if we need to exclude this from checkout
1041
+ send = true;
1042
+ simpleCart.each(settings.excludeFromCheckout, function (field_name) {
1043
+ if (field_name === attr) { send = false; }
1044
+ });
1045
+ if (send) {
1046
+ options_list.push(attr + ": " + val);
1047
+ }
1048
+ });
1049
+
1050
+ // add the options to the description
1051
+ data['item_description_' + counter] = options_list.join(", ");
1052
+ });
1053
+
1054
+ // return the data for the checkout form
1055
+ return {
1056
+ action : action
1057
+ , method : method
1058
+ , data : data
1059
+ };
1060
+
1061
+
1062
+ },
1063
+
1064
+
1065
+ AmazonPayments: function (opts) {
1066
+ // required options
1067
+ if (!opts.merchant_signature) {
1068
+ return simpleCart.error("No merchant signature provided for Amazon Payments");
1069
+ }
1070
+ if (!opts.merchant_id) {
1071
+ return simpleCart.error("No merchant id provided for Amazon Payments");
1072
+ }
1073
+ if (!opts.aws_access_key_id) {
1074
+ return simpleCart.error("No AWS access key id provided for Amazon Payments");
1075
+ }
1076
+
1077
+
1078
+ // build basic form options
1079
+ var data = {
1080
+ aws_access_key_id: opts.aws_access_key_id
1081
+ , merchant_signature: opts.merchant_signature
1082
+ , currency_code: simpleCart.currency().code
1083
+ , tax_rate: simpleCart.taxRate()
1084
+ , weight_unit: opts.weight_unit || 'lb'
1085
+ },
1086
+ action = "https://payments" + (opts.sandbox ? "-sandbox" : "") + ".amazon.com/checkout/" + opts.merchant_id,
1087
+ method = opts.method === "GET" ? "GET" : "POST";
1088
+
1089
+
1090
+ // add items to data
1091
+ simpleCart.each(function (item,x) {
1092
+ var counter = x+1,
1093
+ options_list = [];
1094
+ data['item_title_' + counter] = item.get('name');
1095
+ data['item_quantity_' + counter] = item.quantity();
1096
+ data['item_price_' + counter] = item.price();
1097
+ data['item_sku_ ' + counter] = item.get('sku') || item.id();
1098
+ data['item_merchant_id_' + counter] = opts.merchant_id;
1099
+ if (item.get('weight')) {
1100
+ data['item_weight_' + counter] = item.get('weight');
1101
+ }
1102
+ if (settings.shippingQuantityRate) {
1103
+ data['shipping_method_price_per_unit_rate_' + counter] = settings.shippingQuantityRate;
1104
+ }
1105
+
1106
+
1107
+ // create array of extra options
1108
+ simpleCart.each(item.options(), function (val,x,attr) {
1109
+ // check to see if we need to exclude this from checkout
1110
+ var send = true;
1111
+ simpleCart.each(settings.excludeFromCheckout, function (field_name) {
1112
+ if (field_name === attr) { send = false; }
1113
+ });
1114
+ if (send && attr !== 'weight' && attr !== 'tax') {
1115
+ options_list.push(attr + ": " + val);
1116
+ }
1117
+ });
1118
+
1119
+ // add the options to the description
1120
+ data['item_description_' + counter] = options_list.join(", ");
1121
+ });
1122
+
1123
+ // return the data for the checkout form
1124
+ return {
1125
+ action : action
1126
+ , method : method
1127
+ , data : data
1128
+ };
1129
+
1130
+ },
1131
+
1132
+
1133
+ SendForm: function (opts) {
1134
+ // url required
1135
+ if (!opts.url) {
1136
+ return simpleCart.error('URL required for SendForm Checkout');
1137
+ }
1138
+
1139
+ // build basic form options
1140
+ var data = {
1141
+ currency : simpleCart.currency().code
1142
+ , shipping : simpleCart.shipping()
1143
+ , tax : simpleCart.tax()
1144
+ , taxRate : simpleCart.taxRate()
1145
+ , itemCount : simpleCart.find({}).length
1146
+ },
1147
+ action = opts.url,
1148
+ method = opts.method === "GET" ? "GET" : "POST";
1149
+
1150
+
1151
+ // add items to data
1152
+ simpleCart.each(function (item,x) {
1153
+ var counter = x+1,
1154
+ options_list = [],
1155
+ send;
1156
+ data['item_name_' + counter] = item.get('name');
1157
+ data['item_quantity_' + counter] = item.quantity();
1158
+ data['item_price_' + counter] = item.price();
1159
+
1160
+ // create array of extra options
1161
+ simpleCart.each(item.options(), function (val,x,attr) {
1162
+ // check to see if we need to exclude this from checkout
1163
+ send = true;
1164
+ simpleCart.each(settings.excludeFromCheckout, function (field_name) {
1165
+ if (field_name === attr) { send = false; }
1166
+ });
1167
+ if (send) {
1168
+ options_list.push(attr + ": " + val);
1169
+ }
1170
+ });
1171
+
1172
+ // add the options to the description
1173
+ data['item_options_' + counter] = options_list.join(", ");
1174
+ });
1175
+
1176
+
1177
+ // check for return and success URLs in the options
1178
+ if (opts.success) {
1179
+ data['return'] = opts.success;
1180
+ }
1181
+ if (opts.cancel) {
1182
+ data.cancel_return = opts.cancel;
1183
+ }
1184
+
1185
+ if (opts.extra_data) {
1186
+ data = simpleCart.extend(data,opts.extra_data);
1187
+ }
1188
+
1189
+ // return the data for the checkout form
1190
+ return {
1191
+ action : action
1192
+ , method : method
1193
+ , data : data
1194
+ };
1195
+ }
1196
+
1197
+
1198
+ });
1199
+
1200
+
1201
+ /*******************************************************************
1202
+ * EVENT MANAGEMENT
1203
+ *******************************************************************/
1204
+ eventFunctions = {
1205
+
1206
+ // bind a callback to an event
1207
+ bind: function (name, callback) {
1208
+ if (!isFunction(callback)) {
1209
+ return this;
1210
+ }
1211
+
1212
+ if (!this._events) {
1213
+ this._events = {};
1214
+ }
1215
+
1216
+ // split by spaces to allow for multiple event bindings at once
1217
+ var eventNameList = name.split(/ +/);
1218
+
1219
+ // iterate through and bind each event
1220
+ simpleCart.each( eventNameList , function( eventName ){
1221
+ if (this._events[eventName] === true) {
1222
+ callback.apply(this);
1223
+ } else if (!isUndefined(this._events[eventName])) {
1224
+ this._events[eventName].push(callback);
1225
+ } else {
1226
+ this._events[eventName] = [callback];
1227
+ }
1228
+ });
1229
+
1230
+
1231
+ return this;
1232
+ },
1233
+
1234
+ // trigger event
1235
+ trigger: function (name, options) {
1236
+ var returnval = true,
1237
+ x,
1238
+ xlen;
1239
+
1240
+ if (!this._events) {
1241
+ this._events = {};
1242
+ }
1243
+ if (!isUndefined(this._events[name]) && isFunction(this._events[name][0])) {
1244
+ for (x = 0, xlen = this._events[name].length; x < xlen; x += 1) {
1245
+ returnval = this._events[name][x].apply(this, (options || []));
1246
+ }
1247
+ }
1248
+ if (returnval === false) {
1249
+ return false;
1250
+ }
1251
+ return true;
1252
+ }
1253
+
1254
+ };
1255
+ // alias for bind
1256
+ eventFunctions.on = eventFunctions.bind;
1257
+ simpleCart.extend(eventFunctions);
1258
+ simpleCart.extend(simpleCart.Item._, eventFunctions);
1259
+
1260
+
1261
+ // base simpleCart events in options
1262
+ baseEvents = {
1263
+ beforeAdd : null
1264
+ , afterAdd : null
1265
+ , load : null
1266
+ , beforeSave : null
1267
+ , afterSave : null
1268
+ , update : null
1269
+ , ready : null
1270
+ , checkoutSuccess : null
1271
+ , checkoutFail : null
1272
+ , beforeCheckout : null
1273
+ , beforeRemove : null
1274
+ };
1275
+
1276
+ // extend with base events
1277
+ simpleCart(baseEvents);
1278
+
1279
+ // bind settings to events
1280
+ simpleCart.each(baseEvents, function (val, x, name) {
1281
+ simpleCart.bind(name, function () {
1282
+ if (isFunction(settings[name])) {
1283
+ settings[name].apply(this, arguments);
1284
+ }
1285
+ });
1286
+ });
1287
+
1288
+ /*******************************************************************
1289
+ * FORMATTING FUNCTIONS
1290
+ *******************************************************************/
1291
+ simpleCart.extend({
1292
+ toCurrency: function (number,opts) {
1293
+ var num = parseFloat(number),
1294
+ opt_input = opts || {},
1295
+ _opts = simpleCart.extend(simpleCart.extend({
1296
+ symbol: "$"
1297
+ , decimal: "."
1298
+ , delimiter: ","
1299
+ , accuracy: 2
1300
+ , after: false
1301
+ }, simpleCart.currency()), opt_input),
1302
+
1303
+ numParts = num.toFixed(_opts.accuracy).split("."),
1304
+ dec = numParts[1],
1305
+ ints = numParts[0];
1306
+
1307
+ ints = simpleCart.chunk(ints.reverse(), 3).join(_opts.delimiter.reverse()).reverse();
1308
+
1309
+ return (!_opts.after ? _opts.symbol : "") +
1310
+ ints +
1311
+ (dec ? _opts.decimal + dec : "") +
1312
+ (_opts.after ? _opts.symbol : "");
1313
+
1314
+ },
1315
+
1316
+
1317
+ // break a string in blocks of size n
1318
+ chunk: function (str, n) {
1319
+ if (typeof n==='undefined') {
1320
+ n=2;
1321
+ }
1322
+ var result = str.match(new RegExp('.{1,' + n + '}','g'));
1323
+ return result || [];
1324
+ }
1325
+
1326
+ });
1327
+
1328
+
1329
+ // reverse string function
1330
+ String.prototype.reverse = function () {
1331
+ return this.split("").reverse().join("");
1332
+ };
1333
+
1334
+
1335
+ // currency functions
1336
+ simpleCart.extend({
1337
+ currency: function (currency) {
1338
+ if (isString(currency) && !isUndefined(currencies[currency])) {
1339
+ settings.currency = currency;
1340
+ } else if (isObject(currency)) {
1341
+ currencies[currency.code] = currency;
1342
+ settings.currency = currency.code;
1343
+ } else {
1344
+ return currencies[settings.currency];
1345
+ }
1346
+ }
1347
+ });
1348
+
1349
+
1350
+ /*******************************************************************
1351
+ * VIEW MANAGEMENT
1352
+ *******************************************************************/
1353
+
1354
+ simpleCart.extend({
1355
+ // bind outlets to function
1356
+ bindOutlets: function (outlets) {
1357
+ simpleCart.each(outlets, function (callback, x, selector) {
1358
+
1359
+ simpleCart.bind('update', function () {
1360
+ simpleCart.setOutlet("." + namespace + "_" + selector, callback);
1361
+ });
1362
+ });
1363
+ },
1364
+
1365
+ // set function return to outlet
1366
+ setOutlet: function (selector, func) {
1367
+ var val = func.call(simpleCart, selector);
1368
+ if (isObject(val) && val.el) {
1369
+ simpleCart.$(selector).html(' ').append(val);
1370
+ } else if (!isUndefined(val)) {
1371
+ simpleCart.$(selector).html(val);
1372
+ }
1373
+ },
1374
+
1375
+ // bind click events on inputs
1376
+ bindInputs: function (inputs) {
1377
+ simpleCart.each(inputs, function (info) {
1378
+ simpleCart.setInput("." + namespace + "_" + info.selector, info.event, info.callback);
1379
+ });
1380
+ },
1381
+
1382
+ // attach events to inputs
1383
+ setInput: function (selector, event, func) {
1384
+ simpleCart.$(selector).live(event, func);
1385
+ }
1386
+ });
1387
+
1388
+
1389
+ // class for wrapping DOM selector shit
1390
+ simpleCart.ELEMENT = function (selector) {
1391
+
1392
+ this.create(selector);
1393
+ this.selector = selector || null; // "#" + this.attr('id'); TODO: test length?
1394
+ };
1395
+
1396
+ simpleCart.extend(selectorFunctions, {
1397
+
1398
+ "MooTools" : {
1399
+ text: function (text) {
1400
+ return this.attr(_TEXT_, text);
1401
+ },
1402
+ html: function (html) {
1403
+ return this.attr(_HTML_, html);
1404
+ },
1405
+ val: function (val) {
1406
+ return this.attr(_VALUE_, val);
1407
+ },
1408
+ attr: function (attr, val) {
1409
+ if (isUndefined(val)) {
1410
+ return this.el[0] && this.el[0].get(attr);
1411
+ }
1412
+
1413
+ this.el.set(attr, val);
1414
+ return this;
1415
+ },
1416
+ remove: function () {
1417
+ this.el.dispose();
1418
+ return null;
1419
+ },
1420
+ addClass: function (klass) {
1421
+ this.el.addClass(klass);
1422
+ return this;
1423
+ },
1424
+ removeClass: function (klass) {
1425
+ this.el.removeClass(klass);
1426
+ return this;
1427
+ },
1428
+ append: function (item) {
1429
+ this.el.adopt(item.el);
1430
+ return this;
1431
+ },
1432
+ each: function (callback) {
1433
+ if (isFunction(callback)) {
1434
+ simpleCart.each(this.el, function( e, i, c) {
1435
+ callback.call( i, i, e, c );
1436
+ });
1437
+ }
1438
+ return this;
1439
+ },
1440
+ click: function (callback) {
1441
+ if (isFunction(callback)) {
1442
+ this.each(function (e) {
1443
+ e.addEvent(_CLICK_, function (ev) {
1444
+ callback.call(e,ev);
1445
+ });
1446
+ });
1447
+ } else if (isUndefined(callback)) {
1448
+ this.el.fireEvent(_CLICK_);
1449
+ }
1450
+
1451
+ return this;
1452
+ },
1453
+ live: function ( event,callback) {
1454
+ var selector = this.selector;
1455
+ if (isFunction(callback)) {
1456
+ simpleCart.$("body").el.addEvent(event + ":relay(" + selector + ")", function (e, el) {
1457
+ callback.call(el, e);
1458
+ });
1459
+ }
1460
+ },
1461
+ match: function (selector) {
1462
+ return this.el.match(selector);
1463
+ },
1464
+ parent: function () {
1465
+ return simpleCart.$(this.el.getParent());
1466
+ },
1467
+ find: function (selector) {
1468
+ return simpleCart.$(this.el.getElements(selector));
1469
+ },
1470
+ closest: function (selector) {
1471
+ return simpleCart.$(this.el.getParent(selector));
1472
+ },
1473
+ descendants: function () {
1474
+ return this.find("*");
1475
+ },
1476
+ tag: function () {
1477
+ return this.el[0].tagName;
1478
+ },
1479
+ submit: function (){
1480
+ this.el[0].submit();
1481
+ return this;
1482
+ },
1483
+ create: function (selector) {
1484
+ this.el = $engine(selector);
1485
+ }
1486
+
1487
+
1488
+ },
1489
+
1490
+ "Prototype" : {
1491
+ text: function (text) {
1492
+ if (isUndefined(text)) {
1493
+ return this.el[0].innerHTML;
1494
+ }
1495
+ this.each(function (i,e) {
1496
+ $(e).update(text);
1497
+ });
1498
+ return this;
1499
+ },
1500
+ html: function (html) {
1501
+ return this.text(html);
1502
+ },
1503
+ val: function (val) {
1504
+ return this.attr(_VALUE_, val);
1505
+ },
1506
+ attr: function (attr, val) {
1507
+ if (isUndefined(val)) {
1508
+ return this.el[0].readAttribute(attr);
1509
+ }
1510
+ this.each(function (i,e) {
1511
+ $(e).writeAttribute(attr, val);
1512
+ });
1513
+ return this;
1514
+ },
1515
+ append: function (item) {
1516
+ this.each(function (i,e) {
1517
+ if (item.el) {
1518
+ item.each(function (i2,e2) {
1519
+ $(e).appendChild(e2);
1520
+ });
1521
+ } else if (isElement(item)) {
1522
+ $(e).appendChild(item);
1523
+ }
1524
+ });
1525
+ return this;
1526
+ },
1527
+ remove: function () {
1528
+ this.each(function (i, e) {
1529
+ $(e).remove();
1530
+ });
1531
+ return this;
1532
+ },
1533
+ addClass: function (klass) {
1534
+ this.each(function (i, e) {
1535
+ $(e).addClassName(klass);
1536
+ });
1537
+ return this;
1538
+ },
1539
+ removeClass: function (klass) {
1540
+ this.each(function (i, e) {
1541
+ $(e).removeClassName(klass);
1542
+ });
1543
+ return this;
1544
+ },
1545
+ each: function (callback) {
1546
+ if (isFunction(callback)) {
1547
+ simpleCart.each(this.el, function( e, i, c) {
1548
+ callback.call( i, i, e, c );
1549
+ });
1550
+ }
1551
+ return this;
1552
+ },
1553
+ click: function (callback) {
1554
+ if (isFunction(callback)) {
1555
+ this.each(function (i, e) {
1556
+ $(e).observe(_CLICK_, function (ev) {
1557
+ callback.call(e,ev);
1558
+ });
1559
+ });
1560
+ } else if (isUndefined(callback)) {
1561
+ this.each(function (i, e) {
1562
+ $(e).fire(_CLICK_);
1563
+ });
1564
+ }
1565
+ return this;
1566
+ },
1567
+ live: function (event,callback) {
1568
+ if (isFunction(callback)) {
1569
+ var selector = this.selector;
1570
+ document.observe(event, function (e, el) {
1571
+ if (el === $engine(e).findElement(selector)) {
1572
+ callback.call(el, e);
1573
+ }
1574
+ });
1575
+ }
1576
+ },
1577
+ parent: function () {
1578
+ return simpleCart.$(this.el.up());
1579
+ },
1580
+ find: function (selector) {
1581
+ return simpleCart.$(this.el.getElementsBySelector(selector));
1582
+ },
1583
+ closest: function (selector) {
1584
+ return simpleCart.$(this.el.up(selector));
1585
+ },
1586
+ descendants: function () {
1587
+ return simpleCart.$(this.el.descendants());
1588
+ },
1589
+ tag: function () {
1590
+ return this.el.tagName;
1591
+ },
1592
+ submit: function() {
1593
+ this.el[0].submit();
1594
+ },
1595
+
1596
+ create: function (selector) {
1597
+ if (isString(selector)) {
1598
+ this.el = $engine(selector);
1599
+ } else if (isElement(selector)) {
1600
+ this.el = [selector];
1601
+ }
1602
+ }
1603
+
1604
+
1605
+
1606
+ },
1607
+
1608
+ "jQuery": {
1609
+ passthrough: function (action, val) {
1610
+ if (isUndefined(val)) {
1611
+ return this.el[action]();
1612
+ }
1613
+
1614
+ this.el[action](val);
1615
+ return this;
1616
+ },
1617
+ text: function (text) {
1618
+ return this.passthrough(_TEXT_, text);
1619
+ },
1620
+ html: function (html) {
1621
+ return this.passthrough(_HTML_, html);
1622
+ },
1623
+ val: function (val) {
1624
+ return this.passthrough("val", val);
1625
+ },
1626
+ append: function (item) {
1627
+ var target = item.el || item;
1628
+ this.el.append(target);
1629
+ return this;
1630
+ },
1631
+ attr: function (attr, val) {
1632
+ if (isUndefined(val)) {
1633
+ return this.el.attr(attr);
1634
+ }
1635
+ this.el.attr(attr, val);
1636
+ return this;
1637
+ },
1638
+ remove: function () {
1639
+ this.el.remove();
1640
+ return this;
1641
+ },
1642
+ addClass: function (klass) {
1643
+ this.el.addClass(klass);
1644
+ return this;
1645
+ },
1646
+ removeClass: function (klass) {
1647
+ this.el.removeClass(klass);
1648
+ return this;
1649
+ },
1650
+ each: function (callback) {
1651
+ return this.passthrough('each', callback);
1652
+ },
1653
+ click: function (callback) {
1654
+ return this.passthrough(_CLICK_, callback);
1655
+ },
1656
+ live: function (event, callback) {
1657
+ $engine(document).delegate(this.selector, event, callback);
1658
+ return this;
1659
+ },
1660
+ parent: function () {
1661
+ return simpleCart.$(this.el.parent());
1662
+ },
1663
+ find: function (selector) {
1664
+ return simpleCart.$(this.el.find(selector));
1665
+ },
1666
+ closest: function (selector) {
1667
+ return simpleCart.$(this.el.closest(selector));
1668
+ },
1669
+ tag: function () {
1670
+ return this.el[0].tagName;
1671
+ },
1672
+ descendants: function () {
1673
+ return simpleCart.$(this.el.find("*"));
1674
+ },
1675
+ submit: function() {
1676
+ return this.el.submit();
1677
+ },
1678
+
1679
+ create: function (selector) {
1680
+ this.el = $engine(selector);
1681
+ }
1682
+ }
1683
+ });
1684
+ simpleCart.ELEMENT._ = simpleCart.ELEMENT.prototype;
1685
+
1686
+ // bind the DOM setup to the ready event
1687
+ simpleCart.ready(simpleCart.setupViewTool);
1688
+
1689
+ // bind the input and output events
1690
+ simpleCart.ready(function () {
1691
+ simpleCart.bindOutlets({
1692
+ total: function () {
1693
+ return simpleCart.toCurrency(simpleCart.total());
1694
+ }
1695
+ , quantity: function () {
1696
+ return simpleCart.quantity();
1697
+ }
1698
+ , items: function (selector) {
1699
+ simpleCart.writeCart(selector);
1700
+ }
1701
+ , tax: function () {
1702
+ return simpleCart.toCurrency(simpleCart.tax());
1703
+ }
1704
+ , taxRate: function () {
1705
+ return simpleCart.taxRate().toFixed();
1706
+ }
1707
+ , shipping: function () {
1708
+ return simpleCart.toCurrency(simpleCart.shipping());
1709
+ }
1710
+ , grandTotal: function () {
1711
+ return simpleCart.toCurrency(simpleCart.grandTotal());
1712
+ }
1713
+ });
1714
+ simpleCart.bindInputs([
1715
+ { selector: 'checkout'
1716
+ , event: 'click'
1717
+ , callback: function () {
1718
+ simpleCart.checkout();
1719
+ }
1720
+ }
1721
+ , { selector: 'empty'
1722
+ , event: 'click'
1723
+ , callback: function () {
1724
+ simpleCart.empty();
1725
+ }
1726
+ }
1727
+ , { selector: 'increment'
1728
+ , event: 'click'
1729
+ , callback: function () {
1730
+ simpleCart.find(simpleCart.$(this).closest('.itemRow').attr('id').split("_")[1]).increment();
1731
+ simpleCart.update();
1732
+ }
1733
+ }
1734
+ , { selector: 'decrement'
1735
+ , event: 'click'
1736
+ , callback: function () {
1737
+ simpleCart.find(simpleCart.$(this).closest('.itemRow').attr('id').split("_")[1]).decrement();
1738
+ simpleCart.update();
1739
+ }
1740
+ }
1741
+ /* remove from cart */
1742
+ , { selector: 'remove'
1743
+ , event: 'click'
1744
+ , callback: function () {
1745
+ simpleCart.find(simpleCart.$(this).closest('.itemRow').attr('id').split("_")[1]).remove();
1746
+ }
1747
+ }
1748
+
1749
+ /* cart inputs */
1750
+ , { selector: 'input'
1751
+ , event: 'change'
1752
+ , callback: function () {
1753
+ var $input = simpleCart.$(this),
1754
+ $parent = $input.parent(),
1755
+ classList = $parent.attr('class').split(" ");
1756
+ simpleCart.each(classList, function (klass) {
1757
+ if (klass.match(/item-.+/i)) {
1758
+ var field = klass.split("-")[1];
1759
+ simpleCart.find($parent.closest('.itemRow').attr('id').split("_")[1]).set(field,$input.val());
1760
+ simpleCart.update();
1761
+ return;
1762
+ }
1763
+ });
1764
+ }
1765
+ }
1766
+
1767
+ /* here is our shelfItem add to cart button listener */
1768
+ , { selector: 'shelfItem .item_add'
1769
+ , event: 'click'
1770
+ , callback: function () {
1771
+ var $button = simpleCart.$(this),
1772
+ fields = {};
1773
+
1774
+ $button.closest("." + namespace + "_shelfItem").descendants().each(function (x,item) {
1775
+ var $item = simpleCart.$(item);
1776
+
1777
+ // check to see if the class matches the item_[fieldname] pattern
1778
+ if ($item.attr("class") &&
1779
+ $item.attr("class").match(/item_.+/) &&
1780
+ !$item.attr('class').match(/item_add/)) {
1781
+
1782
+ // find the class name
1783
+ simpleCart.each($item.attr('class').split(' '), function (klass) {
1784
+ var attr,
1785
+ val,
1786
+ type;
1787
+
1788
+ // get the value or text depending on the tagName
1789
+ if (klass.match(/item_.+/)) {
1790
+ attr = klass.split("_")[1];
1791
+ val = "";
1792
+ switch($item.tag().toLowerCase()) {
1793
+ case "input":
1794
+ case "textarea":
1795
+ case "select":
1796
+ type = $item.attr("type");
1797
+ if (!type || ((type.toLowerCase() === "checkbox" || type.toLowerCase() === "radio") && $item.attr("checked")) || type.toLowerCase() === "text" || type.toLowerCase() === "number") {
1798
+ val = $item.val();
1799
+ }
1800
+ break;
1801
+ case "img":
1802
+ val = $item.attr('src');
1803
+ break;
1804
+ default:
1805
+ val = $item.text();
1806
+ break;
1807
+ }
1808
+
1809
+ if (val !== null && val !== "") {
1810
+ fields[attr.toLowerCase()] = fields[attr.toLowerCase()] ? fields[attr.toLowerCase()] + ", " + val : val;
1811
+ }
1812
+ }
1813
+ });
1814
+ }
1815
+ });
1816
+
1817
+ // add the item
1818
+ simpleCart.add(fields);
1819
+ }
1820
+ }
1821
+ ]);
1822
+ });
1823
+
1824
+
1825
+ /*******************************************************************
1826
+ * DOM READY
1827
+ *******************************************************************/
1828
+ // Cleanup functions for the document ready method
1829
+ // used from jQuery
1830
+ /*global DOMContentLoaded */
1831
+ if (document.addEventListener) {
1832
+ window.DOMContentLoaded = function () {
1833
+ document.removeEventListener("DOMContentLoaded", DOMContentLoaded, false);
1834
+ simpleCart.init();
1835
+ };
1836
+
1837
+ } else if (document.attachEvent) {
1838
+ window.DOMContentLoaded = function () {
1839
+ // Make sure body exists, at least, in case IE gets a little overzealous (ticket #5443).
1840
+ if (document.readyState === "complete") {
1841
+ document.detachEvent("onreadystatechange", DOMContentLoaded);
1842
+ simpleCart.init();
1843
+ }
1844
+ };
1845
+ }
1846
+ // The DOM ready check for Internet Explorer
1847
+ // used from jQuery
1848
+ function doScrollCheck() {
1849
+ if (simpleCart.isReady) {
1850
+ return;
1851
+ }
1852
+
1853
+ try {
1854
+ // If IE is used, use the trick by Diego Perini
1855
+ // http://javascript.nwbox.com/IEContentLoaded/
1856
+ document.documentElement.doScroll("left");
1857
+ } catch (e) {
1858
+ setTimeout(doScrollCheck, 1);
1859
+ return;
1860
+ }
1861
+
1862
+ // and execute any waiting functions
1863
+ simpleCart.init();
1864
+ }
1865
+
1866
+ // bind ready event used from jquery
1867
+ function sc_BindReady () {
1868
+
1869
+ // Catch cases where $(document).ready() is called after the
1870
+ // browser event has already occurred.
1871
+ if (document.readyState === "complete") {
1872
+ // Handle it asynchronously to allow scripts the opportunity to delay ready
1873
+ return setTimeout(simpleCart.init, 1);
1874
+ }
1875
+
1876
+ // Mozilla, Opera and webkit nightlies currently support this event
1877
+ if (document.addEventListener) {
1878
+ // Use the handy event callback
1879
+ document.addEventListener("DOMContentLoaded", DOMContentLoaded, false);
1880
+
1881
+ // A fallback to window.onload, that will always work
1882
+ window.addEventListener("load", simpleCart.init, false);
1883
+
1884
+ // If IE event model is used
1885
+ } else if (document.attachEvent) {
1886
+ // ensure firing before onload,
1887
+ // maybe late but safe also for iframes
1888
+ document.attachEvent("onreadystatechange", DOMContentLoaded);
1889
+
1890
+ // A fallback to window.onload, that will always work
1891
+ window.attachEvent("onload", simpleCart.init);
1892
+
1893
+ // If IE and not a frame
1894
+ // continually check to see if the document is ready
1895
+ var toplevel = false;
1896
+
1897
+ try {
1898
+ toplevel = window.frameElement === null;
1899
+ } catch (e) {}
1900
+
1901
+ if (document.documentElement.doScroll && toplevel) {
1902
+ doScrollCheck();
1903
+ }
1904
+ }
1905
+ }
1906
+
1907
+ // bind the ready event
1908
+ sc_BindReady();
1909
+
1910
+ return simpleCart;
1911
+ };
1912
+
1913
+
1914
+ window.simpleCart = generateSimpleCart();
1915
+
1916
+ }(window, document));
1917
+
1918
+ /************ JSON *************/
1919
+ var JSON;JSON||(JSON={});
1920
+ (function () {function k(a) {return a<10?"0"+a:a}function o(a) {p.lastIndex=0;return p.test(a)?'"'+a.replace(p,function (a) {var c=r[a];return typeof c==="string"?c:"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)})+'"':'"'+a+'"'}function l(a,j) {var c,d,h,m,g=e,f,b=j[a];b&&typeof b==="object"&&typeof b.toJSON==="function"&&(b=b.toJSON(a));typeof i==="function"&&(b=i.call(j,a,b));switch(typeof b) {case "string":return o(b);case "number":return isFinite(b)?String(b):"null";case "boolean":case "null":return String(b);case "object":if (!b)return"null";
1921
+ e += n;f=[];if (Object.prototype.toString.apply(b)==="[object Array]") {m=b.length;for (c=0;c<m;c += 1)f[c]=l(c,b)||"null";h=f.length===0?"[]":e?"[\n"+e+f.join(",\n"+e)+"\n"+g+"]":"["+f.join(",")+"]";e=g;return h}if (i&&typeof i==="object") {m=i.length;for (c=0;c<m;c += 1)typeof i[c]==="string"&&(d=i[c],(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h))}else for (d in b)Object.prototype.hasOwnProperty.call(b,d)&&(h=l(d,b))&&f.push(o(d)+(e?": ":":")+h);h=f.length===0?"{}":e?"{\n"+e+f.join(",\n"+e)+"\n"+g+"}":"{"+f.join(",")+
1922
+ "}";e=g;return h}}if (typeof Date.prototype.toJSON!=="function")Date.prototype.toJSON=function () {return isFinite(this.valueOf())?this.getUTCFullYear()+"-"+k(this.getUTCMonth()+1)+"-"+k(this.getUTCDate())+"T"+k(this.getUTCHours())+":"+k(this.getUTCMinutes())+":"+k(this.getUTCSeconds())+"Z":null},String.prototype.toJSON=Number.prototype.toJSON=Boolean.prototype.toJSON=function () {return this.valueOf()};var q=/[\u0000\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,
1923
+ p=/[\\\"\x00-\x1f\x7f-\x9f\u00ad\u0600-\u0604\u070f\u17b4\u17b5\u200c-\u200f\u2028-\u202f\u2060-\u206f\ufeff\ufff0-\uffff]/g,e,n,r={"\u0008":"\\b","\t":"\\t","\n":"\\n","\u000c":"\\f","\r":"\\r",'"':'\\"',"\\":"\\\\"},i;if (typeof JSON.stringify!=="function")JSON.stringify=function (a,j,c) {var d;n=e="";if (typeof c==="number")for (d=0;d<c;d += 1)n += " ";else typeof c==="string"&&(n=c);if ((i=j)&&typeof j!=="function"&&(typeof j!=="object"||typeof j.length!=="number"))throw Error("JSON.stringify");return l("",
1924
+ {"":a})};if (typeof JSON.parse!=="function")JSON.parse=function (a,e) {function c(a,d) {var g,f,b=a[d];if (b&&typeof b==="object")for (g in b)Object.prototype.hasOwnProperty.call(b,g)&&(f=c(b,g),f!==void 0?b[g]=f:delete b[g]);return e.call(a,d,b)}var d,a=String(a);q.lastIndex=0;q.test(a)&&(a=a.replace(q,function (a) {return"\\u"+("0000"+a.charCodeAt(0).toString(16)).slice(-4)}));if (/^[\],:{}\s]*$/.test(a.replace(/\\(?:["\\\/bfnrt]|u[0-9a-fA-F]{4})/g,"@").replace(/"[^"\\\n\r]*"|true|false|null|-?\d+(?:\.\d*)?(?:[eE][+\-]?\d+)?/g,
1925
+ "]").replace(/(?:^|:|,)(?:\s*\[)+/g,"")))return d=eval("("+a+")"),typeof e==="function"?c({"":d},""):d;throw new SyntaxError("JSON.parse");}})();
1926
+
1927
+
1928
+ /************ HTML5 Local Storage Support *************/
1929
+ (function () {if (!this.localStorage)if (this.globalStorage)try {this.localStorage=this.globalStorage}catch(e) {}else{var a=document.createElement("div");a.style.display="none";document.getElementsByTagName("head")[0].appendChild(a);if (a.addBehavior) {a.addBehavior("#default#userdata");var d=this.localStorage={length:0,setItem:function (b,d) {a.load("localStorage");b=c(b);a.getAttribute(b)||this.length++;a.setAttribute(b,d);a.save("localStorage")},getItem:function (b) {a.load("localStorage");b=c(b);return a.getAttribute(b)},
1930
+ removeItem:function (b) {a.load("localStorage");b=c(b);a.removeAttribute(b);a.save("localStorage");this.length=0},clear:function () {a.load("localStorage");for (var b=0;attr=a.XMLDocument.documentElement.attributes[b++];)a.removeAttribute(attr.name);a.save("localStorage");this.length=0},key:function (b) {a.load("localStorage");return a.XMLDocument.documentElement.attributes[b]}},c=function (a) {return a.replace(/[^-._0-9A-Za-z\xb7\xc0-\xd6\xd8-\xf6\xf8-\u037d\u37f-\u1fff\u200c-\u200d\u203f\u2040\u2070-\u218f]/g,
1931
+ "-")};a.load("localStorage");d.length=a.XMLDocument.documentElement.attributes.length}}})();