oml.addList = function() {
// addList(isSmart, isFrom[, name[, callback]])
// or addList(list) [=duplicate]
var args = arguments,
isDuplicate = args.length == 1,
isSmart, isFrom, name, callback,
list, listData, data,
ui = oml.user.ui,
username = oml.user.preferences.username;
Ox.Request.clearCache('getLists');
oml.api.getLists(function(result) {
var lists = result.data.lists,
listNames = lists.filter(function(list) {
return list.user = username;
}).map(function(list) {
return list.name;
}),
query;
if (!isDuplicate) {
isSmart = args[0];
isFrom = args[1];
name = args[2] || Ox._('Untitled');
callback = args[3];
data = {
name: oml.getValidName(name, listNames),
type: !isSmart ? 'static' : 'smart'
};
if (!isSmart) {
if (isFrom) {
data.items = ui.listSelection;
}
} else {
if (!isFrom) {
data.query = oml.config.user.ui.find;
} else {
data.query = ui.find;
}
}
addList();
} else {
list = args[0];
listData = Ox.getObjectById(Ox.flatten(Ox.values(lists)), list);
data = Ox.extend({
name: oml.getValidName(listData.name, listNames),
type: listData.type
}, listData.query ? {
query: listData.query
} : {});
if (!data.query) {
var query = {
conditions: [{key: 'list', operator: '==', value: list}],
operator: '&'
};
oml.api.find({query: query}, function(result) {
if (result.data.items) {
oml.api.find({
query: query,
keys: ['id'],
sort: [{key: 'id', operator: '+'}],
range: [0, result.data.items]
}, function(result) {
data.items = result.data.items.map(function(item) {
return item.id;
});
addList();
});
} else {
addList();
}
});
} else {
addList();
}
}
});
function addList() {
oml.api.addList(data, function(result) {
var list = result.data.id,
$folderList = oml.$ui.folderList[0];
oml.$ui.folder[0].options({collapsed: false}); // FIXME: SET UI!
// FIXME: DOESN'T WORK
if (
!oml.$ui.importExportDialog
|| !oml.$ui.importExportDialog.is(':visible')
) {
$folderList
.bindEventOnce({
load: function() {
$folderList
.gainFocus()
.options({selected: [list]});
oml.UI.set({
find: {
conditions: [{
key: 'list',
operator: '==',
value: list
}],
operator: '&'
}
});
oml.$ui.listDialog = oml.ui.listDialog().open();
}
});
}
oml.$ui.folders.updateOwnLists();
callback && callback();
});
}
};
oml.clearFilters = function() {
var ui = oml.user.ui,
find = Ox.clone(ui.find, true),
indices = ui._filterState.map(function(filterState) {
return filterState.index;
}).filter(function(index) {
return index > -1;
});
find.conditions = find.conditions.filter(function(condition, index) {
return !Ox.contains(indices, index);
});
oml.UI.set({find: find});
};
oml.autovalidateEmail = function(value, blur, callback) {
value = value.toLowerCase().split('').map(function(v, i) {
return /[0-9a-z\.\+\-_@]/.test(v) ? v : null;
}).join('').slice(0, 255);
callback({valid: Ox.isValidEmail(value), value: value});
};
oml.clickLink = function(e) {
if (
e.target.hostname == document.location.hostname
&& !Ox.startsWith(e.target.pathname, '/static')
) {
oml.URL.push(e.target.pathname, true);
} else {
oml.openLink(e.target.href);
}
};
oml.createLinks = function($element) {
function isExternalLink(target) {
return target.hostname != document.location.hostname
|| Ox.startsWith(target.pathname, '/static');
}
$element.on({
click: function(e) {
var $target = $(e.target);
if ($target.is('a')) {
e.preventDefault();
if (isExternalLink(e.target)) {
oml.openLink(e.target.href);
} else {
oml.clickLink(e);
}
}
return false;
}
});
};
(function() {
oml.doHistory = function(action, items, targets, callback) {
items = Ox.makeArray(items);
targets = Ox.makeArray(targets);
if (action == 'copy' || action == 'paste') {
addItems(items, targets[0], addToHistory);
} else if (action == 'cut' || action == 'delete') {
removeItems(items, targets[0], addToHistory);
} else if (action == 'move') {
removeItems(items, targets[0], function() {
addItems(items, targets[1], addToHistory);
});
}
function addToHistory(result, addedItems) {
var actions = {
copy: 'Copying',
cut: 'Cutting',
'delete': 'Deleting',
move: 'Moving',
paste: 'Pasting'
},
length = items.length,
text = Ox._(actions[action]) + ' ' + (
length == 1 ? 'Book' : 'Books'
);
oml.history.add({
action: action,
items: action == 'cut' || action == 'delete' ? [items]
: action == 'copy' || action == 'paste' ? [addedItems]
: [items, addedItems], // move
positions: [],
targets: targets,
text: text
});
callback(result);
}
};
oml.redoHistory = function(callback) {
var object = oml.history.redo();
if (object) {
if (object.action == 'copy' || object.action == 'paste') {
addItems(object.items[0], object.targets[0], done);
} else if (object.action == 'cut' || object.action == 'delete') {
removeItems(object.items[0], object.targets[0], done);
} else if (object.action == 'move') {
removeItems(object.items[0], object.targets[0], function() {
addItems(object.items[1], object.targets[1], done);
});
}
}
function done() {
doneHistory(object, callback);
}
};
oml.undoHistory = function(callback) {
var object = oml.history.undo();
if (object) {
if (object.action == 'copy' || object.action == 'paste') {
removeItems(object.items[0], object.targets[0], done);
} else if (object.action == 'cut' || object.action == 'delete') {
addItems(object.items[0], object.targets[0], done);
} else if (object.action == 'move') {
removeItems(object.items[1], object.targets[1], function() {
addItems(object.items[0], object.targets[0], done);
});
}
}
function done() {
doneHistory(object, callback);
}
};
function addItems(items, target, callback) {
oml.api.find({
query: {
conditions: [{
key: 'list',
operator: '==',
value: target
}],
operator: '&'
},
positions: items
}, function(result) {
var existingItems = Object.keys(result.data.positions),
addedItems = items.filter(function(item) {
return !Ox.contains(existingItems, item);
});
if (addedItems.length) {
oml.api.addListItems({
items: addedItems,
list: target
}, function(result) {
Ox.Request.clearCache();
callback(result, addedItems);
});
} else {
callback(null, []);
}
});
}
function doneHistory(object, callback) {
var list, listData, ui = oml.user.ui;
Ox.Request.clearCache('find');
object.targets.filter(function(list) {
return list != ui._list;
}).forEach(function(list) {
listData = oml.getListData(list);
oml.api.find({
query: {
conditions: [{
key: 'list',
operator: '==',
value: list
}],
operator: '&'
}
}, function(result) {
oml.$ui.folderList[listData.folder].value(
list, 'items', result.data.items
);
});
});
if (Ox.contains(object.targets, ui._list)) {
// FIXME: Why is this timeout needed?
setTimeout(oml.reloadLists, 250);
}
callback && callback();
}
function removeItems(items, target, callback) {
oml.api.removeListItems({
items: items,
list: target
}, callback);
}
}());
oml.enableDragAndDrop = function($list, canMove) {
var $tooltip = Ox.Tooltip({
animate: false
}),
drag = {},
scrollInterval,
ui = oml.user.ui;
$list.bindEvent({
draganddropstart: function(data) {
var $lists = oml.$ui.libraryList.concat(oml.$ui.inboxList).concat(oml.$ui.folderList);
drag.action = 'copy';
drag.ids = $list.options('selected');
drag.item = drag.ids.length == 1
? Ox.decodeHTMLEntities($list.value(drag.ids[0], 'title'))
: drag.ids.length;
drag.source = oml.getListData();
drag.targets = {};
$lists.forEach(function($list) {
$list.addClass('OxDroppable').find('.OxItem').each(function() {
var $item = $(this),
id = $item.data('id'),
data = oml.getListData(id);
drag.targets[id] = Ox.extend(data, {
editable: data.editable || (
data.type == 'library'
&& drag.source.user != ''
&& data.user == ''
) || (
data.type == 'library'
&& drag.source.user == ''
&& data.user != ''
),
selected: data.id == ui._list
}, data);
if (!drag.targets[id].selected && drag.targets[id].editable) {
$item.addClass('OxDroppable');
}
});
});
$tooltip.options({title: getTitle()}).show(data.event);
Ox.$window.on({
keydown: keydown,
keyup: keyup
});
},
draganddrop: function(data) {
var event = data.event;
$tooltip.options({
title: getTitle(event)
}).show(event);
if (scrollInterval && !isAtListsTop(event) && !isAtListsBottom(event)) {
clearInterval(scrollInterval);
scrollInterval = 0;
}
},
draganddroppause: function(data) {
var event = data.event, scroll, title,
ui = oml.user.ui,
$parent, $grandparent, $panel;
if (!ui.showSidebar) {
if (event.clientX < 16 && event.clientY >= 44
&& event.clientY < window.innerHeight - 16
) {
oml.$ui.mainPanel.toggleElement(0);
}
} else {
$parent = $(event.target).parent();
$grandparent = $parent.parent();
$panel = $parent.is('.OxCollapsePanel') ? $parent
: $grandparent.is('.OxCollapsePanel') ? $grandparent
: null;
if ($panel) {
title = $panel.children('.OxBar').children('.OxTitle')
.html().split(' ')[0].toLowerCase();
if (!ui.showFolder[title]) {
Ox.$elements[$panel.data('oxid')].options({
collapsed: false
});
}
}
if (!scrollInterval) {
scroll = isAtListsTop(event) ? -16
: isAtListsBottom(event) ? 16
: 0
if (scroll) {
scrollInterval = setInterval(function() {
oml.$ui.folders.scrollTop(
oml.$ui.folders.scrollTop() + scroll
);
}, 100);
}
}
}
},
draganddropenter: function(data) {
var $parent = $(data.event.target).parent(),
$item = $parent.is('.OxItem') ? $parent : $parent.parent(),
$list = $item.parent().parent().parent().parent();
if ($list.is('.OxDroppable')) {
$item.addClass('OxDrop');
drag.target = drag.targets[$item.data('id')];
} else {
drag.target = null;
}
},
draganddropleave: function(data) {
var $parent = $(data.event.target).parent(),
$item = $parent.is('.OxItem') ? $parent : $parent.parent();
if ($item.is('.OxDroppable')) {
$item.removeClass('OxDrop');
drag.target = null;
}
},
draganddropend: function(data) {
var targets;
Ox.$window.off({
keydown: keydown,
keyup: keyup
});
if (
drag.target && drag.target.editable && !drag.target.selected
&& (drag.action == 'copy' || drag.source.editable)
) {
var targets = drag.action == 'copy' ? drag.target.id
: [oml.user.ui._list, drag.target.id];
oml.doHistory(drag.action, data.ids, targets, function() {
Ox.Request.clearCache('find');
oml.api.find({
query: {
conditions: [{
key: 'list',
operator: '==',
value: drag.target.id
}],
operator: '&'
}
}, function(result) {
/* FIXME
oml.$ui.folderList[drag.target.folder].value(
drag.target.id, 'items', result.data.items
);
*/
});
oml.$ui.folders.updateItems();
if (drag.action == 'move') {
oml.$ui.list.updateElement();
}
cleanup(250);
});
} else {
cleanup()
}
}
});
function cleanup(ms) {
ms = ms || 0;
drag = {};
clearInterval(scrollInterval);
scrollInterval = 0;
setTimeout(function() {
$('.OxDroppable').removeClass('OxDroppable');
$('.OxDrop').removeClass('OxDrop');
$tooltip.hide();
}, ms);
}
function getTitle() {
var image, text,
actionText = drag.action == 'copy' ? (
drag.source.user == '' ? 'copy' : 'download'
) : 'move',
itemText = Ox.isString(drag.item)
? '"' + Ox.encodeHTMLEntities(Ox.truncate(drag.item, 32)) + '"'
: Ox._('{0} books', [drag.item]),
targetText;
if (drag.action == 'move') {
if (drag.source.user != '') {
text = Ox._('You can only remove books
from your own lists.');
} else if (drag.source.type == 'library') {
text = Ox._('You cannot move books
out of your library.');
} else if (drag.source.type == 'smart') {
text = Ox._('You cannot move books
out of a smart list.');
}
} else if (drag.target) {
targetText = drag.target.type == 'libraries' ? Ox._('a library')
: drag.target.type == 'library' ?
drag.target.user == ''
? Ox._('your library')
: Ox._('{0}\'s library', [Ox.encodeHTMLEntities(Ox.truncate(drag.target.user, 32))])
: Ox._('the list "{0}"', [Ox.encodeHTMLEntities(Ox.truncate(drag.target.name, 32))]);
if (
(
drag.target.type == 'library'
&& drag.source.user == ''
&& drag.target.user == ''
)
|| drag.target.selected
) {
text = Ox._('{0}
is already in {1}.', [
Ox._(itemText[0] == '"' ? '' : 'These ') + itemText,
targetText
]);
} else if (drag.target.user != '' && drag.target.type != 'library') {
text = Ox._(
'You can only {0} books
to your own {1}.',
[actionText, drag.target.type == 'library' ? 'library' : 'lists']
);
} else if (drag.target.type == 'smart') {
text = Ox._('You cannot {0} books
to a smart list.', [actionText]);
}
}
if (text) {
image = 'symbolClose'
} else {
image = drag.action == 'copy' ? (
drag.source.user == '' ? 'symbolAdd' : 'symbolDownload'
) : 'symbolRemove',
text = Ox._(Ox.toTitleCase(actionText)) + ' ' + (
Ox.isString(drag.item)
? '"' + Ox.encodeHTMLEntities(Ox.truncate(drag.item, 32)) + '"'
: drag.item + ' ' + 'books'
) + '
' + (
drag.target && drag.target.editable && !drag.target.selected
? Ox._('to {0}.', [targetText])
: drag.source.user == ''
? Ox._('to {0} list.', [ui._list == ':' ? 'a' : 'another'])
: Ox._('to your library or to one of your lists.')
);
}
return $('