1
0
Fork 0
forked from 0x2620/oxjs

remove unneeded Ox. prefix from path and file names

This commit is contained in:
rolux 2014-09-26 15:51:50 +02:00
commit 51696562f1
1365 changed files with 43 additions and 43 deletions

285
source/UI/js/List/Chart.js vendored Normal file
View file

@ -0,0 +1,285 @@
'use strict';
/*@
Ox.Chart <f> Bar Chart
options <o> Options
color <[n]|[[n]]|[128, 128, 128]> Bar color
data <o> {k: v, ...} or {k: {k: v, ...}, ...}
formatKey <f|null> Format function for keys
keyAlign <s|'right'> Alignment of keys
keyWidth <n|128> Width of keys
limit <n|0> Number of items, or 0 for all
rows <n|1> undocumented
sort <o|{key: 'value', operator: '-'}> Sort
title <s|''> Chart title
width <n|512> Chart width
self <o> shared private variable
([options[, self]]) -> <o:Ox.Element> Chart object
@*/
Ox.Chart = function(options, self) {
self = self || {};
var that = Ox.Element({}, self)
.defaults({
color: [128, 128, 128],
data: {},
formatKey: null,
keyAlign: 'right',
keyWidth: 128,
limit: 0,
rows: 1,
sort: {key: 'value', operator: '-'},
sortKey: null,
title: '',
width: 512
})
.options(options || {})
.update({
width: function() {
self.$chart.empty();
renderChart();
}
})
.addClass('OxChart');
self.valueWidth = self.options.width - self.options.keyWidth;
self.keys = Object.keys(self.options.data);
if (Ox.isObject(self.options.data[self.keys[0]])) {
if (Ox.isUndefined(options.color)) {
self.options.color = [
[192, 64, 64], [ 64, 192, 64], [ 64, 64, 192],
[192, 192, 64], [ 64, 192, 192], [192, 64, 192],
[192, 128, 64], [ 64, 192, 128], [128, 64, 192],
[192, 64, 128], [128, 192, 64], [ 64, 128, 192]
];
}
self.subData = {};
}
self.sort = {};
self.totals = {};
Ox.forEach(self.options.data, function(value, key) {
self.totals[key] = self.subData ? Ox.sum(value) : value;
if (self.subData) {
Object.keys(value).forEach(function(subKey) {
self.subData[subKey] = (self.subData[subKey] || 0) + value[subKey];
});
}
self.sort[key] = key.replace(/(\d+)/g, function(number) {
return Ox.pad(parseInt(number, 10), 16);
});
});
self.max = Ox.max(self.totals);
self.sum = Ox.sum(self.totals);
if (self.subData) {
Ox.forEach(self.subData, function(subValue, subKey) {
self.sort[subKey] = subKey.replace(/(\d+)/g, function(number) {
return Ox.pad(parseInt(number, 10), 16);
});
});
self.subKeys = Object.keys(self.subData).sort(function(a, b) {
var aValue = self.subData[a],
bValue = self.subData[b];
return a === '' ? 1
: b === '' ? -1
: self.sort[a] < self.sort[b] ? -1
: self.sort[a] > self.sort[b] ? 1
: 0;
});
}
self.items = self.keys.map(function(key) {
return {
key: key,
keySort: self.sort[key],
value: self.options.data[key],
valueSort: self.subData ? self.totals[key] : self.options.data[key]
};
});
self.sortBy = self.options.sort.key == 'key'
? [
{key: 'keySort', operator: self.options.sort.operator}
]
: [
{key: 'valueSort', operator: self.options.sort.operator},
{key: 'keySort', operator: '+'}
]
if (self.options.limit) {
self.items = Ox.sortBy(
self.items, self.sortBy
).slice(0, self.options.limit);
self.max = Ox.max(self.items.map(function(item) {
return self.subData ? Ox.sum(item.value) : item.value;
}));
}
self.max = self.max || 1;
if (self.options.rows == 2) {
self.row = 0;
}
self.$title = Ox.Bar({size: 16})
.append(
$('<div>')
.css({margin: '1px 0 0 4px'})
.html(self.options.title)
)
.appendTo(that);
self.$chart = $('<div>')
.css({position: 'absolute', top: '16px'})
.append(renderChart())
.appendTo(that);
function getColumns() {
return [
{
align: self.options.keyAlign,
format: self.options.formatKey,
id: 'key',
width: self.options.keyWidth,
visible: true
},
{
format: renderValue,
id: 'value',
width: self.valueWidth,
visible: true
}
];
}
function getWidths(values) {
var max, maxKeys,
total = Ox.sum(values),
totalWidth = Math.ceil(total / self.max * self.valueWidth),
widths = {};
Ox.forEach(values, function(value, key) {
widths[key] = Math.round(value / total * totalWidth);
});
while (Ox.sum(widths) != totalWidth) {
max = Ox.max(widths);
maxKeys = Object.keys(widths).filter(function(key) {
return widths[key] == max;
});
widths[maxKeys[0]] += Ox.sum(widths) < totalWidth ? 1 : -1;
}
return widths;
}
function renderChart() {
that.css({
width: self.options.width + 'px',
height: 16 + self.items.length * 16 + 'px',
overflowY: 'hidden'
});
return Ox.TableList({
columns: getColumns(),
items: self.items,
max: 0,
min: 0,
pageLength: self.items.length,
sort: self.sortBy,
width: self.options.width,
unique: 'key'
})
.css({
left: 0,
top: 0,
width: self.options.width + 'px',
height: self.items.length * 16 + 'px'
});
}
function renderValue(value, data) {
var $bars = [],
$element,
colors = [], len, widths;
if (!self.subData) {
$element = $bars[0] = Ox.Element({
element: '<div>',
tooltip: Ox.formatNumber(value)
+ ' (' + Ox.formatPercent(value * self.options.rows, self.sum, 2) + ')'
})
.css({
width: Math.ceil(value / self.max * self.valueWidth) + 'px',
height: '14px',
borderRadius: '4px',
marginLeft: '-4px'
});
colors[0] = Ox.isFunction(self.options.color)
? self.options.color(data.key) : self.options.color;
} else {
$element = $('<div>')
.css({
width: Math.ceil(self.totals[data.key] / self.max * self.valueWidth) + 'px',
height: '14px',
marginLeft: '-4px'
});
len = Ox.len(value);
widths = getWidths(value);
self.subKeys.forEach(function(subKey, subKeyIndex) {
var i = $bars.length,
subValue = value[subKey];
if (subValue) {
$bars[i] = Ox.Element({
element: '<div>',
/*
tooltip: Ox.formatNumber(self.totals[data.key])
+ ' (' + Ox.formatPercent(self.totals[data.key] * self.options.rows, self.sum, 2) + ')'
+ '<br>' + subKey + ': ' + Ox.formatNumber(subValue)
+ ' (' + Ox.formatPercent(subValue, self.totals[data.key], 2) + ')'
*/
tooltip: Ox.formatNumber(self.totals[data.key])
+ ' (' + Ox.formatPercent(self.totals[data.key] * self.options.rows, self.sum, 2) + ')'
})
.css({
float: 'left',
width: widths[subKey] + 'px',
height: '14px',
borderTopLeftRadius: i == 0 ? '4px' : 0,
borderBottomLeftRadius: i == 0 ? '4px' : 0,
borderTopRightRadius: i == len - 1 ? '4px' : 0,
borderBottomRightRadius: i == len - 1 ? '4px' : 0
})
.appendTo($element);
colors[i] = subKey == '' ? [128, 128, 128]
: Ox.isArray(self.options.color)
? self.options.color[subKeyIndex % self.options.color.length]
: Ox.isObject(self.options.color)
? self.options.color[subKey]
: self.options.color(subKey);
}
});
}
$bars.forEach(function($bar, i) {
/*
if (self.options.rows == 2) {
colors[i] = colors[i].map(function(v) {
return v + (self.row % 2 == 0 ? 16 : -16);
});
}
*/
['moz', 'o', 'webkit'].forEach(function(browser) {
$bar.css({
backgroundImage: '-' + browser
+ '-linear-gradient(top, rgb(' + colors[i].map(function(v) {
return Ox.limit(v + 16, 0, 255);
}).join(', ') + '), rgb(' + colors[i].map(function(v) {
return Ox.limit(v - 16, 0, 255);
}) + '))'
});
});
});
if (self.options.rows == 2) {
self.row++;
}
return $element;
}
return that;
};

View file

@ -0,0 +1,212 @@
'use strict';
/*@
Ox.ColumnList <f> Column List Widget
experimental
@*/
Ox.ColumnList = function(options, self) {
self = self || {};
var that = Ox.Element({}, self)
.defaults({
columns: [],
custom: {},
items: [],
list: 'table',
query: {conditions: [], operator: '&'},
resize: null,
width: 768
})
.options(options || {})
.update({
query: updateQuery,
width: function() {
self.columnWidths = getColumnWidths();
self.$panel.size(0, self.columnWidths[0]);
self.$panel.size(2, self.columnWidths[2]);
self.$lists.forEach(function($list, i) {
$list.options({itemWidth: self.columnWidths[i]});
});
}
})
.addClass('OxColumnList');
self.numberOfColumns = self.options.columns.length;
self.columnWidths = getColumnWidths();
self.flatItems = [];
self.ids = [{}, {}, {}];
self.options.items.forEach(function(item0) {
item0.items.forEach(function(item1) {
self.ids[1][item1.id] = [item0.id];
item1.items.forEach(function(item2) {
self.ids[2][item2.id] = [item0.id, item1.id];
self.flatItems.push(item2);
});
});
});
self.api = Ox.api(self.flatItems);
self.$lists = self.options.columns.map(function(column, i) {
return Ox.CustomList({
item: self.options.columns[i].item,
itemHeight: self.options.columns[i].itemHeight,
items: getItems(i),
itemWidth: self.columnWidths[i],
keys: self.options.columns[i].keys,
// FIXME: undefined max will overwrite CustomList default
max: self.options.columns[i].max,
resize: self.options.resize,
scrollbarVisible: true,
selected: self.options.columns[i].selected,
sort: self.options.columns[i].sort,
unique: 'id'
})
.bindEvent({
key_left: function() {
if (i > 0) {
self.$lists[i - 1].gainFocus();
that.triggerEvent('select', {
id: self.options.columns[i - 1].id,
ids: self.$lists[i - 1].options('selected')
});
}
},
key_right: function() {
var index, object, selected = self.$lists[i].options('selected');
if (selected.length) {
if (i < self.numberOfColumns - 1) {
if (self.$lists[i + 1].options('selected').length == 0) {
self.$lists[i + 1].selectPosition(0);
}
self.$lists[i + 1].gainFocus();
that.triggerEvent('select', {
id: self.options.columns[i + 1].id,
ids: self.$lists[i + 1].options('selected')
});
}
}
},
open: function(data) {
that.triggerEvent('open', {
id: column.id,
ids: data.ids
});
},
select: function(data) {
self.options.columns[i].selected = data.ids;
if (i < self.numberOfColumns - 1) {
self.$lists[i + 1].options({items: getItems(i + 1)});
}
if (i == 0 || data.ids.length) {
that.triggerEvent('select', {
id: column.id,
ids: data.ids
});
} else {
self.$lists[i - 1].gainFocus();
that.triggerEvent('select', {
id: self.options.columns[i - 1].id,
ids: self.$lists[i - 1].options('selected')
});
}
}
});
});
self.$panel = Ox.SplitPanel({
elements: self.$lists.map(function($list, index) {
return Ox.extend(
{element: $list},
index == 1 ? {} : {size: self.columnWidths[index]}
);
}),
orientation: 'horizontal'
});
that.setElement(self.$panel);
function getColumnWidths() {
return Ox.splitInt(self.options.width, self.numberOfColumns);
}
function getItems(i) {
var items;
if (i == 0) {
items = self.options.items;
} else {
items = [];
self.options.columns[i - 1].selected.forEach(function(id) {
var index;
if (i == 1) {
index = Ox.getIndexById(self.options.items, id);
items = items.concat(
self.options.items[index].items
);
} else if (i == 2) {
index = [];
Ox.forEach(self.options.columns[0].selected, function(id_) {
index[0] = Ox.getIndexById(
self.options.items, id_
);
index[1] = Ox.getIndexById(
self.options.items[index[0]].items, id
);
if (index[1] > -1) {
return false;
}
});
items = items.concat(
self.options.items[index[0]].items[index[1]].items
);
}
});
}
return items;
}
function updateQuery() {
if (self.options.query.conditions.length == 0) {
self.items = self.options.items;
} else {
self.api({
keys: ['id', '_ids'],
query: self.options.query
}, function(result) {
var ids = [[], [], []];
result.data.items.forEach(function(item) {
ids[0].push(self.ids[2][item.id][0]);
ids[1].push(self.ids[2][item.id][1]);
ids[2].push(item.id);
});
self.items = self.options.items.filter(function(item0) {
return Ox.contains(ids[0], item0.id);
});
self.items.forEach(function(item0) {
item0.items = item0.items.filter(function(item1) {
return Ox.contains(ids[1], item1.id);
});
item0.items.forEach(function(item1) {
item1.items = item1.items.filter(function(item2) {
return Ox.contains(ids[2], item2.id);
});
});
});
});
}
self.$lists.forEach(function($list, i) {
$list.options({items: i == 0 ? self.items : []});
});
}
that.sort = function(id, sort) {
var index = Ox.isNumber(id) ? id
: Ox.getIndexById(self.options.columns, id);
self.$lists[index].options({sort: sort});
self.options.columns[index].sort = sort;
};
return that;
};

View file

@ -0,0 +1,156 @@
'use strict';
/*@
Ox.CustomList <f> Custom List Widget
experimental
@*/
Ox.CustomList = function(options, self) {
self = self || {};
var that = Ox.Element({}, self)
.defaults({
draggable: false,
item: null,
itemHeight: 32,
items: null,
itemWidth: 256,
keys: [],
max: -1,
min: 0,
pageLength: 100,
query: {conditions: [], operator: '&'},
resize: null,
scrollbarVisible: false,
selected: [],
sort: [],
sortable: false,
sums: [],
unique: ''
})
.options(options || {})
.update({
items: function() {
self.$list.options({items: self.options.items});
},
itemWidth: function() {
var width = self.options.itemWidth - Ox.UI.SCROLLBAR_SIZE;
if (self.options.resize) {
that.find('.OxItem').each(function(element) {
self.options.resize($(this), width);
});
}
},
query: function() {
self.$list.options({query: self.options.query});
},
selected: function() {
self.$list.options({selected: self.options.selected});
// FIXME: TableList doesn't trigger event here
that.triggerEvent('select', {ids: self.options.selected});
},
sort: function() {
self.$list.options({sort: self.options.sort});
}
})
.addClass('OxCustomList');
self.$list = Ox.List({
construct: function(data) {
return self.options.item(
data, self.options.itemWidth - Ox.UI.SCROLLBAR_SIZE
).addClass('OxTarget');
},
draggable: self.options.draggable,
itemHeight: self.options.itemHeight,
itemWidth: self.options.itemWidth
- self.options.scrollbarVisible * Ox.UI.SCROLLBAR_SIZE,
items: self.options.items,
keys: self.options.keys.concat(self.options.unique),
max: self.options.max,
min: self.options.min,
orientation: 'vertical',
pageLength: self.options.pageLength,
query: Ox.clone(self.options.query, true),
selected: self.options.selected,
sort: Ox.clone(self.options.sort, true),
sortable: self.options.sortable,
sums: self.options.sums,
type: 'text',
unique: self.options.unique
})
.css({
top: 0,
overflowY: (self.options.scrollbarVisible ? 'scroll' : 'hidden')
})
.bindEvent(function(data, event) {
if (event == 'select') {
self.options.selected = data.ids;
}
that.triggerEvent(event, data);
})
.appendTo(that);
that.api = self.$list.options('items');
/*@
gainFocus <f> gain Focus
@*/
that.gainFocus = function() {
self.$list.gainFocus();
return that;
};
that.getPasteIndex = function() {
return self.$list.getPasteIndex();
};
/*@
hasFocus <f> has Focus
@*/
that.hasFocus = function() {
return self.$list.hasFocus();
};
that.invertSelection = function() {
self.$list.invertSelection();
return that;
};
/*@
loseFocus <f> lose Focus
@*/
that.loseFocus = function() {
self.$list.loseFocus();
return that;
};
that.selectAll = function() {
self.$list.selectAll();
return that;
};
/*@
selectPosition <f> select position
@*/
that.selectPosition = function(pos) {
self.$list.selectPosition(pos);
return that;
};
that.selectSelected = function(offset) {
that.$list.selectSelected(offset);
return that;
};
/*@
size <f> size
@*/
that.size = function() {
self.$list.size();
return that;
};
return that;
};

View file

@ -0,0 +1,226 @@
'use strict';
/*@
Ox.IconItem <f> IconItem Object
options <o> Options object
borderRadius <n|0> Border radius for icon images
find <s|''> String to be highlighted
iconHeight <n|128> Icon height
iconWidth <n|128> Icon width
imageHeight <n|128> Icon image height
imageWidth <n|128> Icon image width
id <s> Element id
info <s> Icon info
size <n|128> Icon size
title <s> Title
url <s> Icon url
self <o> Shared private variable
([options[, self]]) -> <o:Ox.Element> IconItem Object
@*/
Ox.IconItem = function(options, self) {
//Ox.Log('List', 'IconItem', options, self)
self = self || {};
var that = Ox.Element({}, self)
.defaults({
borderRadius: 0,
extra: null,
find: '',
iconHeight: 128,
iconWidth: 128,
imageHeight: 128,
imageWidth: 128,
itemHeight: 192,
itemWidth: 128,
id: '',
info: '',
title: '',
url: ''
})
.options(options || {});
Ox.extend(self, {
fontSize: self.options.itemWidth == 64 ? 6 : 9,
infoIsObject: Ox.isObject(self.options.info),
lineLength: self.options.itemWidth == 64 ? 15 : 23,
lines: self.options.itemWidth == 64 ? 4 : 5,
url: Ox.UI.PATH + 'png/transparent.png'
});
self.title = formatText(self.options.title, self.lines - 1 - self.infoIsObject, self.lineLength);
if (!self.infoIsObject) {
self.info = formatText(self.options.info, 5 - self.title.split('<br/>').length, self.lineLength);
} else {
self.title = $('<div>').css({fontSize: self.fontSize + 'px'}).html(self.title);
self.info = $('<div>').append(
self.options.info.css(Ox.extend(self.options.info.css('width') == '0px' ? {
width: Math.round(self.options.itemWidth / 2) + 'px'
} : {}, {
padding: 0,
margin: '1px auto',
fontSize: self.fontSize + 'px',
textShadow: 'none'
}))
);
}
that.css({
// 2 * 2 px margin (.css), 2 * 2 px border (here)
width: self.options.itemWidth + 4 + 'px',
height: self.options.itemHeight + + 4 + 'px'
});
that.$icon = $('<div>')
.addClass('OxIcon')
.css({
top: (self.options.iconWidth == 64 ? -64 : -122) + 'px',
width: self.options.iconWidth + 4 + 'px',
height: self.options.iconHeight + 4 + 'px'
});
that.$iconImage = $('<img>')
.addClass('OxLoading OxTarget')
.attr({
src: self.url
})
.css({
width: self.options.imageWidth + 'px',
height: self.options.imageHeight + 'px',
borderRadius: self.options.borderRadius + 4 + 'px'
})
.mousedown(mousedown)
.mouseenter(mouseenter)
.mouseleave(mouseleave);
self.options.url && that.$iconImage.one('load', load);
that.$textBox = $('<div>')
.addClass('OxText')
.css({
top: self.options.iconHeight - (self.options.itemWidth == 64 ? 32 : 62) + 'px',
width: self.options.itemWidth + 4 + 'px',
height: (self.options.itemWidth == 64 ? 30 : 58) + 'px'
});
that.$text = $('<div>')
.addClass('OxTarget')
.css({
fontSize: self.fontSize + 'px'
})
.mouseenter(mouseenter)
.mouseleave(mouseleave);
if (!self.infoIsObject) {
that.$text.html(
(self.title ? self.title + '<br/>' : '')
+ '<span class="OxInfo">' + self.info + '</span>'
);
} else {
that.$text.append(self.title).append(self.info);
}
that.$reflection = $('<div>')
.addClass('OxReflection')
.css({
top: self.options.iconHeight + (self.options.itemWidth == 64 ? 0 : 2) + 'px',
width: self.options.itemWidth + 4 + 'px',
height: self.options.itemHeight - self.options.iconHeight + 'px'
});
that.$reflectionImage = $('<img>')
.addClass('OxLoading')
.attr({
src: self.url
})
.css({
width: self.options.imageWidth + 'px',
height: self.options.imageHeight + 'px',
// firefox is 1px off when centering images with odd width and scaleY(-1)
paddingLeft: ($.browser.mozilla && self.options.imageWidth % 2 ? 1 : 0) + 'px',
borderRadius: self.options.borderRadius + 'px'
});
that.$gradient = $('<div>')
.css({
// `+2` is a temporary fix for https://code.google.com/p/chromium/issues/detail?id=167198
width: self.options.itemWidth + 2 + 'px',
height: self.options.itemWidth / 2 + 'px'
});
that.append(
that.$reflection.append(
that.$reflectionImage
).append(
that.$gradient
)
).append(
that.$textBox.append(
that.$text
)
).append(
that.$icon.append(
that.$iconImage
)
);
if (self.options.extra) {
that.$extra = $('<div>')
.addClass('OxTarget')
.css({
position: 'absolute',
left: 0,
right: 0,
bottom: 0,
width: self.options.imageWidth + 'px',
height: self.options.imageHeight + 'px',
border: '2px solid transparent',
margin: 'auto',
cursor: 'pointer',
overflow: 'hidden'
})
that.$icon.append(
that.$extra.append(
self.options.extra
)
);
}
function formatText(text, maxLines, maxLength) {
text = Ox.isArray(text) ? text.join(', ') : text;
var lines = Ox.wordwrap(text, maxLength, true).split('\n');
// if the text has too many lines, replace the last line with the
// truncated rest (including the last line) and discard all extra lines
if (lines.length > maxLines) {
lines[maxLines - 1] = Ox.truncate(
lines.slice(maxLines - 1).join(''), 'center', maxLength
).replace('…', '<span class="OxLight">…</span>');
lines = lines.slice(0, maxLines);
}
return Ox.highlight(
lines.join('<br/>'), self.options.find, 'OxHighlight', true
);
}
function load() {
that.$iconImage.attr({
src: self.options.url
})
.one('load', function() {
that.$iconImage.removeClass('OxLoading');
that.$reflectionImage
.attr({
src: self.options.url
})
.removeClass('OxLoading');
});
}
function mousedown(e) {
// fixme: preventDefault keeps image from being draggable in safari - but also keeps the list from getting focus
// e.preventDefault();
}
function mouseenter() {
that.addClass('OxHover');
}
function mouseleave() {
that.removeClass('OxHover');
}
return that;
};

View file

@ -0,0 +1,308 @@
'use strict';
/*@
Ox.IconList <f> IconList Object
options <o> Options object
borderRadius <n|0> border radius for icon images
centered <b|false> scroll list so selection is always centered
defaultRatio <n|1> aspect ratio of icon placeholders
draggable <b|false> If true, items can be dragged
fixedRatio <b|n|false> if set to a number, icons have a fixed ratio
id <s|''> element id
item <f|null> called with data, sort, size,
extends data with information needed for constructor
itemConstructor <f|Ox.IconItem> contructor used to create item
items <f|null> items array or callback function
keys <a|[]> available item keys
max <n|-1> maximum selected selected items
min <n|0> minimum of selcted items
orientation <s|both> orientation ("horizontal", "vertical" or "both")
pageLength <n|100> Number of items per page (if orientation != "both")
query <o> Query
selectAsYouType <s|''> If set to a key, enables select-as-you-type
selected <a|[]> array of selected items
size <n|128> list size
sort <a|[]> sort keys
sums <[s]|[]> Sums to be included in totals
self <o> Shared private variable
([options[, self]]) -> <o:Ox.List> IconList Object
@*/
Ox.IconList = function(options, self) {
self = self || {};
var that = Ox.Element({}, self)
.defaults({
borderRadius: 0,
centered: false,
defaultRatio: 1,
draggable: false,
find: '',
fixedRatio: false,
id: '',
item: null,
itemConstructor: Ox.IconItem,
items: null,
keys: [],
max: -1,
min: 0,
orientation: 'both',
pageLength: 100,
query: {conditions: [], operator: '&'},
selectAsYouType: '',
selected: [],
size: 128,
sort: [],
sums: [],
unique: ''
})
.options(options || {})
.update({
items: function() {
self.$list.options({items: self.options.items});
},
query: function() {
self.$list.options({query: self.options.query});
},
selected: function() {
self.$list.options({selected: self.options.selected});
},
sort: function() {
updateKeys();
self.$list.options({sort: self.options.sort});
}
});
if (self.options.fixedRatio) {
self.options.defaultRatio = self.options.fixedRatio;
}
if (Ox.isArray(self.options.items)) {
self.options.keys = Ox.unique(Ox.flatten(
self.options.items.map(function(item) {
return Object.keys(item);
})
));
}
self.iconWidth = self.options.size;
self.iconHeight = self.options.fixedRatio > 1
? Math.round(self.options.size / self.options.fixedRatio)
: self.options.size;
self.itemWidth = self.options.size;
self.itemHeight = self.iconHeight + self.options.size * 0.5;
self.$list = Ox.List({
centered: self.options.centered,
// fixme: change all occurences of construct to render
construct: constructItem,
draggable: self.options.draggable,
id: self.options.id,
itemHeight: self.itemHeight,
items: self.options.items,
itemWidth: self.itemWidth,
keys: self.options.keys,
max: self.options.max,
min: self.options.min,
orientation: self.options.orientation,
pageLength: self.options.pageLength,
query: self.options.query,
selectAsYouType: self.options.selectAsYouType,
selected: self.options.selected,
sort: self.options.sort,
sums: self.options.sums,
type: 'icon',
unique: self.options.unique
})
.addClass('OxIconList Ox' + Ox.toTitleCase(self.options.orientation))
.bindEvent(function(data, event) {
if (event == 'select') {
self.options.selected = data.ids;
}
that.triggerEvent(event, data);
});
that.setElement(self.$list);
updateKeys();
function constructItem(data) {
var isEmpty = Ox.isEmpty(data);
data = !isEmpty
? self.options.item(data, self.options.sort, self.options.size)
: {
width: Math.round(self.options.size * (
self.options.defaultRatio >= 1 ? 1 : self.options.defaultRatio
)),
height: Math.round(self.options.size / (
self.options.defaultRatio <= 1 ? 1 : self.options.defaultRatio
))
};
return self.options.itemConstructor(Ox.extend(data, {
borderRadius: self.options.borderRadius,
find: self.options.find,
iconHeight: self.iconHeight,
iconWidth: self.iconWidth,
imageHeight: data.height,
imageWidth: data.width,
itemHeight: self.itemHeight,
itemWidth: self.itemWidth
//height: Math.round(self.options.size / (ratio <= 1 ? 1 : ratio)),
//size: self.options.size,
//width: Math.round(self.options.size * (ratio >= 1 ? 1 : ratio))
}));
}
function updateKeys() {
self.$list.options({
keys: Ox.unique(
[self.options.sort[0].key].concat(self.options.keys)
)
});
}
/*@
closePreview <f> close preview
() -> <o> the list
@*/
that.closePreview = function() {
self.$list.closePreview();
return that;
};
/*@
gainFocus <f> gainFocus
@*/
that.gainFocus = function() {
self.$list.gainFocus();
return that;
};
that.getPasteIndex = function() {
return self.$list.getPasteIndex();
};
/*@
hasFocus <f> hasFocus
@*/
that.hasFocus = function() {
return self.$list.hasFocus();
};
that.invertSelection = function() {
self.$list.invertSelection();
return that;
};
/*@
loseFocus <f> loseFocus
@*/
that.loseFocus = function() {
self.$list.loseFocus();
return that;
};
/*@
openPreview <f> openPreview
@*/
that.openPreview = function() {
self.$list.openPreview();
return that;
};
/*@
reloadList <f> reload list
() -> <o> the list
@*/
that.reloadList = function() {
self.$list.reloadList();
return that;
};
/*@
scrollToSelection <f> scroll list to selection
() -> <o> the list
@*/
that.scrollToSelection = function() {
self.$list.scrollToSelection();
return that;
};
that.selectAll = function() {
self.$list.selectAll();
return that;
};
that.selectPosition = function(pos) {
self.$list.selectPosition(pos);
return that;
};
that.selectSelected = function(offset) {
self.$list.selectSelected(offset);
return that;
};
/*@
size <f> get size of list
() -> <n> size
@*/
that.size = function() {
self.$list.size();
return that;
};
// fixme: deprecate, use options()
/*@
sortList <f> sort list
(key, operator) -> <o> the list
key <s> sort key
operator <s> sort operator ("+" or "-")
@*/
that.sortList = function(key, operator) {
self.options.sort = [{
key: key,
operator: operator
}];
updateKeys();
self.$list.sortList(key, operator);
return that;
};
/*@
value <f> get/set value of item in list
(id) -> <o> get all data for item
(id, key) -> <s> get value of key of item with id
(id, key, value) -> <f> set value, returns IconList
(id, {key: value, ...}) -> <f> set values, returns IconList
@*/
that.value = function() {
var args = Ox.slice(arguments),
id = args.shift(),
sort = false;
if (arguments.length == 1) {
return self.$list.value(id);
} else if (arguments.length == 2 && Ox.isString(arguments[1])) {
return self.$list.value(id, arguments[1]);
} else {
Ox.forEach(Ox.makeObject(args), function(value, key) {
self.$list.value(id, key, value);
if (key == self.unique) {
// unique id has changed
self.options.selected = self.options.selected.map(function(id_) {
return id_ == id ? value : id_
});
id = value;
}
if (key == self.options.sort[0].key) {
// sort key has changed
sort = true;
}
});
sort && self.$list.sort();
return that;
}
};
return that;
};

View file

@ -0,0 +1,303 @@
'use strict';
/*@
Ox.InfoList <f> Info List
options <o> Options
self <o> Shared private variable
([options[, self]]) -> <o:Ox.List> Info List
@*/
Ox.InfoList = function(options, self) {
self = self || {};
var that = Ox.Element({}, self)
.defaults({
borderRadius: 0,
defaultRatio: 1,
draggable: false,
id: '',
item: null,
items: null,
keys: [],
max: -1,
min: 0,
query: {conditions: [], operator: '&'},
selectAsYouType: '',
selected: [],
size: 192,
sort: [],
sums: [],
unique: ''
})
.options(options || {})
.update({
items: function() {
self.$list.options({items: self.options.items});
},
query: function() {
self.$list.options({query: self.options.query});
},
selected: function() {
self.$list.options({selected: self.options.selected});
},
sort: function() {
updateKeys();
self.$list.options({sort: self.options.sort});
},
width: function() {
// FIXME: don't use classname for this lookup
var width = getItemWidth();
$('.OxInfoElement').each(function() {
var $parent = $(this).parent(),
id = parseInt(/OxId(.*?)$/.exec(this.className)[1], 10);
$parent.css({width: width - 144});
$parent.parent().css({width: width - 144});
$parent.parent().parent().css({width: width - 8});
Ox.$elements[id].options({width: width - 152});
});
}
});
self.iconSize = Math.round(self.options.size * 2/3);
self.itemHeight = self.options.size;
that.setElement(
self.$list = Ox.List({
construct: constructItem,
draggable: self.options.draggable,
id: self.options.id,
itemHeight: self.itemHeight,
items: self.options.items,
itemWidth: getItemWidth(),
keys: self.options.keys,
max: self.options.max,
min: self.options.min,
orientation: 'vertical',
pageLength: 10,
query: self.options.query,
selectAsYouType: self.options.selectAsYouType,
selected: self.options.selected,
sort: self.options.sort,
sums: self.options.sums,
type: 'info',
unique: self.options.unique
})
.addClass('OxInfoList')
.bindEvent(function(data, event) {
if (event == 'select') {
self.options.selected = data.ids;
}
that.triggerEvent(event, data);
})
);
updateKeys();
function constructItem(data) {
var isEmpty = Ox.isEmpty(data),
data = !isEmpty
? self.options.item(data, self.options.sort, self.options.size)
: {
icon: {
width: Math.round(self.iconSize * (
self.options.defaultRatio >= 1 ? 1 : self.options.defaultRatio
)),
height: Math.round(self.iconSize / (
self.options.defaultRatio <= 1 ? 1 : self.options.defaultRatio
))
},
info: {}
},
$icon = Ox.Element()
.css({
float: 'left',
width: '132px',
height: '192px',
margin: '2px'
})
.append(
Ox.IconItem(Ox.extend(data.icon, {
borderRadius: self.options.borderRadius,
iconHeight: self.iconSize,
iconWidth: self.iconSize,
imageHeight: data.icon.height,
imageWidth: data.icon.width,
itemHeight: self.itemHeight,
itemWidth: 128
}))
.addClass('OxInfoIcon')
.css({
position: 'absolute'
})
),
$info = Ox.Element()
.css({
float: 'left',
width: getItemWidth() - 144 + 'px',
height: 196 + 'px'
}),
$infobox = Ox.Element()
.css({
position: 'absolute',
width: getItemWidth() - 144 + 'px',
height: 196 + 'px',
marginTop: '-2px',
overflow: 'hidden'
})
.appendTo($info),
$item = Ox.Element()
.css({
width: getItemWidth() - 8 + 'px',
height: 196 + 'px',
margin: '4px'
})
.append($icon)
.append($info);
if (!isEmpty) {
var $element = data.info.element(Ox.extend(data.info.options, {
width: getItemWidth() - 152
}))
.addClass('OxInfoElement');
data.info.css && $element.css(data.info.css);
data.info.events && $element.bindEvent(data.info.events);
$element.addClass('OxId' + $element.oxid); // fixme: needed?
$infobox.append($element);
}
return $item;
}
function getItemWidth(cached) {
if (!cached) {
self.cachedWidth = that.width() - Ox.UI.SCROLLBAR_SIZE;
} else if (!self.cachedWidth || self.cachedWidthTime < +new Date() - 5000) {
self.cachedWidth = that.width() - Ox.UI.SCROLLBAR_SIZE;
self.cachedWidthTime = +new Date();
}
return self.cachedWidth;
}
function updateKeys() {
self.$list.options({
keys: Ox.unique(
[self.options.sort[0].key].concat(self.options.keys)
)
});
}
/*@
closePreview <f> closePreview
@*/
that.closePreview = function() {
self.$list.closePreview();
return that;
};
/*@
gainFocus <f> gainFocus
@*/
that.gainFocus = function() {
self.$list.gainFocus();
return that;
};
that.getPasteIndex = function() {
return self.$list.getPasteIndex();
};
/*@
hasFocus <f> hasFocus
@*/
that.hasFocus = function() {
return self.$list.hasFocus();
};
that.invertSelection = function() {
self.$list.invertSelection();
return that;
};
/*@
loseFocus <f> loseFocus
@*/
that.loseFocus = function() {
self.$list.loseFocus();
return that;
};
/*@
reloadList <f> reloadList
@*/
that.reloadList = function(stayAtPosition) {
self.$list.reloadList(stayAtPosition);
return that;
};
/*@
scrollToSelection <f> scrollToSelection
@*/
that.scrollToSelection = function() {
self.$list.scrollToSelection();
return that;
};
that.selectAll = function() {
self.$list.selectAll();
return that;
};
that.selectPosition = function(pos) {
self.$list.selectPosition(pos);
return that;
};
that.selectSelected = function(offset) {
self.$list.selectSelected(offset);
return that;
};
/*@
size <f> size
@*/
that.size = function() {
self.$list.size();
return that;
};
/*@
sortList <f> sortList
(key, operator) -> <o>
@*/
that.sortList = function(key, operator) {
self.options.sort = [{
key: key,
operator: operator
}];
updateKeys();
self.$list.sortList(key, operator);
return that;
};
/*@
value <f> value
(id) -> values
(id, key) -> value
(id, key, value) -> <o>
(id, {key: value}) -> <o>
@*/
that.value = function() {
var args = Ox.slice(arguments),
id = args.shift();
if (arguments.length == 1) {
return self.$list.value(id);
} else if (arguments.length == 2 && Ox.isString(arguments[1])) {
return self.$list.value(id, arguments[1]);
} else {
Ox.forEach(Ox.makeObject(args), function(value, key) {
self.$list.value(id, key, value);
});
return that;
}
};
return that;
};

