Skip to content
Snippets Groups Projects
Commit d338ad90 authored by Demian Katz's avatar Demian Katz
Browse files

Added config setting for cart cookie domain.

parent 8c02cd08
No related merge requests found
......@@ -84,6 +84,9 @@ sidebarOnLeft = false
showBookBag = false
; Set the maximum amount of items allowed in the Book Bag - Default is 100
bookBagMaxSize = 100
; Set the domain used for cart-related cookies (sometimes useful for sharing the
; cookies across subdomains)
;bookBagCookieDomain = ".example.edu"
; Generator value to display in an HTML header <meta> tag:
generator = "VuFind 2.3.1"
......
......@@ -68,6 +68,13 @@ class Cart
*/
protected $recordLoader;
/**
* Domain context for cookies (null for default)
*
* @var string
*/
protected $cookieDomain;
const CART_COOKIE = 'vufind_cart';
const CART_COOKIE_SOURCES = 'vufind_cart_src';
const CART_COOKIE_DELIM = "\t";
......@@ -75,18 +82,21 @@ class Cart
/**
* Constructor
*
* @param \VuFind\Record\Loader $loader Object for loading records
* @param int $maxSize Maximum size of cart contents
* @param bool $active Is cart enabled?
* @param array $cookies Current cookie values (leave null
* @param \VuFind\Record\Loader $loader Object for loading records
* @param int $maxSize Maximum size of cart contents
* @param bool $active Is cart enabled?
* @param array $cookies Current cookie values (leave null
* to use $_COOKIE superglobal)
* @param string $cookieDomain Domain context for cookies
* (optional)
*/
public function __construct(\VuFind\Record\Loader $loader,
$maxSize = 100, $active = true, $cookies = null
$maxSize = 100, $active = true, $cookies = null, $cookieDomain = null
) {
$this->recordLoader = $loader;
$this->maxSize = $maxSize;
$this->active = $active;
$this->cookieDomain = $cookieDomain;
// Initialize contents
$this->init(null === $cookies ? $_COOKIE : $cookies);
......@@ -282,9 +292,11 @@ class Cart
// Save the cookies:
$cookie = implode(self::CART_COOKIE_DELIM, $ids);
$this->setCookie(self::CART_COOKIE, $cookie, 0, '/');
$this->setCookie(self::CART_COOKIE, $cookie, 0, '/', $this->cookieDomain);
$cookie = implode(self::CART_COOKIE_DELIM, $sources);
$this->setCookie(self::CART_COOKIE_SOURCES, $cookie, 0, '/');
$this->setCookie(
self::CART_COOKIE_SOURCES, $cookie, 0, '/', $this->cookieDomain
);
}
/**
......@@ -300,6 +312,16 @@ class Cart
// @codeCoverageIgnoreEnd
}
/**
* Get cookie domain context (null if unset).
*
* @return string
*/
public function getCookieDomain()
{
return $this->cookieDomain;
}
/**
* Process parameters and return the cart content.
*
......
......@@ -93,8 +93,10 @@ class Factory
? (bool)$config->Site->showBookBag : false;
$size = isset($config->Site->bookBagMaxSize)
? $config->Site->bookBagMaxSize : 100;
$domain = isset($config->Site->bookBagCookieDomain)
? $config->Site->bookBagCookieDomain : null;
return new \VuFind\Cart(
$sm->get('VuFind\RecordLoader'), $size, $active
$sm->get('VuFind\RecordLoader'), $size, $active, $_COOKIE, $domain
);
}
......
......@@ -70,14 +70,26 @@ class CartTest extends \PHPUnit_Framework_TestCase
*
* @return \VuFind\Cart
*/
protected function getCart($maxSize = 100, $active = true, $cookies = array())
{
protected function getCart($maxSize = 100, $active = true, $cookies = array(),
$domain = null
) {
return $this->getMock(
'VuFind\Cart', array('setCookie'),
array($this->loader, $maxSize, $active, $cookies)
array($this->loader, $maxSize, $active, $cookies, $domain)
);
}
/**
* Test cookie domain setting.
*
* @return void
*/
public function testCookieDomain()
{
$cart = $this->getCart(100, true, array(), '.example.com');
$this->assertEquals('.example.com', $cart->getCookieDomain());
}
/**
* Check that the cart is empty by default.
*
......
/*global contextHelp, vufindString*/
/*global cartCookieDomain, contextHelp, vufindString*/
var _CART_COOKIE = 'vufind_cart';
var _CART_COOKIE_SOURCES = 'vufind_cart_src';
......@@ -51,11 +51,19 @@ function uniqueValues(array) {
return r;
}
function getCartCookieParams() {
if (cartCookieDomain) {
return { path: '/', domain: cartCookieDomain }
} else {
return { path: '/' };
}
}
function saveCartCookie(items) {
// No items? Clear cookies:
if (items.length == 0) {
$.cookie(_CART_COOKIE, null, { path: '/' });
$.cookie(_CART_COOKIE_SOURCES, null, { path: '/' });
$.cookie(_CART_COOKIE, null, getCartCookieParams());
$.cookie(_CART_COOKIE_SOURCES, null, getCartCookieParams());
return;
}
......@@ -83,8 +91,8 @@ function saveCartCookie(items) {
}
// Save the cookies:
$.cookie(_CART_COOKIE, ids.join(_CART_COOKIE_DELIM), { path: '/' });
$.cookie(_CART_COOKIE_SOURCES, sources.join(_CART_COOKIE_DELIM), { path: '/' });
$.cookie(_CART_COOKIE, ids.join(_CART_COOKIE_DELIM), getCartCookieParams());
$.cookie(_CART_COOKIE_SOURCES, sources.join(_CART_COOKIE_DELIM), getCartCookieParams());
}
function addItemToCartCookie(item) {
......
......@@ -38,6 +38,10 @@
if ($cart->isActive()) {
$this->headScript()->appendFile("jquery.cookie.js");
$this->headScript()->appendFile("cart.js");
$domain = $cart->getCookieDomain();
$this->headScript()->appendScript(
'var cartCookieDomain = ' . (!empty($domain) ? "'$domain'" : 'false') . ';'
);
$this->jsTranslations()->addStrings(
array(
'bulk_noitems_advice' => 'bulk_noitems_advice',
......
/*global bulkActionSubmit, Cookies, newAccountHandler, path, vufindString, Lightbox, updatePageForLogin */
var _CART_COOKIE = 'vufind_cart';
var _CART_COOKIE_SOURCES = 'vufind_cart_src';
var _CART_COOKIE_DELIM = "\t";
var currentId,currentSource;
var lastCartSubmit = false;
function getCartItems() {
var items = Cookies.getItem(_CART_COOKIE);
if(items) {
return items.split(_CART_COOKIE_DELIM);
}
return [];
}
function getCartSources() {
var items = Cookies.getItem(_CART_COOKIE_SOURCES);
if(items) {
return items.split(_CART_COOKIE_DELIM);
}
return [];
}
function getFullCartItems() {
var items = getCartItems();
var sources = getCartSources();
var full = [];
if(items.length == 0) {
return [];
}
for(var i=items.length;i--;) {
full[full.length] = sources[items[i].charCodeAt(0)-65]+'|'+items[i].substr(1);
}
return full;
}
function addItemToCart(id,source) {
if(!source) {
source = 'VuFind';
}
var cartItems = getCartItems();
var cartSources = getCartSources();
var sIndex = cartSources.indexOf(source);
if(sIndex < 0) {
// Add source to source cookie
cartItems[cartItems.length] = String.fromCharCode(65+cartSources.length) + id;
cartSources[cartSources.length] = source;
Cookies.setItem(_CART_COOKIE_SOURCES, cartSources.join(_CART_COOKIE_DELIM), false, '/');
} else {
cartItems[cartItems.length] = String.fromCharCode(65+sIndex) + id;
}
Cookies.setItem(_CART_COOKIE, $.unique(cartItems).join(_CART_COOKIE_DELIM), false, '/');
$('#cartItems strong').html(parseInt($('#cartItems strong').html(), 10)+1);
return true;
}
function uniqueArray(op) {
var ret = [];
for(var i=0;i<op.length;i++) {
if(ret.indexOf(op[i]) < 0) {
ret.push(op[i]);
}
}
return ret;
}
function removeItemFromCart(id,source) {
var cartItems = getCartItems();
var cartSources = getCartSources();
// Find
var cartIndex = cartItems.indexOf(String.fromCharCode(65+cartSources.indexOf(source))+id);
if(cartIndex > -1) {
var sourceIndex = cartItems[cartIndex].charCodeAt(0)-65;
var cartItem = cartItems[cartIndex];
var saveSource = false;
for(var i=cartItems.length;i--;) {
if(i==cartIndex) {
continue;
}
// If this source is shared by another, keep it
if(cartItems[i].charCodeAt(0)-65 == sourceIndex) {
saveSource = true;
break;
}
}
cartItems.splice(cartIndex,1);
// Remove unused sources
if(!saveSource) {
var oldSources = cartSources.slice(0);
cartSources.splice(sourceIndex,1);
// Adjust source index characters
for(var j=cartItems.length;j--;) {
var si = cartItems[j].charCodeAt(0)-65;
var ni = cartSources.indexOf(oldSources[si]);
cartItems[j] = String.fromCharCode(65+ni)+cartItems[j].substring(1);
}
}
if(cartItems.length > 0) {
Cookies.setItem(_CART_COOKIE, uniqueArray(cartItems).join(_CART_COOKIE_DELIM), false, '/');
Cookies.setItem(_CART_COOKIE_SOURCES, uniqueArray(cartSources).join(_CART_COOKIE_DELIM), false, '/');
} else {
Cookies.removeItem(_CART_COOKIE, '/');
Cookies.removeItem(_CART_COOKIE_SOURCES, '/');
}
$('#cartItems strong').html(parseInt($('#cartItems strong').html(), 10)-1);
return true;
}
return false;
}
var cartNotificationTimeout = false;
function registerUpdateCart($form) {
if($form) {
$("#updateCart, #bottom_updateCart").unbind('click').click(function(){
var elId = this.id;
var selectedBoxes = $("input[name='ids[]']:checked", $form);
var selected = [];
$(selectedBoxes).each(function(i) {
selected[i] = this.value;
});
if (selected.length > 0) {
var inCart = 0;
var msg = "";
var orig = getFullCartItems();
$(selected).each(function(i) {
for (var x in orig) {
if (this == orig[x]) {
inCart++;
return;
}
}
var data = this.split('|');
addItemToCart(data[1], data[0]);
});
var updated = getFullCartItems();
var added = updated.length - orig.length;
msg += added + " " + vufindString.itemsAddBag;
if (inCart > 0 && orig.length > 0) {
msg += "<br/>" + inCart + " " + vufindString.itemsInBag;
}
if (updated.length >= vufindString.bookbagMax) {
msg += "<br/>" + vufindString.bookbagFull;
}
$('#'+elId).data('bs.popover').options.content = msg;
$('#cartItems strong').html(updated.length);
} else {
$('#'+elId).data('bs.popover').options.content = vufindString.bulk_noitems_advice;
}
$('#'+elId).popover('show');
if (cartNotificationTimeout !== false) {
clearTimeout(cartNotificationTimeout);
}
cartNotificationTimeout = setTimeout(function() {
$('#'+elId).popover('hide');
}, 5000);
return false;
});
}
}
$(document).ready(function() {
// Record buttons
var cartId = $('#cartId');
if(cartId.length > 0) {
cartId = cartId.val().split('|');
currentId = cartId[1];
currentSource = cartId[0];
$('#cart-add.correct,#cart-remove.correct').removeClass('correct hidden');
$('#cart-add').click(function() {
addItemToCart(currentId,currentSource);
$('#cart-add,#cart-remove').toggleClass('hidden');
});
$('#cart-remove').click(function() {
removeItemFromCart(currentId,currentSource);
$('#cart-add,#cart-remove').toggleClass('hidden');
});
} else {
// Search results
var $form = $('form[name="bulkActionForm"]');
registerUpdateCart($form);
}
$("#updateCart, #bottom_updateCart").popover({content:'', html:true, trigger:'manual'});
// Setup lightbox behavior
// Cart lightbox
$('#cartItems').click(function() {
return Lightbox.get('Cart','Cart');
});
// Overwrite
Lightbox.addFormCallback('accountForm', function(html) {
updatePageForLogin();
if (lastCartSubmit !== false) {
bulkActionSubmit(lastCartSubmit);
lastCartSubmit = false;
} else {
newAccountHandler(html);
}
});
Lightbox.addFormHandler('cartForm', function(evt) {
lastCartSubmit = $(evt.target);
bulkActionSubmit($(evt.target));
return false;
});
Lightbox.addFormCallback('bulkEmail', function(html) {
Lightbox.confirm(vufindString['bulk_email_success']);
});
Lightbox.addFormCallback('bulkSave', function(html) {
// After we close the lightbox, redirect to list view
Lightbox.addCloseAction(function() {
document.location.href = path+'/MyResearch/MyList/'+Lightbox.lastPOST['list'];
});
Lightbox.confirm(vufindString['bulk_save_success']);
});
Lightbox.addFormHandler('exportForm', function(evt) {
$.ajax({
url: path + '/AJAX/JSON?' + $.param({method:'exportFavorites'}),
type:'POST',
dataType:'json',
data:Lightbox.getFormData($(evt.target)),
success:function(data) {
if(data.data.needs_redirect) {
document.location.href = data.data.result_url;
} else {
Lightbox.changeContent(data.data.result_additional);
}
},
error:function(d,e) {
//console.log(d,e); // Error reporting
}
});
return false;
});
$('#modal').on('hidden.bs.modal', function() {
// Update cart items (add to cart, remove from cart, cart lightbox interface)
var cartCount = $('#cartItems strong');
if(cartCount.length > 0) {
var cart = getFullCartItems();
var id = $('#cartId');
if(id.length > 0) {
id = id.val();
$('#cart-add,#cart-remove').addClass('hidden');
if(cart.indexOf(id) > -1) {
$('#cart-remove').removeClass('hidden');
} else {
$('#cart-add').removeClass('hidden');
}
}
cartCount.html(cart.length);
}
});
});
/*global bulkActionSubmit, cartCookieDomain, Cookies, newAccountHandler, path, vufindString, Lightbox, updatePageForLogin */
var _CART_COOKIE = 'vufind_cart';
var _CART_COOKIE_SOURCES = 'vufind_cart_src';
var _CART_COOKIE_DELIM = "\t";
var currentId,currentSource;
var lastCartSubmit = false;
function getCartItems() {
var items = Cookies.getItem(_CART_COOKIE);
if(items) {
return items.split(_CART_COOKIE_DELIM);
}
return [];
}
function getCartSources() {
var items = Cookies.getItem(_CART_COOKIE_SOURCES);
if(items) {
return items.split(_CART_COOKIE_DELIM);
}
return [];
}
function getFullCartItems() {
var items = getCartItems();
var sources = getCartSources();
var full = [];
if(items.length == 0) {
return [];
}
for(var i=items.length;i--;) {
full[full.length] = sources[items[i].charCodeAt(0)-65]+'|'+items[i].substr(1);
}
return full;
}
function addItemToCart(id,source) {
if(!source) {
source = 'VuFind';
}
var cartItems = getCartItems();
var cartSources = getCartSources();
var sIndex = cartSources.indexOf(source);
if(sIndex < 0) {
// Add source to source cookie
cartItems[cartItems.length] = String.fromCharCode(65+cartSources.length) + id;
cartSources[cartSources.length] = source;
Cookies.setItem(_CART_COOKIE_SOURCES, cartSources.join(_CART_COOKIE_DELIM), false, '/', cartCookieDomain);
} else {
cartItems[cartItems.length] = String.fromCharCode(65+sIndex) + id;
}
Cookies.setItem(_CART_COOKIE, $.unique(cartItems).join(_CART_COOKIE_DELIM), false, '/', cartCookieDomain);
$('#cartItems strong').html(parseInt($('#cartItems strong').html(), 10)+1);
return true;
}
function uniqueArray(op) {
var ret = [];
for(var i=0;i<op.length;i++) {
if(ret.indexOf(op[i]) < 0) {
ret.push(op[i]);
}
}
return ret;
}
function removeItemFromCart(id,source) {
var cartItems = getCartItems();
var cartSources = getCartSources();
// Find
var cartIndex = cartItems.indexOf(String.fromCharCode(65+cartSources.indexOf(source))+id);
if(cartIndex > -1) {
var sourceIndex = cartItems[cartIndex].charCodeAt(0)-65;
var cartItem = cartItems[cartIndex];
var saveSource = false;
for(var i=cartItems.length;i--;) {
if(i==cartIndex) {
continue;
}
// If this source is shared by another, keep it
if(cartItems[i].charCodeAt(0)-65 == sourceIndex) {
saveSource = true;
break;
}
}
cartItems.splice(cartIndex,1);
// Remove unused sources
if(!saveSource) {
var oldSources = cartSources.slice(0);
cartSources.splice(sourceIndex,1);
// Adjust source index characters
for(var j=cartItems.length;j--;) {
var si = cartItems[j].charCodeAt(0)-65;
var ni = cartSources.indexOf(oldSources[si]);
cartItems[j] = String.fromCharCode(65+ni)+cartItems[j].substring(1);
}
}
if(cartItems.length > 0) {
Cookies.setItem(_CART_COOKIE, uniqueArray(cartItems).join(_CART_COOKIE_DELIM), false, '/', cartCookieDomain);
Cookies.setItem(_CART_COOKIE_SOURCES, uniqueArray(cartSources).join(_CART_COOKIE_DELIM), false, '/', cartCookieDomain);
} else {
Cookies.removeItem(_CART_COOKIE, '/', cartCookieDomain);
Cookies.removeItem(_CART_COOKIE_SOURCES, '/', cartCookieDomain);
}
$('#cartItems strong').html(parseInt($('#cartItems strong').html(), 10)-1);
return true;
}
return false;
}
var cartNotificationTimeout = false;
function registerUpdateCart($form) {
if($form) {
$("#updateCart, #bottom_updateCart").unbind('click').click(function(){
var elId = this.id;
var selectedBoxes = $("input[name='ids[]']:checked", $form);
var selected = [];
$(selectedBoxes).each(function(i) {
selected[i] = this.value;
});
if (selected.length > 0) {
var inCart = 0;
var msg = "";
var orig = getFullCartItems();
$(selected).each(function(i) {
for (var x in orig) {
if (this == orig[x]) {
inCart++;
return;
}
}
var data = this.split('|');
addItemToCart(data[1], data[0]);
});
var updated = getFullCartItems();
var added = updated.length - orig.length;
msg += added + " " + vufindString.itemsAddBag;
if (inCart > 0 && orig.length > 0) {
msg += "<br/>" + inCart + " " + vufindString.itemsInBag;
}
if (updated.length >= vufindString.bookbagMax) {
msg += "<br/>" + vufindString.bookbagFull;
}
$('#'+elId).data('bs.popover').options.content = msg;
$('#cartItems strong').html(updated.length);
} else {
$('#'+elId).data('bs.popover').options.content = vufindString.bulk_noitems_advice;
}
$('#'+elId).popover('show');
if (cartNotificationTimeout !== false) {
clearTimeout(cartNotificationTimeout);
}
cartNotificationTimeout = setTimeout(function() {
$('#'+elId).popover('hide');
}, 5000);
return false;
});
}
}
$(document).ready(function() {
// Record buttons
var cartId = $('#cartId');
if(cartId.length > 0) {
cartId = cartId.val().split('|');
currentId = cartId[1];
currentSource = cartId[0];
$('#cart-add.correct,#cart-remove.correct').removeClass('correct hidden');
$('#cart-add').click(function() {
addItemToCart(currentId,currentSource);
$('#cart-add,#cart-remove').toggleClass('hidden');
});
$('#cart-remove').click(function() {
removeItemFromCart(currentId,currentSource);
$('#cart-add,#cart-remove').toggleClass('hidden');
});
} else {
// Search results
var $form = $('form[name="bulkActionForm"]');
registerUpdateCart($form);
}
$("#updateCart, #bottom_updateCart").popover({content:'', html:true, trigger:'manual'});
// Setup lightbox behavior
// Cart lightbox
$('#cartItems').click(function() {
return Lightbox.get('Cart','Cart');
});
// Overwrite
Lightbox.addFormCallback('accountForm', function(html) {
updatePageForLogin();
if (lastCartSubmit !== false) {
bulkActionSubmit(lastCartSubmit);
lastCartSubmit = false;
} else {
newAccountHandler(html);
}
});
Lightbox.addFormHandler('cartForm', function(evt) {
lastCartSubmit = $(evt.target);
bulkActionSubmit($(evt.target));
return false;
});
Lightbox.addFormCallback('bulkEmail', function(html) {
Lightbox.confirm(vufindString['bulk_email_success']);
});
Lightbox.addFormCallback('bulkSave', function(html) {
// After we close the lightbox, redirect to list view
Lightbox.addCloseAction(function() {
document.location.href = path+'/MyResearch/MyList/'+Lightbox.lastPOST['list'];
});
Lightbox.confirm(vufindString['bulk_save_success']);
});
Lightbox.addFormHandler('exportForm', function(evt) {
$.ajax({
url: path + '/AJAX/JSON?' + $.param({method:'exportFavorites'}),
type:'POST',
dataType:'json',
data:Lightbox.getFormData($(evt.target)),
success:function(data) {
if(data.data.needs_redirect) {
document.location.href = data.data.result_url;
} else {
Lightbox.changeContent(data.data.result_additional);
}
},
error:function(d,e) {
//console.log(d,e); // Error reporting
}
});
return false;
});
$('#modal').on('hidden.bs.modal', function() {
// Update cart items (add to cart, remove from cart, cart lightbox interface)
var cartCount = $('#cartItems strong');
if(cartCount.length > 0) {
var cart = getFullCartItems();
var id = $('#cartId');
if(id.length > 0) {
id = id.val();
$('#cart-add,#cart-remove').addClass('hidden');
if(cart.indexOf(id) > -1) {
$('#cart-remove').removeClass('hidden');
} else {
$('#cart-add').removeClass('hidden');
}
}
cartCount.html(cart.length);
}
});
});
......@@ -39,6 +39,10 @@
if ($cart->isActive()) {
$this->headScript()->appendFile("vendor/cookies.js");
$this->headScript()->appendFile("cart.js");
$domain = $cart->getCookieDomain();
$this->headScript()->appendScript(
'var cartCookieDomain = ' . (!empty($domain) ? "'$domain'" : 'false') . ';'
);
$this->jsTranslations()->addStrings(
array(
'bulk_noitems_advice' => 'bulk_noitems_advice',
......
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment