diff --git a/.gitignore b/.gitignore
index 1c3e58b..6d6a912 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1,3 +1,4 @@
-node_modules
.DS_Store
-*.log
\ No newline at end of file
+.idea
+node_modules
+_site
\ No newline at end of file
diff --git a/.jshintrc b/.jshintrc
deleted file mode 100644
index 0013810..0000000
--- a/.jshintrc
+++ /dev/null
@@ -1,68 +0,0 @@
-{
- "passfail": false,
- "maxerr": 100,
-
-
- "browser": true,
- "node": false,
- "rhino": false,
- "couch": false,
- "wsh": false,
-
- "jquery": false,
- "prototypejs": false,
- "mootools": false,
- "dojo": false,
-
- "predef": [],
-
- "debug": false,
- "devel": false,
-
- "es5": true,
- "strict": true,
- "globalstrict": false,
-
- "asi": false,
- "laxbreak": false,
- "bitwise": false,
- "boss": true,
- "curly": true,
- "eqeqeq": true,
- "eqnull": false,
- "evil": false,
- "expr": true,
- "forin": false,
- "immed": true,
- "latedef": false,
- "loopfunc": false,
- "noarg": false,
- "regexp": false,
- "regexdash": false,
- "scripturl": false,
- "shadow": false,
- "supernew": false,
- "undef": true,
- "validthis": false,
- "smarttabs": true,
- "proto": false,
- "onecase": false,
- "nonstandard": false,
- "multistr": false,
- "laxcomma": false,
- "lastsemic": false,
- "iterator": false,
- "funcscope": false,
- "esnext": false,
-
- "newcap": false,
- "noempty": false,
- "nonew": false,
- "nomen": false,
- "onevar": false,
- "plusplus": false,
- "sub": false,
- "trailing": true,
- "white": true,
- "indent": 4
-}
\ No newline at end of file
diff --git a/CNAME b/CNAME
new file mode 100644
index 0000000..1b23dff
--- /dev/null
+++ b/CNAME
@@ -0,0 +1 @@
+minicartjs.com
diff --git a/Gemfile b/Gemfile
new file mode 100644
index 0000000..3a1ebf3
--- /dev/null
+++ b/Gemfile
@@ -0,0 +1,2 @@
+source 'https://rubygems.org'
+gem 'github-pages'
\ No newline at end of file
diff --git a/Gemfile.lock b/Gemfile.lock
new file mode 100644
index 0000000..60d0d12
--- /dev/null
+++ b/Gemfile.lock
@@ -0,0 +1,58 @@
+GEM
+ remote: https://rubygems.org/
+ specs:
+ RedCloth (4.2.9)
+ classifier (1.3.3)
+ fast-stemmer (>= 1.0.0)
+ colorator (0.1)
+ commander (4.1.5)
+ highline (~> 1.6.11)
+ fast-stemmer (1.0.2)
+ ffi (1.9.3)
+ github-pages (11)
+ RedCloth (= 4.2.9)
+ jekyll (= 1.3.1)
+ kramdown (= 1.2.0)
+ liquid (= 2.5.4)
+ maruku (= 0.6.1)
+ rdiscount (= 2.1.7)
+ redcarpet (= 2.3.0)
+ highline (1.6.20)
+ jekyll (1.3.1)
+ classifier (~> 1.3)
+ colorator (~> 0.1)
+ commander (~> 4.1.3)
+ liquid (~> 2.5.2)
+ listen (~> 1.3)
+ maruku (~> 0.6.0)
+ pygments.rb (~> 0.5.0)
+ redcarpet (~> 2.3.0)
+ safe_yaml (~> 0.9.7)
+ kramdown (1.2.0)
+ liquid (2.5.4)
+ listen (1.3.1)
+ rb-fsevent (>= 0.9.3)
+ rb-inotify (>= 0.9)
+ rb-kqueue (>= 0.2)
+ maruku (0.6.1)
+ syntax (>= 1.0.0)
+ posix-spawn (0.3.6)
+ pygments.rb (0.5.4)
+ posix-spawn (~> 0.3.6)
+ yajl-ruby (~> 1.1.0)
+ rb-fsevent (0.9.3)
+ rb-inotify (0.9.2)
+ ffi (>= 0.5.0)
+ rb-kqueue (0.2.0)
+ ffi (>= 0.5.0)
+ rdiscount (2.1.7)
+ redcarpet (2.3.0)
+ safe_yaml (0.9.7)
+ syntax (1.0.0)
+ yajl-ruby (1.1.0)
+
+PLATFORMS
+ ruby
+
+DEPENDENCIES
+ github-pages
diff --git a/LICENSE b/LICENSE
deleted file mode 100644
index ee4dd86..0000000
--- a/LICENSE
+++ /dev/null
@@ -1,7 +0,0 @@
-Copyright (c) 2013 Jeff Harrell
-
-Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the "Software"), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
-
-The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
-
-THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
\ No newline at end of file
diff --git a/README.md b/README.md
index 7a4c6b9..18b76db 100644
--- a/README.md
+++ b/README.md
@@ -1,228 +1,248 @@
-The Mini Cart
-=============
+# Minicart.js
-The Mini Cart is a great way to improve your PayPal integration by creating an overlay which appears as a user adds products to their cart. It’s a simple change that creates a wonderful new experience for your website!
+[](https://travis-ci.org/jeffharrell/minicart)
+The minicart is a great way to improve your PayPal shopping cart integration. One simple change and your users will be able to manage their shopping cart directly from your website. Additional APIs provide you the power to customize the behavior to your needs.
-1. [Setup](#interested-let%E2%80%99s-get-you-setup)
-2. [Customization](#customization)
-3. [Event callback examples](#event-callback-examples)
-4. [Localization](#localization)
-5. [JavaScript API](#javascript-api)
+
+1. [Basic Setup](#basic-setup)
+2. [Advanced API](#advanced-api)
+3. [API Examples](#api-examples)
+4. [Customization](#customization)
+5. [Localization](#localization)
6. [FAQ](#faq)
-7. [Questions or comments](#questions-or-comments)
-Interested? Let’s get you setup
--------------------------------
+## Basic Setup
+
+1. Create a PayPal [Add to Cart Button](https://www.paypal.com/cgi-bin/webscr?cmd=p/xcl/web-accept-to-sc-button-outside)
+2. Include the following snippet into your HTML before the closing </body> tag:
-1. Start with a PayPal [Add to Cart Button](https://www.paypal.com/cgi-bin/webscr?cmd=p/xcl/web-accept-to-sc-button-outside)
-2. Download the latest [minicart.js](https://raw.github.com/jeffharrell/MiniCart/master/dist/minicart.min.js) – You can also browse the [tagged versions](https://github.com/jeffharrell/MiniCart/tags)
-3. Next, include the following snippet of JavaScript code into your HTML file before the closing </body> tag
+ ```html
+
+
+ ```
-Make sure to update the path to point to your downloaded copy of minicart.js!
+3. On your return page include:
-
+ ```html
+ ```
-It’s as simple as that! Now the Mini Cart will appear when a user adds a product to, views, or has an item in their cart.
+It's that simple! Now the minicart will appear when a user views or adds a product to their cart.
-Customization
--------------
+## Advanced API
-You can customize the script to make it work for your site by passing a JavaScript object as an argument, setting any of the following optional properties:
+The minicart has a JavaScript API for advanced users to customize the behavior.
-`parent`
-The HTMLElement the Mini Cart should render as a child of. Default document.body.
-`formTarget`
-The HTML target property for the checkout form.
+### General
-`displayEdge`
-The edge of the page the cart should pin to. Set to left or right. Default right.
+`paypal.minicart.render(config)`
+Renders the minicart to the page. Config is optional and can have the following properties:
-`edgeDistance`
-Distance from the edge the cart should appear. Default 50px.
+ * `parent` - HTMLElement the minicart should render to.
+ * `target` - HTML target property for the checkout form.
+ * `action` - PayPal URL (if you are accessing sandbox or another version of the PayPal website).
+ * `template` - HTML template for rendering. See [customization](#customization) for details.
+ * `styles` - CSS styles for rendering. See [customization](#customization) for details.
+ * `strings` - An object of text strings: `button`, `buttonAlt`, `subtotal` and `discount`.
-`cookiePath`
-The base path of your website to set the cookie to (useful for shared website hosting)
+`paypal.minicart.reset()`
+Resets the minicart back to its default state.
-`peekEnabled`
-Boolean to determine if the cart should "peek" when it's hidden with items. Default true.
-`paypalURL`
-The PayPal URL to use if you are accessing sandbox or another version of the PayPal website. Defaults to https://www.paypal.com/cgi-bin/webscr.
+### View
-`strings`
-An object of localizable text strings used:
+`paypal.minicart.view.show()`
+Triggers the minicart to show by adding a "minicart-showing" CSS class to the document.
-* `button` - The checkout button text
-* `subtotal` - The subtotal text
-* `discount` - The discount text
-* `shipping` - The shipping text
+`paypal.minicart.view.hide()`
+Triggers the minicart to hide by removing the "minicart-showing" CSS class on the document.
-`events`
-An object of customizable callbacks (see [Event callback examples](#event-callback-examples)):
+`paypal.minicart.view.toggle()`
+Toggles the visibility of the minicart.
-* `onRender` - Event before the cart is rendered
-* `afterRender` - Event after the cart is rendered
-* `onHide` - Event before the cart is hidden
-* `afterHide` - Event after the cart is hidden
-* `onShow` - Event before the cart is shown
-* `afterShow` - Event after the cart is shown
-* `onAddToCart` - Event before a product is added to the cart
-* `afterAddToCart` - Event after a product is added to the cart
-* `onRemoveFromCart` - Event before a product is removed from the cart
-* `afterRemoveFromCart` - Event after a product is removed from the cart
-* `onCheckout` - Event before the checkout action takes place
-* `onReset` - Event before the cart is emptied (typically when a transaction is completed)
-* `afterReset` - Event after the cart is emptied (typically when a transaction is completed)
+`paypal.minicart.view.bind(form)`
+Binds an HTMLFormElement's submit event to the minicart. Useful for forms which may have been added to the page after the initial load.
-The scope of all events is adjusted to the Mini Cart to allow access to the products, UI, and certain functions. See below for an example of a custom configuration:
-
+### Cart
+`paypal.minicart.cart.add(data)`
+Adds an item to the cart. Fires the *add* event. Example data object:
+ { "business": "user@example.com", "item_name": "Product", "amount": 5.00, "currency_code": "USD" }
-Event callback examples
------------------------
+`paypal.minicart.cart.remove(idx)`
+Removes an item from the cart by index. Fires the *remove* event.
-Examples of how you can use the event callbacks:
+`paypal.minicart.cart.items(idx)`
+Returns an array of items from the cart. If an index is passed then only that item is returned.
-* [Preventing checkout until terms are accepted](http://www.minicartjs.com/examples/terms.html)
-* [Requiring a minimum quantity to checkout](http://www.minicartjs.com/examples/minquantity.html)
-* [Only allowing a fixed quantity per item](http://www.minicartjs.com/examples/fixedquantity.html)
-* [Supporting multiple options per item](http://www.minicartjs.com/examples/options.html)
+`paypal.minicart.cart.settings(key)`
+Returns an object of global cart settings. If a key is passed then only that value is returned.
+`paypal.minicart.cart.discount(config)`
+Calculates the cart discount amount. *config* can be used for formatting.
+`paypal.minicart.cart.subtotal(config)`
+Calculates the cart total minus discounts. *config* can be used for formatting.
-Localization
-------------
+`paypal.minicart.cart.total(config)`
+Calculates the cart total. *config* can be used for formatting.
-Localization and adaption are supported in the Mini Cart using the configuration strings object. For example, if we wanted the cart to appear in French we would need to pass our configuration like this:
+`paypal.minicart.cart.destroy()`
+Destroys the cart data and resets it back to the default state. Fires the *destroy* event.
-
+`paypal.minicart.cart.on(event, fn, scope)`
+Subscribe to cart events. Events include:
+ * `add` - Fired when an item is added. *function (idx, product, isExisting)*
+ * `remove` - Fired when an item is removed. *function (idx, product)*
+ * `checkout` - Fired on checkout. *function (evt)*
+ * `destroy` - Fired when the cart is destroyed. *function ()*
+
+`paypal.minicart.cart.off(event, fn)`
+Unsubscribe from cart events.
+
+
+### Products
+
+`product.get(key)`
+Returns a properties object for the product. If a key is passed then only that value is returned.
+
+`product.set(key, value)`
+Sets a property for the product. Fires a *change* event.
+
+`product.options()`
+Returns the options.
+
+`product.discount(config)`
+Calculates the product discount. *config* can be used for formatting.
+
+`product.amount(config)`
+Calculates the product amount discounts. *config* can be used for formatting.
+
+`product.total(config)`
+Calculates the product total. *config* can be used for formatting.
+
+`product.isEqual(product2)`
+Determines if the current product is the same as another.
-The currency symbol will be automatically adjusted based on the currency_code setting of your button.
+`product.destroy()`
+Destroys the product. Fires the *destroy* event.
+`product.on(event, fn, scope)`
+Subscribe to cart events. Events include:
+ * `change` - Fired when a value is changed. *function (key)*
+ * `destroy` - Fired when the product is destroyed. *function ()*
+`product.off(event, fn)`
+Unsubscribe from product events.
-JavaScript API
---------------
-The Mini Cart has a rich JavaScript API which allows you to control it using the following methods:
+## API Examples
-`PAYPAL.apps.MiniCart.render()`
-Renders the cart element to the page. This method is required to see the Mini Cart.
+Examples of how you can use the API:
-`PAYPAL.apps.MiniCart.bindForm(form)`
-Binds a form DOM element's submit event to the Mini Cart. This is useful for forms which may have been added to the page after the initial load.
+* [Preventing checkout until terms are accepted](https://github.com/jeffharrell/minicart/blob/master/examples/terms.html)
+* [Requiring a minimum quantity to checkout](https://github.com/jeffharrell/minicart/blob/master/examples/minquantity.html)
+* [Only allowing a fixed quantity per item](https://github.com/jeffharrell/minicart/blob/master/examples/fixedquantity.html)
+* [Ensuring an option is selected](https://github.com/jeffharrell/minicart/blob/master/examples/notempty.html)
-`PAYPAL.apps.MiniCart.addToCart(data)`
-Allows you to manually add a product to your cart, e.g. directly using JavaScript and not through a PayPal form. The parameter `data` is a key / value pair object of parameters and their value. For example:
- {"business":"user@example.com","item_name":"Product","amount":"5.00","currency_code":"USD"}
+## Customization
-`PAYPAL.apps.MiniCart.reset()`
-Resets the cart, emptying and hiding it.
+The minicart HTML template and CSS can be fully customized using two different approaches: configuration and custom themes. In both approaches, all functionality from the [API](#advanced-api) is available using [Embedded JavaScript Template](https://github.com/visionmedia/ejs) syntax.
-`PAYPAL.apps.MiniCart.hide(null, fully)`
-Hides the cart. If the cart contains products then it will "peek" from the top of the window. Set the parameter `fully` to true to override this and have it fully hidden.
-`PAYPAL.apps.MiniCart.show()`
-Shows the cart.
+### Configuration
-`PAYPAL.apps.MiniCart.toggle()`
-Toggles the visibility of the cart.
+The HTML template and CSS can be overridden using the *config* object.
+```js
+var myTemplate = "
";
+paypal.minicart.render({
+ template: myTemplate
+});
+```
-FAQ
----
+### Custom Themes
-### Is the Mini Cart free? How is it licensed?
-Yes, it’s free and licensed under the [MIT License](https://github.com/jeffharrell/MiniCart/raw/master/LICENSE).
+Custom themes can be created and bundled into your own custom version of the minicart.js file.
-### What browsers does the Mini Cart support?
-The Mini Cart is functionally supported by Chrome, Safari, Firefox, Opera, and Internet Explorer 6+. Older versions of IE use cookies for their data store while all other browsers use localStorage.
+Before creating a custom theme you'll need to have [node.js](http://nodejs.org/) installed. Once install is complete, open a terminal window and run `npm install -g grunt-cli` to install Grunt.
-### I have special integration / translation needs. Are there advanced settings?
-Yes, there’s a rich API which can be used to customize the Mini Cart. See the [project page README](https://github.com/jeffharrell/MiniCart#readme) for more details.
+To create a theme follow these steps:
-### I found a bug / I have an issue!
-Please log the issue on the [Mini Cart’s issue tracker](https://github.com/jeffharrell/MiniCart/issues), including a link or sample code that reproduces it if possible.
+1. [Fork and clone this repo](https://github.com/jeffharrell/minicart/fork) so you can make your own changes. If you're not sure what this means you can find out more on [Github's Help](https://help.github.com/articles/fork-a-repo).
+2. In your new fork, create a directory under `src/themes` with your theme name. For example, let's create `src/themes/myAwesomeTheme`.
+3. Next add your HTML template into `src/themes/myAwesomeTheme/index.html`. The templates use [Embedded JavaScript Template](https://github.com/visionmedia/ejs) syntax for logic.
+4. Finally add your CSS styles into `src/themes/myAwesomeTheme/styles.css`.
+5. With all that behind you it's now time to generate your custom minicart JavaScript file. In a terminal window run `grunt build --theme=myAwesomeTheme`. This will output a bundled JavaScript file complete with the minicart and your new theme at `dist/minicart.myAwesomeTheme.js`.
+6. Include this file into your HTML page instead of the normal JavaScript file and you'll see your new theme!
-### I made a change and want to integrate it back into the Mini Cart!
-Awesome! Thanks for helping out. Please fork the Mini Cart code on Github. Once you're done with the change you can submit a pull request back to me. If everything looks good and the change is beneficial all I will integrate it.
+If you're new to the building a theme it's a good idea to copy the one at `src/themes/default` and start there.
-### I installed the Mini Cart, but my website still redirects to PayPal when clicking on a button. Why?
-There's two causes for this. The first is quite easy and it's that you have inserted the Mini Cart JavaScript in the document head or at the top of your page. It needs to be inserted before the closing body element so that it can "see" the PayPal forms.
-The other cause is that the Mini Cart doesn’t yet work with what PayPal’s call their “hosted” or “encrypted” buttons which is why this is most likely happening. To fix your buttons, you’ll need to log into paypal.com and do the following steps:
-1. Create a button on PayPal’s website and uncheck the Save button at PayPal checkbox under Step 2: Track inventory, profit & loss.
-2. Once you’ve created the button click Remove code protection before copying your button’s code.
+## Localization
-### The Mini Cart isn’t emptying after a transaction is completed. Why?
-The Mini Cart appends a fragment to your button’s return URL which sends a command to it when the user successfully returns from a transaction. If this is not working properly you should make sure that your are setting the value correctly and that it does not already contain a fragment.
+Localization is supported using the *strings* object.
-### Is non-JavaScript supported?
-If your users do not have a JavaScript-capable browser, they will still be able to see your cart buttons and make purchases, but the user interface will gracefully degrade to the standard PayPal Cart.
+```js
+paypal.minicart.render({
+ strings: {
+ button: "Caisse",
+ buttonAlt: "Total:",
+ discount: "Reduction:"
+ }
+});
+```
-### My website uses frames / iframes for it’s products. How can I make the Mini Cart work?
-Depending upon how your site is setup the Mini Cart isn’t always compatible with websites containing frames. To ensure that it works you need to have the product buttons on the same frame as the main window.
+The currency symbol will be automatically updated based on the *currency_code* setting of your button.
-### The Mini Cart isn’t appearing the same as on this page. Why?
-This can occur if your page is being rendered in the browser’s [Quirks mode](http://en.wikipedia.org/wiki/Quirks_mode). Example issues include appearing in the bottom left of the browser, not scrolling properly, or having rendering issues. To check for this issue, validate and correct your HTML markup using the [W3C Markup Validator](http://validator.w3.org/).
-### The Mini Cart is appearing behind objects on my page!
-This happens when you have the position and z-index CSS properties set on an element. If you need to use z-index then you will need to add the following code to your CSS styles:
- #PPMiniCart { position: relative; z-index: 100; }
-and set the value to correspond with your code.
+## FAQ
-### I don't like the way the Mini Cart looks / How can I customize the Mini Cart more?
-The Mini Cart CSS is delivered as part of the code and shouldn't be changed. There are some values which can be changed via the config, e.g. the offset or position, but otherwise you'll need to override the Mini Cart's CSS in your own CSS using a higher CSS specificity.
+### Is the minicart free? How is it licensed?
+Yes, it's free and licensed under the [MIT License](https://github.com/jeffharrell/MiniCart/raw/master/LICENSE).
-Here's an example of changing the Mini Cart height so that it grows as products are added:
+### Which browsers are supported?
+The minicart supports Chrome, Safari, Firefox, and Internet Explorer 8+.
- #myPage #PPMiniCart ul { height: auto; min-height: 130px; max-height: 500px; }
+### I made a change and want to contribute it. Do you accept pull requests?
+Yes, absolutely! Please submit a pull request on Github.
-Note that using an additional id of #myPage in your CSS causes the rule to be more specific than the Mini Cart's and the bowser renders that instead.
+### Help, I found a bug!
+Please submit the issue on the [issue tracker](https://github.com/jeffharrell/MiniCart/issues) including a link or sample code to reproduce it.
+### The minicart isn't appearing the same as on this page. Why?
+This can occur if your page is being rendered in [quirks mode](http://en.wikipedia.org/wiki/Quirks_mode). You can check for this issue, validate and correct your HTML using the [W3C Markup Validator](http://validator.w3.org/).
+### I installed the minicart, but my website still redirects to PayPal. Why?
+The minicart doesn't work with PayPal's hosted buttons. To fix your buttons go to paypal.com and:
-Questions or comments
----------------------
+1. Create a button on PayPal's website and uncheck the *Save button at PayPal* checkbox under *Step 2: Track inventory, profit & loss*.
+2. Once you've created the button click *Remove code protection* before copying your button code.
-If you have questions or suggestions, please use the [issue tracker](https://github.com/jeffharrell/MiniCart/issues) at Github.
+If this isn't the case then you may have a JavaScript error on the page. Open the browser debugger console and see if there are any errors.
+### The minicart isn't emptying after a transaction is completed. Why?
+Your buttons need to contain a *return* parameter with a URL for PayPal to redirect back to on completion. On this page make sure to call `paypal.minicart.reset();`.
+### Does the minicart work with frames?
+Frames are not officially supported. You may be able to get some mileage with the *target* configuration setting.
+### Are previous versions of the minicart available?
+All previous versions are [tagged on Github](https://github.com/jeffharrell/MiniCart/tags).
diff --git a/_config.yml b/_config.yml
new file mode 100644
index 0000000..73942c2
--- /dev/null
+++ b/_config.yml
@@ -0,0 +1,3 @@
+markdown: redcarpet
+redcarpet:
+ extensions: [with_toc_data]
diff --git a/_layouts/index.html b/_layouts/index.html
new file mode 100644
index 0000000..4106b6f
--- /dev/null
+++ b/_layouts/index.html
@@ -0,0 +1,173 @@
+
+
+
+
+
+ Minicart.js - The minicart is a great way to improve your PayPal shopping cart integration
+
+
+
+
+
+
+
+
+
+
+
+
Try it out with the example below.
+
+
+
+
+
+
+
+
+
+
+
+
+
+ {{ content }}
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/bin/npm-debug.log b/bin/npm-debug.log
new file mode 100644
index 0000000..a4e02bc
--- /dev/null
+++ b/bin/npm-debug.log
@@ -0,0 +1,22 @@
+0 info it worked if it ends with ok
+1 verbose cli [ '/Users/jeff/.nvm/v0.10.22/bin/node',
+1 verbose cli '/Users/jeff/.nvm/v0.10.22/bin/npm',
+1 verbose cli 'version',
+1 verbose cli '3.0.2' ]
+2 info using npm@1.3.14
+3 info using node@v0.10.22
+4 error version No package.json found
+5 error Error: ENOENT, open '/Users/jeff/Sites/minicartjs.com/bin/package.json'
+6 error If you need help, you may report this log at:
+6 error
+6 error or email it to:
+6 error
+7 error System Darwin 13.0.0
+8 error command "/Users/jeff/.nvm/v0.10.22/bin/node" "/Users/jeff/.nvm/v0.10.22/bin/npm" "version" "3.0.2"
+9 error cwd /Users/jeff/Sites/minicartjs.com/bin
+10 error node -v v0.10.22
+11 error npm -v 1.3.14
+12 error path /Users/jeff/Sites/minicartjs.com/bin/package.json
+13 error code ENOENT
+14 error errno 34
+15 verbose exit [ 34, true ]
diff --git a/build/images/arrow_down.gif b/build/images/arrow_down.gif
new file mode 100644
index 0000000..5032864
Binary files /dev/null and b/build/images/arrow_down.gif differ
diff --git a/build/images/arrow_up.gif b/build/images/arrow_up.gif
new file mode 100644
index 0000000..9867cac
Binary files /dev/null and b/build/images/arrow_up.gif differ
diff --git a/build/images/button_submit.gif b/build/images/button_submit.gif
new file mode 100644
index 0000000..2c62693
Binary files /dev/null and b/build/images/button_submit.gif differ
diff --git a/build/images/minicart_sprite.png b/build/images/minicart_sprite.png
new file mode 100644
index 0000000..db76719
Binary files /dev/null and b/build/images/minicart_sprite.png differ
diff --git a/build/images/paypal_logo.gif b/build/images/paypal_logo.gif
new file mode 100644
index 0000000..e46180c
Binary files /dev/null and b/build/images/paypal_logo.gif differ
diff --git a/build/images/x.gif b/build/images/x.gif
new file mode 100644
index 0000000..5900e29
Binary files /dev/null and b/build/images/x.gif differ
diff --git a/css/code.css b/css/code.css
new file mode 100644
index 0000000..51143cf
--- /dev/null
+++ b/css/code.css
@@ -0,0 +1,76 @@
+pre {
+ background-color: #eee;
+ padding: 10px;
+ -webkit-border-radius: 5px;
+ -moz-border-radius: 5px;
+ border-radius: 5px;
+ overflow: auto;
+}
+code {
+ background-color: #eee;
+ padding: 1px 3px;
+ -webkit-border-radius: 2px;
+ -moz-border-radius: 2px;
+ border-radius: 2px;
+ word-wrap: break-word;
+}
+
+.hll { background-color: #ffffff }
+.c { color: #888888; font-style: italic } /* Comment */
+.err { color: #a61717; background-color: #e3d2d2 } /* Error */
+.k { color: #000000; font-weight: bold } /* Keyword */
+.cm { color: #888888 } /* Comment.Multiline */
+.cp { color: #cc0000; font-weight: bold } /* Comment.Preproc */
+.c1 { color: #888888 } /* Comment.Single */
+.cs { color: #cc0000; font-weight: bold; } /* Comment.Special */
+.gd { color: #000000; background-color: #ffdddd } /* Generic.Deleted */
+.ge { font-style: italic } /* Generic.Emph */
+.gr { color: #aa0000 } /* Generic.Error */
+.gh { color: #303030 } /* Generic.Heading */
+.gi { color: #000000; background-color: #ddffdd } /* Generic.Inserted */
+.go { color: #888888 } /* Generic.Output */
+.gp { color: #555555 } /* Generic.Prompt */
+.gs { font-weight: bold } /* Generic.Strong */
+.gu { color: #606060 } /* Generic.Subheading */
+.gt { color: #aa0000 } /* Generic.Traceback */
+.highlight .kc{font-weight:bold;} /* Keyword.Constant */
+.highlight .kd{font-weight:bold;} /* Keyword.Declaration */
+.highlight .kn{font-weight:bold;} /* Keyword.Namespace */
+.highlight .kp{font-weight:bold;} /* Keyword.Pseudo */
+.highlight .kr{font-weight:bold;} /* Keyword.Reserved */
+.highlight .kt{color:#458;font-weight:bold;} /* Keyword.Type */
+.m { color: #0000DD; font-weight: bold } /* Literal.Number */
+.s { color: #dd2200; } /* Literal.String */
+.highlight .na{color:#008080;} /* Name.Attribute */
+.highlight .nb{color:#0086B3;} /* Name.Builtin */
+.highlight .nc{color:#458;font-weight:bold;} /* Name.Class */
+.highlight .no{color:#008080;} /* Name.Constant */
+.highlight .ni{color:#800080;}
+.highlight .ne{color:#900;font-weight:bold;} /* Name.Exception */
+.highlight .nf{color:#900;font-weight:bold;} /* Name.Function */
+.highlight .nn{color:#005;font-weight:bold;} /* Name.Namespace */
+.highlight .nt{color:#000080;} /* Name.Tag */
+.highlight .nv{color:#008080;} /* Name.Variable */
+.py { color: #336699; font-weight: bold } /* Name.Property */
+.ow { color: #008800 } /* Operator.Word */
+.w { color: #bbbbbb } /* Text.Whitespace */
+.mf { color: #0000DD; font-weight: bold } /* Literal.Number.Float */
+.mh { color: #0000DD; font-weight: bold } /* Literal.Number.Hex */
+.highlight .mi {color:#099;} /* Literal.Number.Integer */
+.mo { color: #0000DD; font-weight: bold } /* Literal.Number.Oct */
+.sb { color: #dd2200; } /* Literal.String.Backtick */
+.highlight .sc{color:#d14;} /* Literal.String.Char */
+.sd { color: #dd2200; } /* Literal.String.Doc */
+.highlight .s2{color:#d14;} /* Literal.String.Double */
+.highlight .se{color:#d14;} /* Literal.String.Escape */
+.highlight .sh{color:#d14;} /* Literal.String.Heredoc */
+.highlight .si{color:#d14;} /* Literal.String.Interpol */
+.highlight .sx{color:#d14;} /* Literal.String.Other */
+.highlight .sr{color:#d14;} /* Literal.String.Regex */
+.highlight .s1{color:#d14;} /* Literal.String.Single */
+.highlight .ss{color:#d14;} /* Literal.String.Symbol */
+.bp { color: #003388 } /* Name.Builtin.Pseudo */
+.vc { color: #336699 } /* Name.Variable.Class */
+.vg { color: #dd7700 } /* Name.Variable.Global */
+.vi { color: #3333bb } /* Name.Variable.Instance */
+.il { color: #0000DD; font-weight: bold } /* Literal.Number.Integer.Long */
\ No newline at end of file
diff --git a/css/minicart.css b/css/minicart.css
new file mode 100644
index 0000000..6d43f92
--- /dev/null
+++ b/css/minicart.css
@@ -0,0 +1,160 @@
+body {
+ margin: 0;
+ padding: 0;
+ background: #fff;
+ color: #333;
+ font: 100%/normal "HelveticaNeue-Light", "Helvetica Neue Light", "Helvetica Neue", Helvetica, Arial, sans-serif;
+}
+
+h1 {
+ margin: 1em 0;
+ font-size: 2.75em;
+ font-weight: normal;
+}
+
+h2 {
+ margin: 2em 0 1em;
+ font-size: 1.5em;
+}
+
+h3 {
+ margin: 2em 0 0;
+ padding: 0 0 0.25em;
+ font-size: 1.2em;
+}
+
+a {
+ color: #084482;
+ text-decoration: underline;
+}
+
+p {
+ margin: 1em 0;
+}
+
+ul {
+ margin: 1em 0;
+ padding: 0 0 0 3em;
+ list-style-type: disc;
+}
+
+ol {
+ margin: 1em 0 1em 2em;
+ padding: 0;
+}
+
+ol li {
+ margin: 0 0 0.5em;
+}
+
+
+footer {
+ padding: 1em 0;
+}
+
+a img {
+ border: 0;
+}
+
+a:hover {
+ text-decoration: none;
+}
+
+#wrapper {
+ margin: 0 auto;
+}
+
+#header, #example, #readme, #footer {
+ padding: 40px;
+}
+
+#header, #example {
+ background: #32689A;
+ color: #fff;
+}
+
+#header a, #example a {
+ color: #fff;
+}
+
+#header ol {
+ margin: 3em 0 1em 4em;
+}
+
+#header img {
+ display: none;
+}
+
+#example {
+ margin-top: -60px;
+}
+
+#example ul {
+ list-style-type: none;
+ padding: 0;
+ line-height: 1.9em;
+}
+
+#example form {
+ float: left;
+ padding: 10px 10px 10px 15px;
+}
+
+#example form strong {
+ font-size: 1.167em;
+ font-weight: bold;
+}
+
+#example form.last {
+ margin: 0;
+ border: 0;
+}
+
+#example fieldset {
+ position: relative;
+ min-width: 9em;
+ height: 9em;
+ margin: 0;
+ padding: 10px;
+ background: #5a85ad;
+ border: 0;
+ border-radius: 8px;
+}
+
+#example fieldset .button {
+ position: absolute;
+ bottom: 10px;
+}
+
+#example .container {
+ overflow: auto;
+ display: block;
+ width: 100%;
+ padding: 10px 0;
+}
+
+#footer {
+ margin-top: 50px;
+ padding-top: 10px;
+ text-align: center;
+}
+
+.loading * {
+ display: none !important;
+}
+
+
+
+@media only screen and (max-width : 568px) {
+
+ #header, #example, #readme, #footer {
+ padding-left: 10px;
+ padding-right: 10px;
+ }
+
+ #example .container {
+ height: 10.5em;
+ overflow: hidden;
+ }
+
+}
\ No newline at end of file
diff --git a/dist/minicart.js b/dist/minicart.js
index 56b2a89..0ad4c3b 100644
--- a/dist/minicart.js
+++ b/dist/minicart.js
@@ -1,2224 +1,3020 @@
/*!
- * MiniCart
+ * minicart
+ * The Mini Cart is a great way to improve your PayPal shopping cart integration.
*
+ * @version 3.0.6
* @author Jeff Harrell
- * @license MIT
+ * @url http://www.minicartjs.com/
+ * @license MIT
*/
-if (typeof PAYPAL === 'undefined' || !PAYPAL) {
- var PAYPAL = {};
+
+;(function e(t,n,r){function s(o,u){if(!n[o]){if(!t[o]){var a=typeof require=="function"&&require;if(!u&&a)return a(o,!0);if(i)return i(o,!0);throw new Error("Cannot find module '"+o+"'")}var f=n[o]={exports:{}};t[o][0].call(f.exports,function(e){var n=t[o][1][e];return s(n?n:e)},f,f.exports,e,t,n,r)}return n[o].exports}var i=typeof require=="function"&&require;for(var o=0;o i; ++i) {
+ if (array.hasOwnProperty(i)) {
+ if (isValueSet) {
+ value = callback(value, array[i], i, array);
+ }
+ else {
+ value = array[i];
+ isValueSet = true;
+ }
+ }
+ }
+
+ return value;
+};
+
+// String.prototype.substr - negative index don't work in IE8
+if ('ab'.substr(-1) !== 'b') {
+ exports.substr = function (str, start, length) {
+ // did we get a negative start, calculate how much it is from the beginning of the string
+ if (start < 0) start = str.length + start;
+
+ // call the original function
+ return str.substr(start, length);
+ };
+} else {
+ exports.substr = function (str, start, length) {
+ return str.substr(start, length);
+ };
+}
+
+// String.prototype.trim is supported in IE9
+exports.trim = function (str) {
+ if (str.trim) return str.trim();
+ return str.replace(/^\s+|\s+$/g, '');
+};
+
+// Function.prototype.bind is supported in IE9
+exports.bind = function () {
+ var args = Array.prototype.slice.call(arguments);
+ var fn = args.shift();
+ if (fn.bind) return fn.bind.apply(fn, args);
+ var self = args.shift();
+ return function () {
+ fn.apply(self, args.concat([Array.prototype.slice.call(arguments)]));
+ };
+};
+
+// Object.create is supported in IE9
+function create(prototype, properties) {
+ var object;
+ if (prototype === null) {
+ object = { '__proto__' : null };
+ }
+ else {
+ if (typeof prototype !== 'object') {
+ throw new TypeError(
+ 'typeof prototype[' + (typeof prototype) + '] != \'object\''
+ );
+ }
+ var Type = function () {};
+ Type.prototype = prototype;
+ object = new Type();
+ object.__proto__ = prototype;
+ }
+ if (typeof properties !== 'undefined' && Object.defineProperties) {
+ Object.defineProperties(object, properties);
+ }
+ return object;
+}
+exports.create = typeof Object.create === 'function' ? Object.create : create;
+
+// Object.keys and Object.getOwnPropertyNames is supported in IE9 however
+// they do show a description and number property on Error objects
+function notObject(object) {
+ return ((typeof object != "object" && typeof object != "function") || object === null);
+}
+
+function keysShim(object) {
+ if (notObject(object)) {
+ throw new TypeError("Object.keys called on a non-object");
+ }
+
+ var result = [];
+ for (var name in object) {
+ if (hasOwnProperty.call(object, name)) {
+ result.push(name);
+ }
+ }
+ return result;
+}
+
+// getOwnPropertyNames is almost the same as Object.keys one key feature
+// is that it returns hidden properties, since that can't be implemented,
+// this feature gets reduced so it just shows the length property on arrays
+function propertyShim(object) {
+ if (notObject(object)) {
+ throw new TypeError("Object.getOwnPropertyNames called on a non-object");
+ }
+
+ var result = keysShim(object);
+ if (exports.isArray(object) && exports.indexOf(object, 'length') === -1) {
+ result.push('length');
+ }
+ return result;
+}
+
+var keys = typeof Object.keys === 'function' ? Object.keys : keysShim;
+var getOwnPropertyNames = typeof Object.getOwnPropertyNames === 'function' ?
+ Object.getOwnPropertyNames : propertyShim;
+
+if (new Error().hasOwnProperty('description')) {
+ var ERROR_PROPERTY_FILTER = function (obj, array) {
+ if (toString.call(obj) === '[object Error]') {
+ array = exports.filter(array, function (name) {
+ return name !== 'description' && name !== 'number' && name !== 'message';
+ });
+ }
+ return array;
+ };
+
+ exports.keys = function (object) {
+ return ERROR_PROPERTY_FILTER(object, keys(object));
+ };
+ exports.getOwnPropertyNames = function (object) {
+ return ERROR_PROPERTY_FILTER(object, getOwnPropertyNames(object));
+ };
+} else {
+ exports.keys = keys;
+ exports.getOwnPropertyNames = getOwnPropertyNames;
+}
+
+// Object.getOwnPropertyDescriptor - supported in IE8 but only on dom elements
+function valueObject(value, key) {
+ return { value: value[key] };
+}
+
+if (typeof Object.getOwnPropertyDescriptor === 'function') {
+ try {
+ Object.getOwnPropertyDescriptor({'a': 1}, 'a');
+ exports.getOwnPropertyDescriptor = Object.getOwnPropertyDescriptor;
+ } catch (e) {
+ // IE8 dom element issue - use a try catch and default to valueObject
+ exports.getOwnPropertyDescriptor = function (value, key) {
+ try {
+ return Object.getOwnPropertyDescriptor(value, key);
+ } catch (e) {
+ return valueObject(value, key);
+ }
+ };
+ }
+} else {
+ exports.getOwnPropertyDescriptor = valueObject;
+}
+
+},{}],2:[function(require,module,exports){
+
+// not implemented
+// The reason for having an empty file and not throwing is to allow
+// untraditional implementation of this module.
+
+},{}],3:[function(require,module,exports){
+var process=require("__browserify_process");// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var util = require('util');
+var shims = require('_shims');
+
+// resolves . and .. elements in a path array with directory names there
+// must be no slashes, empty elements, or device names (c:\) in the array
+// (so also no leading and trailing slashes - it does not distinguish
+// relative and absolute paths)
+function normalizeArray(parts, allowAboveRoot) {
+ // if the path tries to go above the root, `up` ends up > 0
+ var up = 0;
+ for (var i = parts.length - 1; i >= 0; i--) {
+ var last = parts[i];
+ if (last === '.') {
+ parts.splice(i, 1);
+ } else if (last === '..') {
+ parts.splice(i, 1);
+ up++;
+ } else if (up) {
+ parts.splice(i, 1);
+ up--;
+ }
+ }
+
+ // if the path is allowed to go above the root, restore leading ..s
+ if (allowAboveRoot) {
+ for (; up--; up) {
+ parts.unshift('..');
+ }
+ }
+
+ return parts;
+}
+
+// Split a filename into [root, dir, basename, ext], unix version
+// 'root' is just a slash, or nothing.
+var splitPathRe =
+ /^(\/?|)([\s\S]*?)((?:\.{1,2}|[^\/]+?|)(\.[^.\/]*|))(?:[\/]*)$/;
+var splitPath = function(filename) {
+ return splitPathRe.exec(filename).slice(1);
+};
+
+// path.resolve([from ...], to)
+// posix version
+exports.resolve = function() {
+ var resolvedPath = '',
+ resolvedAbsolute = false;
+
+ for (var i = arguments.length - 1; i >= -1 && !resolvedAbsolute; i--) {
+ var path = (i >= 0) ? arguments[i] : process.cwd();
+
+ // Skip empty and invalid entries
+ if (!util.isString(path)) {
+ throw new TypeError('Arguments to path.resolve must be strings');
+ } else if (!path) {
+ continue;
+ }
+
+ resolvedPath = path + '/' + resolvedPath;
+ resolvedAbsolute = path.charAt(0) === '/';
+ }
+
+ // At this point the path should be resolved to a full absolute path, but
+ // handle relative paths to be safe (might happen when process.cwd() fails)
+
+ // Normalize the path
+ resolvedPath = normalizeArray(shims.filter(resolvedPath.split('/'), function(p) {
+ return !!p;
+ }), !resolvedAbsolute).join('/');
+
+ return ((resolvedAbsolute ? '/' : '') + resolvedPath) || '.';
+};
+
+// path.normalize(path)
+// posix version
+exports.normalize = function(path) {
+ var isAbsolute = exports.isAbsolute(path),
+ trailingSlash = shims.substr(path, -1) === '/';
+
+ // Normalize the path
+ path = normalizeArray(shims.filter(path.split('/'), function(p) {
+ return !!p;
+ }), !isAbsolute).join('/');
+
+ if (!path && !isAbsolute) {
+ path = '.';
+ }
+ if (path && trailingSlash) {
+ path += '/';
+ }
+
+ return (isAbsolute ? '/' : '') + path;
+};
+
+// posix version
+exports.isAbsolute = function(path) {
+ return path.charAt(0) === '/';
+};
+
+// posix version
+exports.join = function() {
+ var paths = Array.prototype.slice.call(arguments, 0);
+ return exports.normalize(shims.filter(paths, function(p, index) {
+ if (!util.isString(p)) {
+ throw new TypeError('Arguments to path.join must be strings');
+ }
+ return p;
+ }).join('/'));
+};
+
+
+// path.relative(from, to)
+// posix version
+exports.relative = function(from, to) {
+ from = exports.resolve(from).substr(1);
+ to = exports.resolve(to).substr(1);
+
+ function trim(arr) {
+ var start = 0;
+ for (; start < arr.length; start++) {
+ if (arr[start] !== '') break;
+ }
+
+ var end = arr.length - 1;
+ for (; end >= 0; end--) {
+ if (arr[end] !== '') break;
+ }
+
+ if (start > end) return [];
+ return arr.slice(start, end - start + 1);
+ }
+
+ var fromParts = trim(from.split('/'));
+ var toParts = trim(to.split('/'));
+
+ var length = Math.min(fromParts.length, toParts.length);
+ var samePartsLength = length;
+ for (var i = 0; i < length; i++) {
+ if (fromParts[i] !== toParts[i]) {
+ samePartsLength = i;
+ break;
+ }
+ }
+
+ var outputParts = [];
+ for (var i = samePartsLength; i < fromParts.length; i++) {
+ outputParts.push('..');
+ }
+
+ outputParts = outputParts.concat(toParts.slice(samePartsLength));
+
+ return outputParts.join('/');
+};
+
+exports.sep = '/';
+exports.delimiter = ':';
+
+exports.dirname = function(path) {
+ var result = splitPath(path),
+ root = result[0],
+ dir = result[1];
+
+ if (!root && !dir) {
+ // No dirname whatsoever
+ return '.';
+ }
+
+ if (dir) {
+ // It has a dirname, strip trailing slash
+ dir = dir.substr(0, dir.length - 1);
+ }
+
+ return root + dir;
+};
+
+
+exports.basename = function(path, ext) {
+ var f = splitPath(path)[2];
+ // TODO: make this comparison case-insensitive on windows?
+ if (ext && f.substr(-1 * ext.length) === ext) {
+ f = f.substr(0, f.length - ext.length);
+ }
+ return f;
+};
+
+
+exports.extname = function(path) {
+ return splitPath(path)[3];
+};
+
+},{"__browserify_process":5,"_shims":1,"util":4}],4:[function(require,module,exports){
+// Copyright Joyent, Inc. and other Node contributors.
+//
+// Permission is hereby granted, free of charge, to any person obtaining a
+// copy of this software and associated documentation files (the
+// "Software"), to deal in the Software without restriction, including
+// without limitation the rights to use, copy, modify, merge, publish,
+// distribute, sublicense, and/or sell copies of the Software, and to permit
+// persons to whom the Software is furnished to do so, subject to the
+// following conditions:
+//
+// The above copyright notice and this permission notice shall be included
+// in all copies or substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
+// OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
+// MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN
+// NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,
+// DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE
+// USE OR OTHER DEALINGS IN THE SOFTWARE.
+
+var shims = require('_shims');
+
+var formatRegExp = /%[sdj%]/g;
+exports.format = function(f) {
+ if (!isString(f)) {
+ var objects = [];
+ for (var i = 0; i < arguments.length; i++) {
+ objects.push(inspect(arguments[i]));
+ }
+ return objects.join(' ');
+ }
+
+ var i = 1;
+ var args = arguments;
+ var len = args.length;
+ var str = String(f).replace(formatRegExp, function(x) {
+ if (x === '%%') return '%';
+ if (i >= len) return x;
+ switch (x) {
+ case '%s': return String(args[i++]);
+ case '%d': return Number(args[i++]);
+ case '%j':
+ try {
+ return JSON.stringify(args[i++]);
+ } catch (_) {
+ return '[Circular]';
+ }
+ default:
+ return x;
+ }
+ });
+ for (var x = args[i]; i < len; x = args[++i]) {
+ if (isNull(x) || !isObject(x)) {
+ str += ' ' + x;
+ } else {
+ str += ' ' + inspect(x);
+ }
+ }
+ return str;
+};
+
+/**
+ * Echos the value of a value. Trys to print the value out
+ * in the best way possible given the different types.
+ *
+ * @param {Object} obj The object to print out.
+ * @param {Object} opts Optional options object that alters the output.
+ */
+/* legacy: obj, showHidden, depth, colors*/
+function inspect(obj, opts) {
+ // default options
+ var ctx = {
+ seen: [],
+ stylize: stylizeNoColor
+ };
+ // legacy...
+ if (arguments.length >= 3) ctx.depth = arguments[2];
+ if (arguments.length >= 4) ctx.colors = arguments[3];
+ if (isBoolean(opts)) {
+ // legacy...
+ ctx.showHidden = opts;
+ } else if (opts) {
+ // got an "options" object
+ exports._extend(ctx, opts);
+ }
+ // set default options
+ if (isUndefined(ctx.showHidden)) ctx.showHidden = false;
+ if (isUndefined(ctx.depth)) ctx.depth = 2;
+ if (isUndefined(ctx.colors)) ctx.colors = false;
+ if (isUndefined(ctx.customInspect)) ctx.customInspect = true;
+ if (ctx.colors) ctx.stylize = stylizeWithColor;
+ return formatValue(ctx, obj, ctx.depth);
+}
+exports.inspect = inspect;
+
+
+// http://en.wikipedia.org/wiki/ANSI_escape_code#graphics
+inspect.colors = {
+ 'bold' : [1, 22],
+ 'italic' : [3, 23],
+ 'underline' : [4, 24],
+ 'inverse' : [7, 27],
+ 'white' : [37, 39],
+ 'grey' : [90, 39],
+ 'black' : [30, 39],
+ 'blue' : [34, 39],
+ 'cyan' : [36, 39],
+ 'green' : [32, 39],
+ 'magenta' : [35, 39],
+ 'red' : [31, 39],
+ 'yellow' : [33, 39]
+};
+
+// Don't use 'blue' not visible on cmd.exe
+inspect.styles = {
+ 'special': 'cyan',
+ 'number': 'yellow',
+ 'boolean': 'yellow',
+ 'undefined': 'grey',
+ 'null': 'bold',
+ 'string': 'green',
+ 'date': 'magenta',
+ // "name": intentionally not styling
+ 'regexp': 'red'
+};
+
+
+function stylizeWithColor(str, styleType) {
+ var style = inspect.styles[styleType];
+
+ if (style) {
+ return '\u001b[' + inspect.colors[style][0] + 'm' + str +
+ '\u001b[' + inspect.colors[style][1] + 'm';
+ } else {
+ return str;
+ }
+}
+
+
+function stylizeNoColor(str, styleType) {
+ return str;
+}
+
+
+function arrayToHash(array) {
+ var hash = {};
+
+ shims.forEach(array, function(val, idx) {
+ hash[val] = true;
+ });
+
+ return hash;
+}
+
+
+function formatValue(ctx, value, recurseTimes) {
+ // Provide a hook for user-specified inspect functions.
+ // Check that value is an object with an inspect function on it
+ if (ctx.customInspect &&
+ value &&
+ isFunction(value.inspect) &&
+ // Filter out the util module, it's inspect function is special
+ value.inspect !== exports.inspect &&
+ // Also filter out any prototype objects using the circular check.
+ !(value.constructor && value.constructor.prototype === value)) {
+ var ret = value.inspect(recurseTimes);
+ if (!isString(ret)) {
+ ret = formatValue(ctx, ret, recurseTimes);
+ }
+ return ret;
+ }
+
+ // Primitive types cannot have properties
+ var primitive = formatPrimitive(ctx, value);
+ if (primitive) {
+ return primitive;
+ }
+
+ // Look up the keys of the object.
+ var keys = shims.keys(value);
+ var visibleKeys = arrayToHash(keys);
+
+ if (ctx.showHidden) {
+ keys = shims.getOwnPropertyNames(value);
+ }
+
+ // Some type of object without properties can be shortcutted.
+ if (keys.length === 0) {
+ if (isFunction(value)) {
+ var name = value.name ? ': ' + value.name : '';
+ return ctx.stylize('[Function' + name + ']', 'special');
+ }
+ if (isRegExp(value)) {
+ return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+ }
+ if (isDate(value)) {
+ return ctx.stylize(Date.prototype.toString.call(value), 'date');
+ }
+ if (isError(value)) {
+ return formatError(value);
+ }
+ }
+
+ var base = '', array = false, braces = ['{', '}'];
+
+ // Make Array say that they are Array
+ if (isArray(value)) {
+ array = true;
+ braces = ['[', ']'];
+ }
+
+ // Make functions say that they are functions
+ if (isFunction(value)) {
+ var n = value.name ? ': ' + value.name : '';
+ base = ' [Function' + n + ']';
+ }
+
+ // Make RegExps say that they are RegExps
+ if (isRegExp(value)) {
+ base = ' ' + RegExp.prototype.toString.call(value);
+ }
+
+ // Make dates with properties first say the date
+ if (isDate(value)) {
+ base = ' ' + Date.prototype.toUTCString.call(value);
+ }
+
+ // Make error with message first say the error
+ if (isError(value)) {
+ base = ' ' + formatError(value);
+ }
+
+ if (keys.length === 0 && (!array || value.length == 0)) {
+ return braces[0] + base + braces[1];
+ }
+
+ if (recurseTimes < 0) {
+ if (isRegExp(value)) {
+ return ctx.stylize(RegExp.prototype.toString.call(value), 'regexp');
+ } else {
+ return ctx.stylize('[Object]', 'special');
+ }
+ }
+
+ ctx.seen.push(value);
+
+ var output;
+ if (array) {
+ output = formatArray(ctx, value, recurseTimes, visibleKeys, keys);
+ } else {
+ output = keys.map(function(key) {
+ return formatProperty(ctx, value, recurseTimes, visibleKeys, key, array);
+ });
+ }
+
+ ctx.seen.pop();
+
+ return reduceToSingleString(output, base, braces);
+}
+
+
+function formatPrimitive(ctx, value) {
+ if (isUndefined(value))
+ return ctx.stylize('undefined', 'undefined');
+ if (isString(value)) {
+ var simple = '\'' + JSON.stringify(value).replace(/^"|"$/g, '')
+ .replace(/'/g, "\\'")
+ .replace(/\\"/g, '"') + '\'';
+ return ctx.stylize(simple, 'string');
+ }
+ if (isNumber(value))
+ return ctx.stylize('' + value, 'number');
+ if (isBoolean(value))
+ return ctx.stylize('' + value, 'boolean');
+ // For some reason typeof null is "object", so special case here.
+ if (isNull(value))
+ return ctx.stylize('null', 'null');
+}
+
+
+function formatError(value) {
+ return '[' + Error.prototype.toString.call(value) + ']';
+}
+
+
+function formatArray(ctx, value, recurseTimes, visibleKeys, keys) {
+ var output = [];
+ for (var i = 0, l = value.length; i < l; ++i) {
+ if (hasOwnProperty(value, String(i))) {
+ output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+ String(i), true));
+ } else {
+ output.push('');
+ }
+ }
+
+ shims.forEach(keys, function(key) {
+ if (!key.match(/^\d+$/)) {
+ output.push(formatProperty(ctx, value, recurseTimes, visibleKeys,
+ key, true));
+ }
+ });
+ return output;
+}
+
+
+function formatProperty(ctx, value, recurseTimes, visibleKeys, key, array) {
+ var name, str, desc;
+ desc = shims.getOwnPropertyDescriptor(value, key) || { value: value[key] };
+ if (desc.get) {
+ if (desc.set) {
+ str = ctx.stylize('[Getter/Setter]', 'special');
+ } else {
+ str = ctx.stylize('[Getter]', 'special');
+ }
+ } else {
+ if (desc.set) {
+ str = ctx.stylize('[Setter]', 'special');
+ }
+ }
+
+ if (!hasOwnProperty(visibleKeys, key)) {
+ name = '[' + key + ']';
+ }
+ if (!str) {
+ if (shims.indexOf(ctx.seen, desc.value) < 0) {
+ if (isNull(recurseTimes)) {
+ str = formatValue(ctx, desc.value, null);
+ } else {
+ str = formatValue(ctx, desc.value, recurseTimes - 1);
+ }
+ if (str.indexOf('\n') > -1) {
+ if (array) {
+ str = str.split('\n').map(function(line) {
+ return ' ' + line;
+ }).join('\n').substr(2);
+ } else {
+ str = '\n' + str.split('\n').map(function(line) {
+ return ' ' + line;
+ }).join('\n');
+ }
+ }
+ } else {
+ str = ctx.stylize('[Circular]', 'special');
+ }
+ }
+ if (isUndefined(name)) {
+ if (array && key.match(/^\d+$/)) {
+ return str;
+ }
+ name = JSON.stringify('' + key);
+ if (name.match(/^"([a-zA-Z_][a-zA-Z_0-9]*)"$/)) {
+ name = name.substr(1, name.length - 2);
+ name = ctx.stylize(name, 'name');
+ } else {
+ name = name.replace(/'/g, "\\'")
+ .replace(/\\"/g, '"')
+ .replace(/(^"|"$)/g, "'");
+ name = ctx.stylize(name, 'string');
+ }
+ }
+
+ return name + ': ' + str;
+}
+
+
+function reduceToSingleString(output, base, braces) {
+ var numLinesEst = 0;
+ var length = shims.reduce(output, function(prev, cur) {
+ numLinesEst++;
+ if (cur.indexOf('\n') >= 0) numLinesEst++;
+ return prev + cur.replace(/\u001b\[\d\d?m/g, '').length + 1;
+ }, 0);
+
+ if (length > 60) {
+ return braces[0] +
+ (base === '' ? '' : base + '\n ') +
+ ' ' +
+ output.join(',\n ') +
+ ' ' +
+ braces[1];
+ }
+
+ return braces[0] + base + ' ' + output.join(', ') + ' ' + braces[1];
+}
+
+
+// NOTE: These type checking functions intentionally don't use `instanceof`
+// because it is fragile and can be easily faked with `Object.create()`.
+function isArray(ar) {
+ return shims.isArray(ar);
+}
+exports.isArray = isArray;
+
+function isBoolean(arg) {
+ return typeof arg === 'boolean';
+}
+exports.isBoolean = isBoolean;
+
+function isNull(arg) {
+ return arg === null;
+}
+exports.isNull = isNull;
+
+function isNullOrUndefined(arg) {
+ return arg == null;
+}
+exports.isNullOrUndefined = isNullOrUndefined;
+
+function isNumber(arg) {
+ return typeof arg === 'number';
+}
+exports.isNumber = isNumber;
+
+function isString(arg) {
+ return typeof arg === 'string';
+}
+exports.isString = isString;
+
+function isSymbol(arg) {
+ return typeof arg === 'symbol';
+}
+exports.isSymbol = isSymbol;
+
+function isUndefined(arg) {
+ return arg === void 0;
+}
+exports.isUndefined = isUndefined;
+
+function isRegExp(re) {
+ return isObject(re) && objectToString(re) === '[object RegExp]';
+}
+exports.isRegExp = isRegExp;
+
+function isObject(arg) {
+ return typeof arg === 'object' && arg;
+}
+exports.isObject = isObject;
+
+function isDate(d) {
+ return isObject(d) && objectToString(d) === '[object Date]';
+}
+exports.isDate = isDate;
+
+function isError(e) {
+ return isObject(e) && objectToString(e) === '[object Error]';
+}
+exports.isError = isError;
+
+function isFunction(arg) {
+ return typeof arg === 'function';
+}
+exports.isFunction = isFunction;
+
+function isPrimitive(arg) {
+ return arg === null ||
+ typeof arg === 'boolean' ||
+ typeof arg === 'number' ||
+ typeof arg === 'string' ||
+ typeof arg === 'symbol' || // ES6 symbol
+ typeof arg === 'undefined';
+}
+exports.isPrimitive = isPrimitive;
+
+function isBuffer(arg) {
+ return arg && typeof arg === 'object'
+ && typeof arg.copy === 'function'
+ && typeof arg.fill === 'function'
+ && typeof arg.binarySlice === 'function'
+ ;
+}
+exports.isBuffer = isBuffer;
+
+function objectToString(o) {
+ return Object.prototype.toString.call(o);
+}
+
+
+function pad(n) {
+ return n < 10 ? '0' + n.toString(10) : n.toString(10);
+}
+
+
+var months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep',
+ 'Oct', 'Nov', 'Dec'];
+
+// 26 Feb 16:19:34
+function timestamp() {
+ var d = new Date();
+ var time = [pad(d.getHours()),
+ pad(d.getMinutes()),
+ pad(d.getSeconds())].join(':');
+ return [d.getDate(), months[d.getMonth()], time].join(' ');
+}
+
+
+// log is just a thin wrapper to console.log that prepends a timestamp
+exports.log = function() {
+ console.log('%s - %s', timestamp(), exports.format.apply(exports, arguments));
+};
+
+
+/**
+ * Inherit the prototype methods from one constructor into another.
+ *
+ * The Function.prototype.inherits from lang.js rewritten as a standalone
+ * function (not on Function.prototype). NOTE: If this file is to be loaded
+ * during bootstrapping this function needs to be rewritten using some native
+ * functions as prototype setup using normal JavaScript does not work as
+ * expected during bootstrapping (see mirror.js in r114903).
+ *
+ * @param {function} ctor Constructor function which needs to inherit the
+ * prototype.
+ * @param {function} superCtor Constructor function to inherit prototype from.
+ */
+exports.inherits = function(ctor, superCtor) {
+ ctor.super_ = superCtor;
+ ctor.prototype = shims.create(superCtor.prototype, {
+ constructor: {
+ value: ctor,
+ enumerable: false,
+ writable: true,
+ configurable: true
+ }
+ });
+};
+
+exports._extend = function(origin, add) {
+ // Don't do anything if add isn't an object
+ if (!add || !isObject(add)) return origin;
+
+ var keys = shims.keys(add);
+ var i = keys.length;
+ while (i--) {
+ origin[keys[i]] = add[keys[i]];
+ }
+ return origin;
+};
+
+function hasOwnProperty(obj, prop) {
+ return Object.prototype.hasOwnProperty.call(obj, prop);
+}
+
+},{"_shims":1}],5:[function(require,module,exports){
+// shim for using process in browser
+
+var process = module.exports = {};
+
+process.nextTick = (function () {
+ var canSetImmediate = typeof window !== 'undefined'
+ && window.setImmediate;
+ var canPost = typeof window !== 'undefined'
+ && window.postMessage && window.addEventListener
+ ;
+
+ if (canSetImmediate) {
+ return function (f) { return window.setImmediate(f) };
+ }
+
+ if (canPost) {
+ var queue = [];
+ window.addEventListener('message', function (ev) {
+ var source = ev.source;
+ if ((source === window || source === null) && ev.data === 'process-tick') {
+ ev.stopPropagation();
+ if (queue.length > 0) {
+ var fn = queue.shift();
+ fn();
+ }
+ }
+ }, true);
+
+ return function nextTick(fn) {
+ queue.push(fn);
+ window.postMessage('process-tick', '*');
+ };
+ }
+
+ return function nextTick(fn) {
+ setTimeout(fn, 0);
+ };
+})();
+
+process.title = 'browser';
+process.browser = true;
+process.env = {};
+process.argv = [];
+
+process.binding = function (name) {
+ throw new Error('process.binding is not supported');
+}
+
+// TODO(shtylman)
+process.cwd = function () { return '/' };
+process.chdir = function (dir) {
+ throw new Error('process.chdir is not supported');
+};
+
+},{}],6:[function(require,module,exports){
+
+/*!
+ * EJS
+ * Copyright(c) 2012 TJ Holowaychuk
+ * MIT Licensed
+ */
+
+/**
+ * Module dependencies.
+ */
+
+var utils = require('./utils')
+ , path = require('path')
+ , dirname = path.dirname
+ , extname = path.extname
+ , join = path.join
+ , fs = require('fs')
+ , read = fs.readFileSync;
+
+/**
+ * Filters.
+ *
+ * @type Object
+ */
+
+var filters = exports.filters = require('./filters');
+
+/**
+ * Intermediate js cache.
+ *
+ * @type Object
+ */
+
+var cache = {};
+
+/**
+ * Clear intermediate js cache.
+ *
+ * @api public
+ */
+
+exports.clearCache = function(){
+ cache = {};
+};
+
+/**
+ * Translate filtered code into function calls.
+ *
+ * @param {String} js
+ * @return {String}
+ * @api private
+ */
+
+function filtered(js) {
+ return js.substr(1).split('|').reduce(function(js, filter){
+ var parts = filter.split(':')
+ , name = parts.shift()
+ , args = parts.join(':') || '';
+ if (args) args = ', ' + args;
+ return 'filters.' + name + '(' + js + args + ')';
+ });
+};
+
+/**
+ * Re-throw the given `err` in context to the
+ * `str` of ejs, `filename`, and `lineno`.
+ *
+ * @param {Error} err
+ * @param {String} str
+ * @param {String} filename
+ * @param {String} lineno
+ * @api private
+ */
+
+function rethrow(err, str, filename, lineno){
+ var lines = str.split('\n')
+ , start = Math.max(lineno - 3, 0)
+ , end = Math.min(lines.length, lineno + 3);
+
+ // Error context
+ var context = lines.slice(start, end).map(function(line, i){
+ var curr = i + start + 1;
+ return (curr == lineno ? ' >> ' : ' ')
+ + curr
+ + '| '
+ + line;
+ }).join('\n');
+
+ // Alter exception message
+ err.path = filename;
+ err.message = (filename || 'ejs') + ':'
+ + lineno + '\n'
+ + context + '\n\n'
+ + err.message;
+
+ throw err;
+}
+
+/**
+ * Parse the given `str` of ejs, returning the function body.
+ *
+ * @param {String} str
+ * @return {String}
+ * @api public
+ */
+
+var parse = exports.parse = function(str, options){
+ var options = options || {}
+ , open = options.open || exports.open || '<%'
+ , close = options.close || exports.close || '%>'
+ , filename = options.filename
+ , compileDebug = options.compileDebug !== false
+ , buf = "";
+
+ buf += 'var buf = [];';
+ if (false !== options._with) buf += '\nwith (locals || {}) { (function(){ ';
+ buf += '\n buf.push(\'';
+
+ var lineno = 1;
+
+ var consumeEOL = false;
+ for (var i = 0, len = str.length; i < len; ++i) {
+ var stri = str[i];
+ if (str.slice(i, open.length + i) == open) {
+ i += open.length
+
+ var prefix, postfix, line = (compileDebug ? '__stack.lineno=' : '') + lineno;
+ switch (str[i]) {
+ case '=':
+ prefix = "', escape((" + line + ', ';
+ postfix = ")), '";
+ ++i;
+ break;
+ case '-':
+ prefix = "', (" + line + ', ';
+ postfix = "), '";
+ ++i;
+ break;
+ default:
+ prefix = "');" + line + ';';
+ postfix = "; buf.push('";
+ }
+
+ var end = str.indexOf(close, i)
+ , js = str.substring(i, end)
+ , start = i
+ , include = null
+ , n = 0;
+
+ if ('-' == js[js.length-1]){
+ js = js.substring(0, js.length - 2);
+ consumeEOL = true;
+ }
+
+ if (0 == js.trim().indexOf('include')) {
+ var name = js.trim().slice(7).trim();
+ if (!filename) throw new Error('filename option is required for includes');
+ var path = resolveInclude(name, filename);
+ include = read(path, 'utf8');
+ include = exports.parse(include, { filename: path, _with: false, open: open, close: close, compileDebug: compileDebug });
+ buf += "' + (function(){" + include + "})() + '";
+ js = '';
+ }
+
+ while (~(n = js.indexOf("\n", n))) n++, lineno++;
+ if (js.substr(0, 1) == ':') js = filtered(js);
+ if (js) {
+ if (js.lastIndexOf('//') > js.lastIndexOf('\n')) js += '\n';
+ buf += prefix;
+ buf += js;
+ buf += postfix;
+ }
+ i += end - start + close.length - 1;
+
+ } else if (stri == "\\") {
+ buf += "\\\\";
+ } else if (stri == "'") {
+ buf += "\\'";
+ } else if (stri == "\r") {
+ // ignore
+ } else if (stri == "\n") {
+ if (consumeEOL) {
+ consumeEOL = false;
+ } else {
+ buf += "\\n";
+ lineno++;
+ }
+ } else {
+ buf += stri;
+ }
+ }
+
+ if (false !== options._with) buf += "'); })();\n} \nreturn buf.join('');";
+ else buf += "');\nreturn buf.join('');";
+ return buf;
+};
+
+/**
+ * Compile the given `str` of ejs into a `Function`.
+ *
+ * @param {String} str
+ * @param {Object} options
+ * @return {Function}
+ * @api public
+ */
+
+var compile = exports.compile = function(str, options){
+ options = options || {};
+ var escape = options.escape || utils.escape;
+
+ var input = JSON.stringify(str)
+ , compileDebug = options.compileDebug !== false
+ , client = options.client
+ , filename = options.filename
+ ? JSON.stringify(options.filename)
+ : 'undefined';
+
+ if (compileDebug) {
+ // Adds the fancy stack trace meta info
+ str = [
+ 'var __stack = { lineno: 1, input: ' + input + ', filename: ' + filename + ' };',
+ rethrow.toString(),
+ 'try {',
+ exports.parse(str, options),
+ '} catch (err) {',
+ ' rethrow(err, __stack.input, __stack.filename, __stack.lineno);',
+ '}'
+ ].join("\n");
+ } else {
+ str = exports.parse(str, options);
+ }
+
+ if (options.debug) console.log(str);
+ if (client) str = 'escape = escape || ' + escape.toString() + ';\n' + str;
+
+ try {
+ var fn = new Function('locals, filters, escape, rethrow', str);
+ } catch (err) {
+ if ('SyntaxError' == err.name) {
+ err.message += options.filename
+ ? ' in ' + filename
+ : ' while compiling ejs';
+ }
+ throw err;
+ }
+
+ if (client) return fn;
+
+ return function(locals){
+ return fn.call(this, locals, filters, escape, rethrow);
+ }
+};
+
+/**
+ * Render the given `str` of ejs.
+ *
+ * Options:
+ *
+ * - `locals` Local variables object
+ * - `cache` Compiled functions are cached, requires `filename`
+ * - `filename` Used by `cache` to key caches
+ * - `scope` Function execution context
+ * - `debug` Output generated function body
+ * - `open` Open tag, defaulting to "<%"
+ * - `close` Closing tag, defaulting to "%>"
+ *
+ * @param {String} str
+ * @param {Object} options
+ * @return {String}
+ * @api public
+ */
+
+exports.render = function(str, options){
+ var fn
+ , options = options || {};
+
+ if (options.cache) {
+ if (options.filename) {
+ fn = cache[options.filename] || (cache[options.filename] = compile(str, options));
+ } else {
+ throw new Error('"cache" option requires "filename".');
+ }
+ } else {
+ fn = compile(str, options);
+ }
+
+ options.__proto__ = options.locals;
+ return fn.call(options.scope, options);
+};
+
+/**
+ * Render an EJS file at the given `path` and callback `fn(err, str)`.
+ *
+ * @param {String} path
+ * @param {Object|Function} options or callback
+ * @param {Function} fn
+ * @api public
+ */
+
+exports.renderFile = function(path, options, fn){
+ var key = path + ':string';
+
+ if ('function' == typeof options) {
+ fn = options, options = {};
+ }
+
+ options.filename = path;
+
+ var str;
+ try {
+ str = options.cache
+ ? cache[key] || (cache[key] = read(path, 'utf8'))
+ : read(path, 'utf8');
+ } catch (err) {
+ fn(err);
+ return;
+ }
+ fn(null, exports.render(str, options));
+};
+
+/**
+ * Resolve include `name` relative to `filename`.
+ *
+ * @param {String} name
+ * @param {String} filename
+ * @return {String}
+ * @api private
+ */
+
+function resolveInclude(name, filename) {
+ var path = join(dirname(filename), name);
+ var ext = extname(name);
+ if (!ext) path += '.ejs';
+ return path;
+}
+
+// express support
+
+exports.__express = exports.renderFile;
+
+/**
+ * Expose to require().
+ */
+
+if (require.extensions) {
+ require.extensions['.ejs'] = function (module, filename) {
+ filename = filename || module.filename;
+ var options = { filename: filename, client: true }
+ , template = fs.readFileSync(filename).toString()
+ , fn = compile(template, options);
+ module._compile('module.exports = ' + fn.toString() + ';', filename);
+ };
+} else if (require.registerExtension) {
+ require.registerExtension('.ejs', function(src) {
+ return compile(src, {});
+ });
}
-PAYPAL.apps = PAYPAL.apps || {};
-
-
-(function () {
- 'use strict';
-
- /**
- * Default configuration
- */
- var config = {
- /**
- * The parent element the cart should "pin" to
- */
- parent: document.body,
-
- /**
- * Edge of the window to pin the cart to
- */
- displayEdge: 'right',
-
- /**
- * Distance from the edge of the window
- */
- edgeDistance: '50px',
-
- /**
- * HTML target property for the checkout form
- */
- formTarget: null,
-
- /**
- * The base path of your website to set the cookie to
- */
- cookiePath: '/',
-
- /**
- * The number of days to keep the cart data
- */
- cartDuration: 30,
-
- /**
- * Strings used for display text
- */
- strings: {
- button: 'Checkout',
- subtotal: 'Subtotal: ',
- discount: 'Discount: ',
- shipping: 'does not include shipping & tax',
- processing: 'Processing...'
- },
-
- /**
- * Unique ID used on the wrapper element
- */
- name: 'PPMiniCart',
-
- /**
- * Boolean to determine if the cart should "peek" when it's hidden with items
- */
- peekEnabled: true,
-
- /**
- * The URL of the PayPal website
- */
- paypalURL: 'https://www.paypal.com/cgi-bin/webscr',
-
- /**
- * The base URL to the visual assets
- */
- assetURL: 'http://www.minicartjs.com/build/',
-
- events: {
- /**
- * Custom event fired before the cart is rendered
- */
- onRender: null,
-
- /**
- * Custom event fired after the cart is rendered
- */
- afterRender: null,
-
- /**
- * Custom event fired before the cart is hidden
- *
- * @param e {event} The triggering event
- */
- onHide: null,
-
- /**
- * Custom event fired after the cart is hidden
- *
- * @param e {event} The triggering event
- */
- afterHide: null,
-
- /**
- * Custom event fired before the cart is shown
- *
- * @param e {event} The triggering event
- */
- onShow: null,
-
- /**
- * Custom event fired after the cart is shown
- *
- * @param e {event} The triggering event
- */
- afterShow: null,
-
- /**
- * Custom event fired before a product is added to the cart
- *
- * @param data {object} Product object
- */
- onAddToCart: null,
-
- /**
- * Custom event fired after a product is added to the cart
- *
- * @param data {object} Product object
- */
- afterAddToCart: null,
-
- /**
- * Custom event fired before a product is removed from the cart
- *
- * @param data {object} Product object
- */
- onRemoveFromCart: null,
-
- /**
- * Custom event fired after a product is removed from the cart
- *
- * @param data {object} Product object
- */
- afterRemoveFromCart: null,
-
- /**
- * Custom event fired before the checkout action takes place
- *
- * @param e {event} The triggering event
- */
- onCheckout: null,
-
- /**
- * Custom event fired before the cart is reset
- */
- onReset: null,
-
- /**
- * Custom event fired after the cart is reset
- */
- afterReset: null
- }
- };
-
-
- if (!PAYPAL.apps.MiniCart) {
-
- /**
- * Mini Cart application
- */
- PAYPAL.apps.MiniCart = (function () {
-
- var minicart = {},
- isShowing = false,
- isRendered = false;
-
-
- /** PRIVATE **/
-
- /**
- * PayPal form cmd values which are supported
- */
- var SUPPORTED_CMDS = { _cart: true, _xclick: true };
-
-
- /**
- * The form origin that is passed to PayPal
- */
- var BN_VALUE = 'MiniCart_AddToCart_WPS_US';
-
-
- /**
- * Regex filter for cart settings, which appear only once in a cart
- */
- var SETTING_FILTER = /^(?:business|currency_code|lc|paymentaction|no_shipping|cn|no_note|invoice|handling_cart|weight_cart|weight_unit|tax_cart|page_style|image_url|cpp_|cs|cbt|return|cancel_return|notify_url|rm|custom|charset)/;
-
-
- /**
- * Adds the cart's CSS to the page in a
+
+
+
+
+
+
+
+
+