1863
source/UI/js/List/List.js Normal file

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,55 @@
'use strict';
/*@
Ox.ListItem <f> ListItem Object
options <o> Options object
construct <f> construct function
data <o|{}> item data
draggable <b|false> can be dragged
position <n|0> item position
unique <s|''> unique key
self <o> Shared private variable
([options[, self]]) -> <o:Ox.Element> ListItem Object
cancel <!> triggered if cancel button is pressed
save <!> triggered if save button is pressed
@*/
Ox.ListItem = function(options, self) {
self = self || {};
var that = Ox.Element({}, self)
.defaults({
construct: null,
data: {},
draggable: false,
position: 0,
unique: ''
})
.options(options || {})
.update({
data: function() {
constructItem(true);
},
position: function() {
that.data({position: self.options.position});
}
});
constructItem();
function constructItem(update) {
var $element = self.options.construct(self.options.data)
.addClass('OxItem')
.data({
id: self.options.data[self.options.unique],
position: self.options.position
});
if (update) {
that.hasClass('OxSelected') && $element.addClass('OxSelected');
}
that.setElement($element);
}
return that;
};

View file

@ -0,0 +1,64 @@
'use strict';
/*@
Ox.SortList <f> Sortable List
options <o> Options object
items <[o]|[]> Items ({id: ..., title: ...})
self <o> Shared private variable
([options[, self]]) -> <o:Ox.Element> SortList Object
@*/
Ox.SortList = function(options, self) {
self = self || {};
var that = Ox.Element({}, self)
.defaults({
items: [],
scrollbarVisible: false
})
.options(options || {})
.update({
items: function() {
self.items = getItems();
self.$list.reloadList();
that.triggerEvent('sort', {
ids: self.items.map(function(item) {
return item.id;
})
});
}
});
self.items = getItems();
self.$list = Ox.TableList({
columns: [
{id: 'title', visible: true}
],
items: self.items,
max: 1,
scrollbarVisible: self.options.scrollbarVisible,
sort: [{key: 'position', operator: '+'}],
sortable: true,
unique: 'id'
})
.bindEvent({
move: function(data) {
self.options.items.sort(function(a, b) {
return data.ids.indexOf(a.id) - data.ids.indexOf(b.id);
});
that.triggerEvent('sort', data);
}
});
function getItems() {
return self.options.items.map(function(item, position) {
return {id: item.id, title: item.title, position: position};
});
}
that.setElement(self.$list);
return that;
};

File diff suppressed because it is too large Load diff

View file

