simplecart-rails 0.0.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -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}}})();