Advertisement
Cnikkanen

Modified simplecart.js

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