@ -0,0 +1,305 @@
'use strict';
/*@
Ox.TreeList <f> Tree List
options <o> Options object
data <f|null> Data to be parsed as items (needs documentation)
expanded <b|false> If true, and data is not null, all items are expanded
icon <o|f|null> Image URL, or function that returns an image object
items <a|[]> Array of items
max <n|-1> Maximum number of items that can be selected, -1 unlimited
min <n|0> Minimum number of items that have to be selected
selected <a|[]> Selected ids
width <n|256> List width
self <o> Shared private variable
([options[, self]]) -> <o:Ox.List> Tree List Object
@*/
Ox.TreeList = function(options, self) {
// fixme: expanding the last item should cause some scroll
self = self || {};
var that = Ox.Element({}, self)
.defaults({
data: null,
expanded: false,
icon: null,
items: [],
max: 1,
min: 0,
selected: [],
width: 'auto'
})
.options(options || {})
.update({
data: function() {
self.options.items = getItems();
self.$list.options({items: parseItems()});
},
selected: function() {
//self.$list.options({selected: self.options.selected});
selectItem({ids: self.options.selected});
self.$list.scrollToSelection();
},
width: function() {
// ...
}
});
if (self.options.data) {
self.options.items = getItems();
}
that.setElement(
self.$list = Ox.List({
_tree: true,
construct: constructItem,
itemHeight: 16,
items: parseItems(),
itemWidth: self.options.width,
keys: ['expanded', 'id', 'items', 'level', 'title'],
max: self.options.max,
min: self.options.min,
unique: 'id'
})
.addClass('OxTableList OxTreeList')
.css({
width: self.options.width + 'px',
overflowY: 'scroll'
})
.bindEvent(function(data, event) {
if (event == 'anyclick') {
clickItem(data);
} else if (event == 'toggle') {
toggleItems(data);
}
that.triggerEvent(event, data);
})
);
self.options.selected.length && selectItem({ids: self.options.selected});
function clickItem(e) {
var $target = $(e.target),
$item, id, item;
if ($target.is('.OxToggle')) {
$item = $target.parent().parent();
id = $item.data('id');
item = getItemById(id);
toggleItem(item, !item.expanded);
}
}
function constructItem(data) {
var $item = $('<div>').css({
width: self.options.width == 'auto' ? '100%'
: self.options.width - Ox.UI.SCROLLBAR_SIZE + 'px'
}),
$cell = $('<div>').addClass('OxCell').css({width: '8px'}),
$icon = data.id ? getIcon(data.id, data.expanded || (
data.items ? false : null
)) : null,
padding = data.level * 16 - 8;
if (data.level) {
$('<div>')
.addClass('OxCell OxTarget')
.css({width: padding + 'px'})
.appendTo($item);
}
$cell.appendTo($item);
$icon && $icon.addClass(data.items ? 'OxToggle' : 'OxTarget').appendTo($cell);
$('<div>')
.addClass('OxCell OxTarget')
.css({
width: self.options.width - padding - 32 - Ox.UI.SCROLLBAR_SIZE + 'px'
})
.html(data.title || '')
.appendTo($item);
return $item;
}
function getIcon(id, expanded) {
var isFunction = Ox.isFunction(self.options.icon),
$icon = isFunction ? self.options.icon(id, expanded) : null;
if (!$icon) {
if (expanded === null) {
if (!$icon && self.options.icon && !isFunction) {
$icon = $('<img>').attr({src: self.options.icon});
}
} else {
$icon = $('<img>').attr({src: Ox.UI.getImageURL(
'symbol' + (expanded ? 'Down' : 'Right')
)});
}
}
return $icon;
}
function getItemById(id, items, level) {
var ret = null;
items = items || self.options.items;
level = level || 0;
Ox.forEach(items, function(item) {
if (item.id == id) {
ret = Ox.extend(item, {
level: level
});
return false; // break
}
if (item.items) {
ret = getItemById(id, item.items, level + 1);
if (ret) {
return false; // break
}
}
});
return ret;
}
function getItems() {
var items = [];
Ox.sort(Object.keys(self.options.data)).forEach(function(key) {
items.push(parseData(key, self.options.data[key]));
});
return items;
}
function getParent(id, items) {
var ret;
Ox.forEach(items, function(item) {
if (item.items) {
if (Ox.getObjectById(item.items, id)) {
ret = item.id;
} else {
ret = getParent(id, item.items);
}
if (ret) {
return false; // break
}
}
});
return ret;
}
function parseData(key, value) {
var ret = {
id: Ox.uid().toString(),
title: Ox.encodeHTMLEntities(key.toString()) + ': '
},
type = Ox.typeOf(value);
if (type == 'array' || type == 'object') {
ret.expanded = self.options.expanded;
ret.title += Ox.toTitleCase(type)
+ ' <span class="OxLight">[' + Ox.len(value) + ']</span>';
ret.items = type == 'array' ? value.map(function(v, i) {
return parseData(i, v);
}) : Ox.sort(Object.keys(value)).map(function(k) {
return parseData(k, value[k]);
});
} else {
ret.title += (
type == 'function'
? value.toString().split('{')[0]
: Ox.encodeHTMLEntities(JSON.stringify(value))
.replace(/(^&quot;|&quot;$)/g, '<span class="OxLight">"</span>')
);
}
return ret;
}
function parseItems(items, level) {
var ret = [];
items = items || self.options.items;
level = level || 0;
items.forEach(function(item, i) {
if (item.items && self.options.expanded) {
item.expanded = true;
}
var item_ = Ox.extend({level: level}, item, item.items ? {
items: item.expanded
? parseItems(item.items, level + 1)
: []
} : {});
ret.push(item_);
if (item.items) {
ret = ret.concat(item_.items);
}
});
return ret;
}
function selectItem(data) {
var id = data.ids[0], parent = id, parents = [];
while (parent = getParent(parent, self.options.items)) {
parents.push(parent);
}
parents = parents.reverse();
toggleItems({
expanded: true,
ids: parents
});
self.$list.options({selected: data.ids})
}
function toggleItem(item, expanded) {
var $img, pos;
item.expanded = expanded;
that.find('.OxItem').each(function() {
var $item = $(this);
if ($item.data('id') == item.id) {
$img = $item.find('.OxToggle');
pos = $item.data('position');
return false;
}
});
//self.$list.value(item.id, 'expanded', expanded);
$img.attr({
src: getIcon(item.id, expanded).attr('src')
});
if (expanded) {
self.$list.addItems(
pos + 1, parseItems(item.items, item.level + 1)
);
} else {
self.$list.removeItems(
pos + 1, parseItems(item.items, item.level + 1).length
);
}
}
function toggleItems(data) {
data.ids.forEach(function(id, i) {
var item = getItemById(id);
if (item.items && data.expanded != !!item.expanded) {
toggleItem(item, data.expanded);
}
});
}
/*@
gainFocus <f> gainFocus
@*/
that.gainFocus = function() {
self.$list.gainFocus();
return that;
};
/*@
hasFocus <f> hasFocus
@*/
that.hasFocus = function() {
return self.$list.hasFocus();
};
/*@
loseFocus <f> loseFocus
@*/
that.loseFocus = function() {
self.$list.loseFocus();
return that;
};
return that;
};