diff --git a/lib/WebGUI/Shop/AddressBook.pm b/lib/WebGUI/Shop/AddressBook.pm index 5d4772128..563853f4b 100644 --- a/lib/WebGUI/Shop/AddressBook.pm +++ b/lib/WebGUI/Shop/AddressBook.pm @@ -224,6 +224,30 @@ sub getAddress { #------------------------------------------------------------------- +=head2 getAddressByLabel ( label ) + +Returns an address object. + +=head3 id + +An address object's label, e.g. 'Home', 'Work' + +=cut + +sub getAddressByLabel { + my ($self, $label) = @_; + my $sql = q{ + SELECT addressId + FROM address + WHERE addressBookId = ? + AND label = ? + }; + my $id = $self->session->db->quickScalar($sql, [$self->getId, $label]); + return $id && $self->getAddress($id); +} + +#------------------------------------------------------------------- + =head2 getAddresses ( ) Returns an array reference of address objects that are in this book. @@ -470,6 +494,48 @@ sub update { #------------------------------------------------------------------- +=head2 www_ajaxGetAddress ( ) + +Gets a JSON object representing the address given by the addressId form +parameter + +=cut + +sub www_ajaxGetAddress { + my $self = shift; + my $session = $self->session; + $session->http->setMimeType('text/plain'); + + my $addressId = $session->form->get('addressId'); + my $address = $self->getAddress($addressId) or return; + return JSON->new->encode($address->get); +} + +#------------------------------------------------------------------- + +=head2 www_ajaxSave ( ) + +Saves an address book entry + +=cut + +sub www_ajaxSave { + my $self = shift; + my $session = $self->session; + my $address = JSON->new->decode($session->form->get('address')); + my $obj = $self->getAddressByLabel($address->{label}); + if ($obj) { + $obj->update($address); + } + else { + $obj = $self->addAddress($address); + } + $session->http->setMimeType('text/plain'); + return $obj->getId; +} + +#------------------------------------------------------------------- + =head2 www_deleteAddress ( ) Deletes an address from the book. diff --git a/lib/WebGUI/Shop/Cart.pm b/lib/WebGUI/Shop/Cart.pm index 9aa4e531f..295ec6749 100644 --- a/lib/WebGUI/Shop/Cart.pm +++ b/lib/WebGUI/Shop/Cart.pm @@ -1137,6 +1137,12 @@ sub www_view { # render the cart my $template = WebGUI::Asset::Template->new($session, $session->setting->get("shopCartTemplateId")); + + my ($style, $url) = $session->quick('style', 'url'); + my $yui = $url->extras('/yui/build'); + $style->setScript("$yui/yahoo/yahoo-min.js"); + $style->setScript("$yui/json/json-min.js"); + $style->setScript($url->extras('shop/cart.js'), undef, 1); return $session->style->userStyle($template->process(\%var)); } diff --git a/www/extras/shop/cart.js b/www/extras/shop/cart.js new file mode 100644 index 000000000..f88a3a7af --- /dev/null +++ b/www/extras/shop/cart.js @@ -0,0 +1,207 @@ +/*global window, document, YAHOO */ + +(function () { + var $event = YAHOO.util.Event, + $connect = YAHOO.util.Connect, + $json = YAHOO.lang.JSON, + addressCache = {}, + elements = { + dropdowns: { + billing: 'billingAddressId_formId', + shipping: 'shippingAddressId_formId' + } + }, + addressParts = [ + 'label', 'firstName', 'lastName', 'organization', 'address1', + 'address2', 'address3', 'city', 'state', 'code', 'country', + 'phoneNumber', 'email' + ]; + + function omap(o, fn) { + var r = [], k; + for (k in o) { + if (o.hasOwnProperty(k)) { + r.push(fn.call(o, k, o[k])); + } + } + return r; + } + + function oeach(o, fn) { + omap(o, fn); + return; + } + + function addAddressKind(name) { + var i, key, obj = elements[name] = {}; + for (i = 0; i < addressParts.length; i += 1) { + key = addressParts[i]; + obj[key] = name + '_' + key + '_formId'; + } + } + + function getDomElements(o) { + oeach(o, function (k, v) { + if (typeof v === 'object') { + getDomElements(v); + } + else { + this[k] = document.getElementById(v); + } + }); + } + + function sameChange() { + var d = elements.same.checked; + oeach(elements.shipping, function (k, v) { + v.disabled = d; + }); + elements.dropdowns.shipping.disabled = d; + } + + function updateAddressDropdowns(o) { + var label = o.argument.address.label, + id = o.responseText; + + function updateOne(dropdown) { + var options = dropdown.options, i, opt; + for (i = 0; i < options.length; i += 1) { + opt = options[i]; + if (opt.text === label) { + opt.value = id; + return; + } + } + + opt = document.createElement('option'); + opt.value = id; + opt.text = label; + dropdown.appendChild(opt); + } + + updateOne(elements.dropdowns.billing); + updateOne(elements.dropdowns.shipping); + elements.dropdowns[o.argument.name].value = id; + } + + function saveAddress(a, name) { + var cb = { + success: updateAddressDropdowns, + argument: { address: a, name: name } + }, + post = 'shop=address;method=ajaxSave;address=' + + $json.stringify(a), + url = window.location.pathname; + + $connect.asyncRequest('POST', url, cb, post); + } + + function validAddress(a) { + return a.label && + a.firstName && + a.lastName && + a.address1 && + a.city && + a.state && + a.code && + a.country; + } + + function addressChange(name) { + var other = name === 'billing' ? 'shipping' : 'billing'; + return function () { + var address = {}, + els = elements[name], + label = els.label.value, + oels = elements[other], + copy = oels.label.value === label, + cached = addressCache[label], + dirty; + + if (!cached) { + cached = addressCache[label] = {}; + } + + oeach(elements[name], function (k, v) { + v = v.value; + address[k] = v; + if (cached[k] !== v) { + dirty = true; + cached[k] = v; + } + if (copy) { + oels[k].value = v; + } + }); + if (dirty && validAddress(address)) { + saveAddress(address, name); + } + }; + } + + function addressUpdater(name) { + var elems = elements[name]; + function update(address) { + oeach(address, function (k, v) { + var dom = elems[k]; + if (dom) { + dom.value = v; + } + }); + } + return function () { + var id = this.value, + label = this.options[this.selectedIndex].text, + cached = addressCache[label], + url, cb; + + if (cached) { + return update(cached); + } + + url = window.location.pathname + + '?shop=address;method=ajaxGetAddress;addressId=' + + id; + + cb = { + success: function (o) { + var address = $json.parse(o.responseText); + addressCache[address.label] = address; + update(address); + } + }; + $connect.asyncRequest('GET', url, cb); + }; + } + + function main() { + var checks; + addAddressKind('billing'); + addAddressKind('shipping'); + getDomElements(elements); + + elements.form = document.forms[0]; + checks = elements.form.sameShippingAsBilling; + elements.same = checks[0]; + $event.on(checks, 'change', sameChange); + sameChange(); + + function handleBlur(name) { + var values = omap(elements[name], function (k, v) { + return v; + }); + $event.on(values, 'focusout', addressChange(name)); + } + handleBlur('billing'); + handleBlur('shipping'); + + function handleDropdown(name) { + $event.on(elements.dropdowns[name], 'change', addressUpdater(name)); + } + + handleDropdown('billing'); + handleDropdown('shipping'); + } + + $event.onDOMReady(main); +}());