diff --git a/pandora/static/js/pandora.js b/pandora/static/js/pandora.js
index c38a30660..d0fb9dc80 100644
--- a/pandora/static/js/pandora.js
+++ b/pandora/static/js/pandora.js
@@ -1,34 +1,673 @@
-$(function(){
+$(function() {
+
Ox.debug = Ox.print;
Ox.print = function() {};
- Ox.theme("modern");
+ var $body = $("body"),
+ $document = $(document),
+ $window = $(window),
+ config = {
+ archiveId: "oxdb",
+ archiveName: "0xDB",
+ findKeys: [
+ { id: "all", title: "All" },
+ { id: "title", title: "Title" },
+ { id: "director", title: "Director" },
+ { id: "country", title: "Country" },
+ { id: "year", title: "Year" },
+ { id: "language", title: "Language" },
+ { id: "writer", title: "Writer" },
+ { id: "producer", title: "Producer" },
+ { id: "cinematographer", title: "Cinematographer" },
+ { id: "editor", title: "Editor" },
+ { id: "actor", title: "Actor" },
+ { id: "character", title: "Character" },
+ { id: "name", title: "Name" },
+ { id: "genre", title: "Genre" },
+ { id: "keyword", title: "Keyword" },
+ { id: "summary", title: "Summary" },
+ { id: "dialog", title: "Dialog" }
+ ],
+ groups: ["director", "country", "year", "language", "genre"],
+ itemViews: [
+ { id: "info", title: "Info" },
+ { id: "statistics", title: "Statistics" },
+ { id: "clips", title: "Clips" },
+ { id: "timeline", title: "Timeline" },
+ { id: "map", title: "Map" },
+ { id: "calendar", title: "Calendar" },
+ { id: "files", title: "Files", admin: true }
+ ],
+ listViews: [
+ { id: "list", title: "View as List" },
+ { id: "icons", title: "View as Icons" },
+ { id: "clips", title: "View with Clips" },
+ { id: "timelines", title: "View with Timelines" },
+ { id: "maps", title: "View with Maps" },
+ { id: "calendars", title: "View with Calendars" },
+ { id: "clip", title: "View as Clips" },
+ { id: "map", title: "View on Map" },
+ { id: "calendar", title: "View on Calendar" },
+ ],
+ sortKeys: [
+ { id: "title", title: "Title", operator: "", align: "left", width: 180 },
+ { id: "director", title: "Director", operator: "", align: "left", width: 180 },
+ { id: "country", title: "Country", operator: "", align: "left", width: 120 },
+ { id: "year", title: "Year", operator: "-", align: "right", width: 60 },
+ { id: "language", title: "Language", operator: "", align: "left", width: 120 },
+ { id: "writer", title: "Writer", operator: "", align: "left", width: 180 },
+ { id: "producer", title: "Producer", operator: "", align: "left", width: 180 },
+ { id: "cinematographer", title: "Cinematographer", operator: "", align: "left", width: 180 },
+ { id: "editor", title: "Editor", operator: "", align: "left", width: 180 },
+ { id: "actors", title: "Number of Actors", operator: "-", align: "right", width: 60 },
+ { id: "genre", title: "Genre", operator: "", align: "left", width: 120 },
+ { id: "keywords", title: "Number of Keywords", operator: "-", align: "right", width: 60 },
+ { id: "summary", title: "Words in Summary", operator: "-", align: "right", width: 60 },
+ { id: "trivia", title: "Words in Trivia", operator: "-", align: "right", width: 60 },
+ { id: "releasedate", title: "Release Date", operator: "-", align: "left", width: 90 },
+ { id: "budget", title: "Budget", operator: "-", align: "right", width: 90 },
+ { id: "gross", title: "Gross", operator: "-", align: "right", width: 90 },
+ { id: "profit", title: "Profit", operator: "-", align: "right", width: 90 },
+ { id: "rating", title: "Rating", operator: "-", align: "right", width: 60 },
+ { id: "votes", title: "Votes", operator: "-", align: "right", width: 90 },
+ { id: "id", title: "ID", operator: "", align: "left", width: 90 }
+ { id: "aspectratio", title: "Aspect Ratio", operator: "-", align: "left", width: 90 },
+ { id: "duration", title: "Duration", operator: "-", align: "right", width: 90 },
+ { id: "color", title: "Color", operator: "", align: "left", width: 90 },
+ { id: "saturation", title: "Saturation", operator: "-", align: "right", width: 60 },
+ { id: "brightness", title: "Brightness", operator: "-", align: "right", width: 60 },
+ { id: "volume", title: "Volume", operator: "-", align: "right", width: 60 },
+ { id: "clips", title: "Clips", operator: "-", align: "right", width: 60 },
+ { id: "cuts", title: "Cuts", operator: "-", align: "right", width: 60 },
+ { id: "cutsperminute", title: "Cuts per Minute", operator: "-", align: "right", width: 60 },
+ { id: "words", title: "Words", operator: "-", align: "right", width: 60 },
+ { id: "wordsperminute", title: "Words per Minute", operator: "-", align: "right", width: 60 },
+ { id: "resolution", title: "Resolution", operator: "-", align: "left", width: 90 },
+ { id: "pixels", title: "Pixels", operator: "-", align: "right", width: 90 },
+ { id: "size", title: "Size", operator: "-", align: "right", width: 90 },
+ { id: "bitrate", title: "Bitrate", operator: "-", align: "right", width: 90 },
+ { id: "files", title: "Files", operator: "-", align: "right", width: 60 },
+ { id: "filename", title: "Filename", operator: "", align: "left", width: 180 },
+ { id: "published", title: "Date Published", operator: "-", align: "left", width: 90 },
+ { id: "modified", title: "Date Modified", operator: "-", align: "left", width: 90 }
+ ],
+ userSettings: {
+ group: "guest",
+ ui: {
+ columns: ["title", "director", "country", "year", "language", "runtime", "genre"],
+ find: { key: "all", value: "", operator: "" },
+ itemView: "info",
+ listView: "list",
+ showGroups: true,
+ showInfo: true,
+ showList: true,
+ showMovies: true,
+ sort: [
+ { key: "director", operator: "" }
+ ],
+ theme: "modern"
+ },
+ username: ""
+ }
+ },
+ user = config.userSettings,
+ $ui = {};
+
+// App
+
+ Ox.theme(user.ui.theme);
app = new Ox.App({
requestURL: "/api/"
});
- var size = window.location.hash.substr(1) || "medium",
- $body = $("body"),
- $toolbars = [];
- var sidePanel = new Ox.Panel();
- var mainPanel = new Ox.Panel()/*.css({
- //borderLeft: "1px solid rgb(160, 160, 160)"
- })*/;
- var middleSplitPanel = Ox.SplitPanel({
+// MainMenu
+
+ $ui.mainMenu = new Ox.MainMenu({
+ extras: [
+ $ui.loadingIcon = new Ox.LoadingIcon({
+ size: "medium"
+ })
+ ],
+ menus: [
+ { id: config.archiveId, title: config.archiveName, items: [
+ { id: "about", title: "About" },
+ {},
+ { id: "home", title: "Home Screen" },
+ { id: "faq", title: "Frequently Asked Questions" },
+ { id: "tos", title: "Terms of Service" },
+ {},
+ { id: "contact", title: "Contact" }
+ ] },
+ { id: "user", title: "User", items: [
+ { id: "username", title: "User: not logged in", disabled: true },
+ {},
+ { id: "preferences", title: "Preferences", disabled: true },
+ {},
+ { id: "login", title: "Login" }
+ ] },
+ { id: "edit", title: "Edit", items: [
+ { id: "undo", title: "Undo", disabled: true },
+ { id: "redo", title: "Redo", disabled: true },
+ {},
+ { id: "cut", title: "Cut", disabled: true },
+ { id: "copy", title: "Copy", disabled: true },
+ { id: "paste", title: "Paste", disabled: true },
+ { id: "delete", title: "Delete", disabled: true },
+ {},
+ { id: "selectall", title: "Select All", disabled: true },
+ { id: "selectnone", title: "Select None", disabled: true },
+ { id: "invertselection", title: "Invert Selection", disabled: true }
+ ] },
+ { id: "list", title: "List", items: [
+ { id: "history", title: "History", items: [
+ { id: "allmovies", title: "All Movies" }
+ ] },
+ { id: "lists", title: "View List", items: [
+ { id: "favorites", title: "Favorites" }
+ ] },
+ { id: "features", title: "View Feature", items: [
+ { id: "situationistfilm", title: "Situationist Film" },
+ { id: "timelines", title: "Timelines" }
+ ] },
+ {},
+ { id: "newlist", title: "New List..." },
+ { id: "newlistfromselection", title: "New List from Selection...", disabled: true},
+ { id: "newsmartlist", title: "New Smart List..." }
+ {},
+ { id: "addtolist", title: "Add Selected Movie to List...", disabled: true },
+ {},
+ { id: "setposterframe", title: "Set Poster Frame", disabled: true }
+ ]},
+ { id: "view", title: "View", items: [
+ { id: "movies", title: "View Movies", items: $.map(config.listViews, function(view, i) {
+ return $.extend(view, {
+ checked: user.ui.listView == view.id,
+ group: "viewmovies"
+ });
+ }) },
+ { id: "icons", title: "Icons", items: [
+ { id: "poster", title: "Poster" },
+ { id: "still", title: "Still" },
+ { id: "timeline", title: "Timeline" }
+ ] },
+ { id: "info", title: "Info", items: [
+ { id: "poster", title: "Poster" },
+ { id: "video", title: "Video" }
+ ] },
+ {},
+ { id: "movie", title: "Open Movie", items: $.map(config.listViews, function(view, i) {
+ return view;
+ }) },
+ {},
+ { id: "lists", title: "Hide Lists" },
+ { id: "info", title: "Hide Info" },
+ { id: "groups", title: "Hide Groups" },
+ { id: "movies", title: "Hide Movies", disabled: true }
+ ]},
+ { id: "sort", title: "Sort", items: [
+ { id: "sortmovies", title: "Sort Movies by", items: $.map(config.sortKeys, function(key, i) {
+ return $.extend(key, {
+ checked: user.ui.sort[0].key == key,
+ group: "sortmovies"
+ });
+ }) },
+ { id: "ordermovies", title: "Order Movies", items: [
+ { id: "ascending", title: "Ascending", group: "ordermovies", checked: user.ui.sort[0].operator == "" },
+ { id: "descending", title: "Descending", group: "ordermovies", checked: user.ui.sort[0].operator == "-" }
+ ]},
+ { id: "advancedsort", title: "Advanced Sort..." }
+ {},
+ { id: "groupsstuff", title: "Groups Stuff" }
+ ] },
+ { id: "find", title: "Find", items: [
+ { id: "find", title: "Find", items: $.map(config.findKeys, function(key, i) {
+ return $.extend(key, {
+ checked: user.ui.find.key == key,
+ group: "find"
+ })
+ }) },
+ { id: "advancedfind", "Advanced Find..." }
+ ] },
+ { id: "code", title: "Code", items: [
+ { id: "download", title: "Download" },
+ { id: "contribute", title: "Contribute" },
+ { id: "report", title: "Report a Bug" },
+ ] },
+ { id: "help", title: "Help", items: [
+ { id: "help", title: config.archiveName + " Help" }
+ ] },
+ { id: "debug", title: "Debug", items: [
+ { id: "query", title: "Show Query" }
+ ]}
+ ]
+ });
+
+// Toolbar
+
+ $ui.toolbar = new Ox.Bar({
+ size: 24
+ })
+ .append(
+ $ui.groupsButton = new Ox.Button({
+ id: "groupsButton",
+ value: ["Show Groups", "Hide Groups"]
+ })
+ .css({
+ float: "left",
+ margin: "4px"
+ })
+ .width(80)
+ )
+ .append(
+ $ui.viewSelect = new Ox.Select({
+ id: "viewSelect",
+ items: $.map(config.listViews, function(view, i) {
+ return $.extend(view, {
+ checked: user.ui.listView == view.id
+ });
+ })
+ })
+ .css({
+ float: "left",
+ margin: "4px"
+ })
+ .width(120)
+ )
+ .append(
+ $ui.findInput = new Ox.Input({
+ autocomplete: function(key, value, callback) {
+ Ox.print("autocomplete", key, value);
+ value === "" && Ox.print("Warning: autocomplete function should never be called with empty value");
+ if (key == "all") {
+ callback();
+ } else {
+ app.request("find", {
+ keys: [key],
+ query: {
+ conditions: [
+ {
+ key: key,
+ value: value,
+ operator: ""
+ }
+ ],
+ operator: ""
+ },
+ sort: [
+ {
+ key: key,
+ operator: ""
+ }
+ ],
+ range: [0, 10]
+ }, function(result) {
+ callback($.map(result.data.items, function(v) {
+ return v.title;
+ }));
+ });
+ }
+ },
+ clear: true,
+ highlight: true,
+ id: "findInput",
+ label: $.map(config.findKeys, function(key, i) {
+ return {
+ id: key.id,
+ title: "Find: " + key.title
+ }
+ }),
+ labelWidth: 85
+ })
+ css({
+ float: "right",
+ margin: "4px"
+ })
+ .width(300)
+ );
+
+
+// Groups
+
+ var rightPanelWidth = $document.width() - 256,
+ groups = $.map(config.groups, function(id, i) {
+ var title = Ox.getObjectById(sortKeys, id).title;
+ return {
+ id: id,
+ conditions: [],
+ element: new Ox.TextList({
+ columns: [
+ {
+ align: "left",
+ id: "name",
+ operator: id == "year" ? "-" : "+",
+ title: title,
+ unique: true,
+ visible: true,
+ width: size - 40 - ($.browser.mozilla ? 16 : 12)
+ },
+ {
+ align: "right",
+ id: "items",
+ operator: "-",
+ title: "#",
+ visible: true,
+ width: 40
+ }
+ ],
+ id: "group_" + id,
+ request: function(options) {
+ delete options.keys;
+ app.request("find", $.extend(options, {
+ group: id,
+ query: constructQuery()
+ }), options.callback);
+ },
+ sort: [
+ {
+ key: id == "year" ? "name" : "items",
+ operator: "-"
+ }
+ ]
+ }),
+ size: rightPanelWidth / 5 + (rightPanelWidth % 5 > i),
+ title: title
+ };
+ });
+
+// Interface
+
+ $ui.app = new Ox.SplitPanel({
elements: [
{
- element: sidePanel,
- size: 256
+ element: $ui.mainMenu,
+ size: 20
},
{
- element: mainPanel
+ element: $ui.mainPanel = new Ox.SplitPanel({
+ elements: [
+ {
+ element: $ui.leftPanel = new Ox.SplitPanel({
+ elements: [
+ {
+ element: $ui.sidebar = new Ox.Element()
+ },
+ {
+ element: $ui.info = new Ox.Element(),
+ size: 128
+ }
+ ]
+ }),
+ size: 256
+ },
+ {
+ element: $ui.rightPanel = new Ox.SplitPanel({
+ elements: [
+ {
+ element: $ui.toolbar,
+ size: 24
+ },
+ {
+ element: $ui.contentPanel = new Ox.SplitPanel({
+ elements: [
+ {
+ element: $ui.groupsOuterPanel = new Ox.SplitPanel({
+ elements: [
+ {
+ element: groups[0].element,
+ size: groups[0].size
+ },
+ {
+ element: $ui.groupsInnerPanel = new Ox.SplitPanel({
+ elements: [
+ {
+ element: groups[1].element,
+ size: groups[1].size
+ },
+ {
+ element: groups[2].element,
+ size: groups[2].size
+ },
+ {
+ element: groups[3].element,
+ size: groups[3].size
+ }
+ ]
+ })
+ },
+ {
+ element: groups[4].element,
+ size: groups[4].size
+ }
+ ]
+ }),
+ size: 128
+ },
+ {
+ element: $ui.list = constructList(user.ui.listView)
+ }
+ ]
+ })
+ }
+ {
+ element: $ui.statusbar = new Ox.Bar({ size: 16 }),
+ size: 16
+ }
+ ]
+ }),
+ }
+ ]
+ })
}
- ],
- orientation: "horizontal"
- })/*.css({
- borderTop: "1px solid rgb(160, 160, 160)",
- borderBottom: "1px solid rgb(160, 160, 160)"
- })*/;
+ ]
+ }).appendTo($body);
+
+// Events
+
+ Ox.Request.requests() && $loadingIcon.start();
+ Ox.Event.bind("requestStart", function() {
+ Ox.print("requestStart")
+ $loadingIcon.start();
+ });
+ Ox.Event.bind("requestStop", function() {
+ Ox.print("requestStop")
+ $loadingIcon.stop();
+ });
+
+ Ox.Event.bind("change_viewSelect", function(event, data) {
+ $list.replaceWith(constructList(data.id));
+ });
+
+ Ox.Event.bind("submit_find", function(event, data) {
+ findCondition = {
+ key: data.key == "all" ? "" : data.key,
+ value: data.value,
+ operator: ""
+ };
+ $.each(groups, function(i, group) {
+ groups[i].conditions = [];
+ $group[i].options({
+ request: function(options) {
+ delete options.keys;
+ return app.request("find", $.extend(options, {
+ group: group.id,
+ query: constructQuery(group.id)
+ }), options.callback);
+ }
+ });
+ });
+ $list.options({
+ request: function(options) {
+ return app.request("find", $.extend(options, {
+ query: constructQuery()
+ }), options.callback);
+ }
+ })
+ });
+
+ $.each(groups, function(i, group) {
+ Ox.Event.bind("select_group_" + group.id, function(event, data) {
+ $list.options({
+ request: function(options) {
+ groups[i].conditions = $.map(data.ids, function(v) {
+ return {
+ key: group.id,
+ value: v,
+ operator: "="
+ };
+ });
+ return app.request("find", $.extend(options, {
+ query: constructQuery()
+ }), options.callback);
+ }
+ });
+ $.each(groups, function(i_, group_) {
+ if (i_ != i) {
+ $group[i_].options({
+ request: function(options) {
+ delete options.keys;
+ return app.request("find", $.extend(options, {
+ group: group_.id,
+ query: constructQuery(group_.id)
+ }), options.callback);
+ }
+ });
+ }
+ });
+ });
+ });
+ Ox.Event.bind("change_sort_movies", function(event, data) {
+
+ });
+ Ox.Event.bind("load_list", function(event, data) {
+ $totals.html(constructStatus({
+ "total": data,
+ "selected": {}
+ }));
+ var html = [
+ Ox.formatNumber(data.items) + " movie" + (data.items != 1 ? "s" : ""),
+ Ox.formatDuration(data.runtime, "medium"),
+ data.files + " file" + (data.files != 1 ? "s" : ""),
+ Ox.formatDuration(data.duration, "short"),
+ Ox.formatValue(data.size, "B"),
+ Ox.formatValue(data.pixels, "px")
+ ];
+ $totals.html("Total: " + constructStatus(data) + " — Selected: " + constructStatus({
+ duration: 0,
+ files: 0,
+ items: 0,
+ pixels: 0,
+ runtime: 0,
+ size: 0
+ }));
+ });
+ Ox.Event.bind("sort_list", function(event, data) {
+
+ });
+ Ox.Event.bind("select_list", function(event, data) {
+
+ });
+ Ox.Event.bind("click_show_query", function(event, data) {
+ var query = constructQuery(),
+ html = "Conditions
" + $.map(query.conditions, function(v) {
+ return v.key + " " + v.operator + " " + v.value;
+ }).join("
") + "
Operator: " + query.operator,
+ $dialog = new Ox.Dialog({
+ title: "Show Query",
+ buttons: [
+ {
+ value: "Close",
+ click: function() {
+ $dialog.close();
+ }
+ }
+ ]
+ })
+ .append(html)
+ .open();
+ });
+
+// Functions
+
+ function constructList(view) {
+ var $list;
+ if (view == "text") {
+ $list = new Ox.TextList({
+ columns: $.map(config.sortKeys, function(key, i) {
+ return $.extend(key, {
+ visible: $.inArray(key.id, user.ui.columns) > -1,
+ unique: key.id == "id"
+ });
+ }),
+ id: "list",
+ request: function(options) {
+ app.request("find", $.extend(options, {
+ query: constructQuery()
+ }), options.callback);
+ },
+ sort: user.ui.sort
+ });
+ } else if (view == "icons") {
+ $list = new Ox.IconList({
+ id: "list",
+ item: function(data, sort, size) {
+ return {
+ height: data.posterHeight,
+ id: data["id"],
+ info: data[$.inArray(sort[0].key, ["title", "director"]) > -1 ? "year" : sort[0].key],
+ title: data.title + (data.director ? " (" + data.director + ")" : ""),
+ url: "http://0xdb.org/" + data.id + "/poster." + size + "." + "jpg",
+ width: data.posterWidth
+ };
+ },
+ keys: ["director", "id", "posterHeight", "posterWidth", "posterURL", "title"],
+ request: function(options) {
+ app.request("find", $.extend(options, {
+ query: constructQuery()
+ }), options.callback);
+ },
+ size: 128,
+ sort: [
+ {
+ key: "director",
+ operator: "+"
+ }
+ ],
+ unique: "id"
+ });
+ }
+ return $list;
+ }
+
+ function constructQuery(groupId) {
+ var conditions = $.merge(!Ox.isUndefined(user.ui.find.key) ? [user.ui.find] : [], $.map(groups, function(v, i) {
+ if (v.id != groupId) {
+ return v.conditions;
+ }
+ }));
+ return {
+ conditions: conditions,
+ operator: conditions.length ? "," : ""
+ };
+ }
+
+ function constructStatus(data) {
+ var html = [];
+ $.each(data, function(k, v) {
+ html.push(Ox.toTitleCase(k) + ": " + [
+ Ox.formatNumber(data.items) + " movie" + (data.items != 1 ? "s" : ""),
+ Ox.formatDuration(data.runtime, "medium"),
+ data.files + " file" + (data.files != 1 ? "s" : ""),
+ Ox.formatDuration(data.duration, "short"),
+ Ox.formatValue(data.size, "B"),
+ Ox.formatValue(data.pixels, "px")
+ ].join(", "));
+ })
+ return html.join(" — ");
+ }
+
+
+
+
//FIXME: how to properly overwrite functions without replacing them
var super_launch = app.launch;
@@ -43,12 +682,7 @@ $(function(){
super_launch();
};
- var loadingIcon = new Ox.LoadingIcon({
- size: "medium"
- })
- .css({
- marginLeft: "4px"
- });
+ return;
app.menu = new Ox.MainMenu({
extras: [