public/src/SAGE2_fileManager.js
// SAGE2 is available for use under the SAGE2 Software License
//
// University of Illinois at Chicago's Electronic Visualization Laboratory (EVL)
// and University of Hawai'i at Manoa's Laboratory for Advanced Visualization and
// Applications (LAVA)
//
// See full text, terms and conditions in the LICENSE.txt included file
//
// Copyright (c) 2015
/**
* SAGE2 File Manager
*
* @module client
* @submodule SAGE2_Files
* @class SAGE2_Files
*/
/* global SAGE2_init, SAGE2_resize, escape, unescape, sage2Version, showDialog */
/* global removeAllChildren, SAGE2_copyToClipboard, displayUI, dateToYYYYMMDDHHMMSS */
/* global showSAGE2Message */
/* global SAGE2_speech */
"use strict";
/**
* Convert a file size (number) to pretty string
*
* @method fileSizeIEC
* @param a {Number} file size to be converted
* @return {String} number with unit
*/
function fileSizeIEC(a, b, c, d, e) {
return (b = Math, c = b.log, d = 1024, e = c(a) / c(d) | 0,
a / b.pow(d, e)).toFixed(1) + ' ' + (e ? 'KMGTPEZY'[--e] : 'B');
}
var interactor;
/**
* FileManager object
*
* @method FileManager
* @param wsio {Object} websocket
* @param mydiv {Element} DOM element to place the file manager
*/
function FileManager(wsio, mydiv, uniqueID) {
this.allFiles = {};
this.allTable = null;
this.tree = null;
this.main = null;
this.uniqueID = uniqueID;
this.selectedItem = null;
this.dragPosition = null;
this.json_cfg = null;
this.http_port = null;
// Set the current sorting order
this.sorting = {by: "name", dir: "asc", as: "string"};
var _this = this;
// WEBIX
// ---------------------------------------------------
var data_with_icon = [
{id: "treeroot", value: "SAGE2", icon: "home", open: true, tooltip: "All the files",
data: [
{id: "Image:/", value: "Image", icon: "search", data: [], tooltip: "Show all the images"},
{id: "Video:/", value: "Video", icon: "search", data: [], tooltip: "Show all the videos"},
{id: "PDF:/", value: "PDF", icon: "search", data: [], tooltip: "Show all the PDF files"},
{id: "Note:/", value: "Note", icon: "search", data: [], tooltip: "Show all the notes"},
{id: "App:/", value: "Application", icon: "search", data: [], tooltip: "Show all the applications"},
{id: "Session:/", value: "Session", icon: "search", data: [], tooltip: "Show all the sessions"},
{id: "Link:/", value: "Link", icon: "search", data: [], tooltip: "Show all the links"},
{id: "Mine:/", value: "My files", icon: "search", data: [], tooltip: "Show all my uploaded files"}
]
}
];
// File menu of the media browser
var fileMediaActions = {
folder_menu: {value: "New folder", callback: function (evt) {
// Try to create a folder
createFolderUI();
}},
upload_menu: {value: "Upload an Image", callback: function (evt) {
// open the file uploader panel
showDialog('uploadDialog');
}},
session_menu2: {value: "Save the Session",
tooltip: "Saves the opened applications and their states in a session file",
callback: function (evt) {
// open the session popup
_this.saveSession();
}
},
separator: {value: "separator"},
refresh_menu: {value: "Refresh Media Browser", callback: function (evt) {
wsio.emit('requestStoredFiles');
}},
hidefm_menu: {value: "Close Media Browser", callback: function (evt) {
var mainUI = document.getElementById('mainUI');
document.getElementById('fileManager').style.display = "none";
if (mainUI.style.display === "none") {
mainUI.style.display = "block";
}
SAGE2_resize();
}}
};
// Edit menu of the media browser
var editMediaActions = {
open_menu: {value: "Open", callback: function (evt) {
// Get selected items
var dItems = _this.allTable.getSelectedId(true);
var tbo = [];
// otherwise take all selected items
for (var i = 0; i < dItems.length; i++) {
tbo.push(dItems[i].id);
}
// Open all the content one at a time
tbo.map(function(tid) {
_this.openItem(tid);
});
}},
copyurl_menu: {value: "Copy URL", callback: function (evt) {
// Get selected items
var dItems = _this.allTable.getSelectedId(true);
copyURLItem(dItems[0].id);
}},
taburl_menu: {value: "Open in Tab", callback: function (evt) {
// Get selected items
var dItems = _this.allTable.getSelectedId(true);
openURLItem(dItems[0].id);
}},
download_menu: {value: "Download", callback: function (evt) {
// Get selected items
var dItems = _this.allTable.getSelectedId(true);
// Go over the list of selected items
for (var i = 0; i < dItems.length; i++) {
// Trigger the download command
downloadItem(dItems[i].id);
}
}},
separator: {value: "separator"},
delete_menu: {value: "Delete", callback: function (evt) {
// Delete one or several selected files
deleteFilesUI();
}}
};
// File manager menu bar
var menuMediaBrowser_data = [
// File entry
{id: "file_menu", value: "File", config: {width: 170}, submenu: buildSubmenu(fileMediaActions)},
// Edit entry
{id: "edit_menu", value: "Edit", submenu: buildSubmenu(editMediaActions)}
];
var menuMediaBrowser = {
view: "menu",
id: "menuMediaBrowser",
openAction: "click",
data: menuMediaBrowser_data
};
var searchToolbar = {
id: "searchToolbar",
view: "toolbar", paddingY: 0, borderless: true, elements: [
{ id: "search_text", view: "text", width: 250, placeholder: "Search" }
]
};
/////////////////////////////////////////////////////////////////////////////
// Build all the sub menus
// File menu
var fileActions = {
upload_menu: {value: "Upload an Image",
tooltip: "Uploads an image to the SAGE2 server and opens it",
callback: function (evt) {
// open the file uploader panel
showDialog('uploadDialog');
}
},
session_menu: {value: "Save the Session",
tooltip: "Saves the opened applications and their states in a session file",
callback: function (evt) {
// open the session popup
_this.saveSession();
}
},
separator: {value: "separator"},
showfm_menu: {value: "Open Media Browser",
tooltip: "Shows the file media browser below the user interface",
callback: function (evt) {
document.getElementById('fileManager').style.display = "block";
SAGE2_resize();
}
},
hidefm_menu: {value: "Close Media Browser",
tooltip: "Hides the file media broswer",
callback: function (evt) {
var mainUI = document.getElementById('mainUI');
document.getElementById('fileManager').style.display = "none";
if (mainUI.style.display === "none") {
mainUI.style.display = "block";
}
SAGE2_resize();
}
}
};
// Partitions menu
var partitionsActions = {
p1x1_menu: {value: "Fullscreen", callback: function (evt) {
// create one full partition
wsio.emit('partitionScreen', {
type: "row", ptn: true, size: 12
});
}},
p2x1_menu: {value: "2 Columns", callback: function (evt) {
// create partition division of screen
wsio.emit('partitionScreen',
{
type: "row", size: 12,
children: [
{type: "col", ptn: true, size: 6},
{type: "col", ptn: true, size: 6}
]
});
}},
p3x1_menu: {value: "3 Columns", callback: function (evt) {
// create partition division of screen
wsio.emit('partitionScreen',
{
type: "row", size: 12,
children: [
{type: "col", ptn: true, size: 4},
{type: "col", ptn: true, size: 4},
{type: "col", ptn: true, size: 4}
]
});
}},
p2x2_menu: {value: "2 Columns, 2 Rows", callback: function (evt) {
// create partition division of screen
wsio.emit('partitionScreen',
{
type: "col", size: 12,
children: [
{
type: "row", size: 6,
children: [
{type: "col", ptn: true, size: 6},
{type: "col", ptn: true, size: 6}
]
},
{
type: "row", size: 6,
children: [
{type: "col", ptn: true, size: 6},
{type: "col", ptn: true, size: 6}
]
}
]
});
}},
p2s_1b_2s_menu: {value: "Center Pane, 4 Mini", callback: function (evt) {
// create partition division of screen
wsio.emit('partitionScreen',
{
type: "row", size: 12,
children: [
{
type: "col", size: 3,
children: [
{type: "row", ptn: true, size: 8},
{type: "row", ptn: true, size: 4}
]
},
{type: "col", ptn: true, size: 6},
{
type: "col", size: 3,
children: [
{type: "row", ptn: true, size: 4},
{type: "row", ptn: true, size: 8}
]
}
]
});
}},
p2b_1w_menu: {value: "2 Pane, Taskbar", callback: function (evt) {
// create partition division of screen
wsio.emit('partitionScreen',
{
type: "col", size: 12,
children: [
{
type: "row", size: 8,
children: [
{type: "col", ptn: true, size: 6},
{type: "col", ptn: true, size: 6}
]
},
{
type: "row", size: 4,
children: [
{type: "col", ptn: true, size: 12}
]
}
]
});
}},
separator: {value: "separator"},
partitiongrab_menu: {
value: "Fit Content",
callback: function (evt) {
wsio.emit('partitionsGrabAllContent');
}}
};
// View menu
var viewActions = {
settings_menu: {value: "Settings",
tooltip: "Opens the pointer and screen sharing settings panel",
callback: function (evt) {
interactor.settingsDialog('main');
}
},
separator1: {value: "separator"},
tile_menu: {value: "Tile Content",
tooltip: "Applies an automatic layout algorithm to tile the current windows",
callback: function (evt) {
// Tile applications on the wall
wsio.emit('tileApplications');
}
},
clear_menu: {value: "Clear Display",
tooltip: "Deletes all applications and partitions",
callback: function (evt) {
// Remove apps and partitions
wsio.emit('clearDisplay');
}
},
deleteapps_menu: {value: "Delete Applications",
tooltip: "Closes all the applications but leaves the partitions",
callback: function (evt) {
// Remove apps and keep the partitions
wsio.emit('deleteAllApplications');
}
},
deletepartition_menu: {value: "Delete Partitions",
tooltip: "Deletes only the partitions but not the applications",
callback: function (evt) {
wsio.emit('deleteAllPartitions');
}
},
partitions_menu: {value: "Create Partitions", submenu: buildSubmenu(partitionsActions)},
separator3: {value: "separator"},
wallScreenshot_menu: {value: "Take Screenshot",
tooltip: "Captures a screenshot of the wall and opens it up",
callback: function (evt) {
wsio.emit("startWallScreenshot");
}
}
};
// Services menu
var servicesActions = {
appstore_menu: {value: "SAGE2 Appstore",
tooltip: "Opens the appstore where you can download new applications\nthat can be added to your wall",
callback: function (evt) {
var storeUrl = "http://apps.sagecommons.org/";
window.open(storeUrl, '_blank');
}
},
imageservice_menu: {value: "Large Image Processing",
tooltip: "Opens a service that lets you process large images into pyramidal representation:\n" +
"download the DZI file and drop it onto your wall",
callback: function (evt) {
var imageUrl = "https://sage2rtt.evl.uic.edu:3043/upload";
window.open(imageUrl, '_blank');
}
},
videoservice_menu: {value: "Video Processing",
tooltip: "Opens a service that lets you convert video files to MP4 format",
callback: function (evt) {
var videoUrl = "https://sage2rtt.evl.uic.edu:3043/video/";
window.open(videoUrl, '_blank');
}
},
voiceserviceEnable_menu: {value: "Enable voice recognition",
tooltip: "Voice recognition will activate if left mouse button is held down for 1 second",
callback: SAGE2_speech.toggleVoiceRecognition
},
voiceserviceDisable_menu: {value: "Disable voice recognition",
tooltip: "Will not activate voice recognition when holding down left mouse button",
callback: SAGE2_speech.toggleVoiceRecognition
}
};
SAGE2_speech.uiMenuEntryEnable = servicesActions.voiceserviceEnable_menu;
SAGE2_speech.uiMenuEntryDisable = servicesActions.voiceserviceDisable_menu;
// Help
var helpActions = {
help_menu: {value: "SAGE2 Help",
tooltip: "Help on how to setup desktop sharing and\nlist supported media formats",
callback: function (evt) {
window.open("help/index.html", '_blank');
}
},
separator1: { value: "separator" },
shortcuts_menu: {value: "Interaction",
tooltip: "Mouse and keyboard operations and shortcuts",
callback: function (evt) {
window.open("help/interaction.html", '_blank');
// webix.modalbox({
// title: "Mouse and keyboard operations",
// buttons: ["Ok"],
// text: "<img src=/images/cheat-sheet.jpg width=100%>",
// width: "70%",
// height: "50%"
// });
}
},
voice_menu: {value: "Voice Commands",
tooltip: "Quick Reference for Voice Commands",
callback: function (evt) {
window.open("help/voice.html", '_blank');
}
},
separator2: { value: "separator" },
forum_menu: {value: "User Forum",
tooltip: "User forum on Google Groups",
callback: function (evt) {
window.open("https://groups.google.com/forum/#!forum/sage2", '_blank');
}
},
info_menu: {value: "Information",
tooltip: "Shows references and links about SAGE2",
callback: function (evt) {
window.open("help/info.html", '_blank');
}
},
about_menu: {value: "About",
tooltip: "SAGE2 server version and configuration",
callback: function (evt) {
var versionText = buildAboutHTML();
// Open the popup
webix.alert({
type: "alert-warning",
title: "SAGE2™",
width: "420px",
ok: "OK",
text: versionText
});
}
}
};
// Assemble the top menu bar
var topmenu_data = [
{id: "topfile_menu", value: "File",
config: {width: 170, zIndex: 9000},
submenu: buildSubmenu(fileActions)
},
{id: "view_menu", value: "View", config: {width: 170, zIndex: 9000},
submenu: buildSubmenu(viewActions)
},
{id: "services_menu", value: "Services", config: {width: 170, zIndex: 9000},
submenu: buildSubmenu(servicesActions)
},
{id: "mainhelp_menu", value: "Help", config: {zIndex: 9000},
submenu: buildSubmenu(helpActions)
}
];
// Build the Advanced menu
var advancedToolbarActions = {
display_menu: {value: "Display Client 0",
tooltip: "Opens a new page with the first display client",
callback: function (evt) {
var displayUrl = "http://" + window.location.hostname + _this.http_port + "/display.html?clientID=0";
window.open(displayUrl, '_blank');
}
},
overview_menu: {value: "Display Full Wall",
tooltip: "Opens a new page with the overview display client",
callback: function (evt) {
var overviewUrl = "http://" + window.location.hostname + _this.http_port + "/display.html?clientID=-1";
window.open(overviewUrl, '_blank');
}
},
separator1: { value: "separator" },
audio_menu: {value: "Audio Manager",
tooltip: "Opens a new page with the audio manager",
callback: function (evt) {
var audioUrl = "http://" + window.location.hostname + _this.http_port + "/audioManager.html";
window.open(audioUrl, '_blank');
}
},
console_menu: {value: "Server Console",
tooltip: "Opens a new page displaying the server debug messages",
callback: function (evt) {
window.open("admin/console.html", '_blank');
}
},
user_menu: {value: "User Console",
tooltip: "Opens a new page displaying users and roles",
callback: function (evt) {
window.open("admin/SAGE2_user.html", '_blank');
}
},
performance_menu: {value: "Performance Console",
tooltip: "Opens a new page displaying performance monitoring data",
callback: function (evt) {
window.open("admin/performance.html", '_blank');
}
},
separator2: { value: "separator" }
};
// Advanced setting, right-aligned in the top menubar
var advancedToolbar = {
view: "toolbar", paddingY: 0, css: {'text-align': 'right'}, elements: [
{view: "menu", id: "advancedToolbar", paddingY: 0, borderless: true,
tooltip: false,
submenuConfig: {
tooltip: {
// function building the tooltip text
template: showTooltip,
// tooltip position offset
dx: 50, dy: 5,
width: 100
},
// Delay the tooltip by 0.5s
mouseEventDelay: 500
},
data: [
{id: "mainadmin_menu", value: "Advanced", config: {zIndex: 9000},
submenu: buildSubmenu(advancedToolbarActions)
}
]
}
]
};
// On mobile, menu opens with a click, otherwise hovers
var clickOrNoClick = __SAGE2__.browser.isMobile ? "click" : null;
var topmenu = {
id: "topmenu",
view: "menu",
// click or not to open
openAction: clickOrNoClick,
data: topmenu_data,
tooltip: false,
submenuConfig: {
tooltip: {
// function building the tooltip text
template: showTooltip,
// tooltip position offset
dx: 50, dy: 5,
width: 100
},
// Delay the tooltip by 0.5s
mouseEventDelay: 500
}
};
// Top menubar above the UI
// Create the top menubar, with menu and avanced settings in the right-aligned toolbar
webix.ui({
container: document.getElementById('mainMenuBar'),
id: "toplayout",
// CSS styling for colors
css: "my_style",
// Remove the css borders for full width
borderless: true,
rows: [{
view: "toolbar",
cols: [topmenu, advancedToolbar]
}]
});
// Disable the screenshot menu. Will wbe enabled later froms server
$$('topmenu').disableItem('wallScreenshot_menu');
// Disable voice recognition. Will be enabled from SAGE2_Speech.js file
$$('topmenu').hideItem('voiceserviceEnable_menu');
$$('topmenu').hideItem('voiceserviceDisable_menu');
// Set the actions for the file menu
attachCallbacks($$("topmenu").getSubMenu('topfile_menu'), fileActions);
// Set the actions for the view menu
attachCallbacks($$('topmenu').getSubMenu('view_menu'), viewActions);
// Set the actions for the services menu
attachCallbacks($$("topmenu").getSubMenu('services_menu'), servicesActions);
// Set the actions for the help menu
attachCallbacks($$("topmenu").getSubMenu('mainhelp_menu'), helpActions);
// Set the actions for the advanced menu
attachCallbacks($$("advancedToolbar").getSubMenu('mainadmin_menu'), advancedToolbarActions);
// Set the actions for the partition menu
attachCallbacks($$('topmenu').getSubMenu('partitions_menu'), partitionsActions);
/////////////////////////////////////////////////////////////////////////////
this.main = webix.ui({
container: mydiv,
id: "layout",
css: { border: "solid 1px #565656;"},
rows: [
{
view: "toolbar",
cols: [menuMediaBrowser, searchToolbar]
},
{ cols: [
{
rows: [
{
id: "tree1",
view: "tree",
select: "select",
navigation: true,
drag: true,
minWidth: 120,
width: 180,
activeTitle: true, // close/open when selected
tooltip: showTooltip,
data: data_with_icon,
onContext: {} // required for context menu
},
{
view: "resizer"},
{
height: 160, rows: [
{type: "header", id: "drop_header", template: "Drop files below"},
{view: "list", id: "uploadlist", type: "uploader", scroll: 'y'}
]
}
]
},
{
view: "resizer"
},
{
id: "all_table",
view: "datatable",
gravity: 2, // two times bigger
columnWidth: 200,
resizeColumn: true,
scroll: 'y',
drag: true,
select: "multiselect",
navigation: true,
scheme: {
// Generate an automatic index
$init: function(obj) {
obj.index = this.count() + 1;
}
},
on: {
// update index after sort or update
"data->onStoreUpdated": function() {
this.data.each(function(obj, i) {
obj.index = i + 1;
});
return true;
}
},
columns: [
{id: "index", header: "", width: 40, minWidth: 25, sort: "int"},
{id: "name", header: "Name", minWidth: 180,
sort: "string", fillspace: true},
{id: "user", header: "User", width: 80, minWidth: 50,
sort: "string", css: {'text-align': 'right'}},
{id: "size", header: "Size", width: 80, minWidth: 50,
sort: sortBySize, css: {'text-align': 'right'}},
{id: "date", header: "Date", width: 150, minWidth: 80,
sort: sortByDate1, css: {'text-align': 'center'}},
{id: "ago", header: "Modified", width: 100, minWidth: 80,
sort: sortByDate2, css: {'text-align': 'right'}},
{id: "type", header: "Type", width: 80, minWidth: 50,
sort: "string", css: {'text-align': 'center'}}
],
data: [
]
},
{
view: "resizer"
},
{
minWidth: 100,
rows: [
{
view: "property",
id: "metadata",
editable: false,
scroll: true,
width: 260,
elements: [
]
},
{
view: "resizer"
},
{
width: 260,
height: 260,
minHeight: 100,
id: "thumb",
template: function(obj) {
if (obj.image) {
if (obj.session) {
// if it is from a session
return "<img src='" + obj.image + "' style='width:100%;'></img>";
}
return "<img src='" + obj.image + "_256.jpg' style='width:100%;'></img>";
}
return "";
}
}
]
}
]
}
]
});
this.tree = $$("tree1");
// Set the actions for the media browser menu
attachCallbacks($$("menuMediaBrowser").getSubMenu('file_menu'),
fileMediaActions);
attachCallbacks($$("menuMediaBrowser").getSubMenu('edit_menu'),
editMediaActions);
// Prevent HTML drop on rest of the page
webix.event(window, 'dragover', function(evt) {
evt.preventDefault();
});
webix.event(window, 'drop', function(evt) {
evt.preventDefault();
});
// Clear the upload list when clicking the header
webix.event($$("drop_header").$view, "click", function(e) {
$$("uploadlist").clearAll();
});
// filter the list of assets based on a search string
$$("search_text").attachEvent("onTimedKeyPress", function() {
var select = _this.tree.getSelectedId() || "treeroot";
updateSearch(select);
var filter = $$("search_text").getValue();
if (filter) {
let filter_regexp = new RegExp(filter, "i");
_this.allTable.filter(function(obj) {
// do a case-insensitive search on name, user and type
return (obj.name.search(filter_regexp) !== -1) ||
(obj.user.search(filter_regexp) !== -1) ||
(obj.type.search(filter_regexp) !== -1);
}, null, true);
}
});
// Get handle on the middle table data
this.allTable = $$("all_table");
// Remember the sorting direction
this.allTable.attachEvent("onAfterSort", function(sort_by, sort_dir, sort_as) {
_this.sorting.dir = sort_dir;
_this.sorting.as = sort_as;
});
// Remember the sorting column
this.allTable.attachEvent("onHeaderClick", function(id, e, trg) {
_this.sorting.by = id.column;
});
// Sort the table with default order
this.allTable.sort(this.sorting.by, this.sorting.dir);
this.allTable.markSorting(this.sorting.by, this.sorting.dir);
// User selection
this.allTable.attachEvent("onSelectChange", function(evt) {
var elt = _this.allTable.getSelectedId();
// remember the selected item (for drag-drop)
_this.selectedItem = elt;
if (!elt || !elt.id) {
// if nothing selected, done
return;
}
var metadata = $$("metadata");
// Rebuild the metadata panel
metadata.config.elements = [];
metadata.config.elements.push({label: "Metadata", type: "label"});
metadata.config.elements.push({label: "Width",
value: _this.allFiles[elt.id].exif.ImageWidth || '-'});
metadata.config.elements.push({label: "Height",
value: _this.allFiles[elt.id].exif.ImageHeight || '-'});
metadata.config.elements.push({label: "Author",
value: _this.allFiles[elt.id].exif.Creator || '-'});
metadata.config.elements.push({label: "File",
value: _this.allFiles[elt.id].exif.MIMEType || '-'});
// Add an EXIF panel for pictures
var info;
if (_this.allFiles[elt.id].exif.MIMEType.indexOf('image') >= 0) {
metadata.config.elements.push({label: "Image", type: "label"});
info = _this.allFiles[elt.id].exif.Make || '';
metadata.config.elements.push({label: "Make", value: info});
info = _this.allFiles[elt.id].exif.Model || '';
metadata.config.elements.push({label: "Camera", value: info});
info = _this.allFiles[elt.id].exif.LensID || _this.allFiles[elt.id].exif.LensInfo || '';
metadata.config.elements.push({label: "Lens", value: info});
info = _this.allFiles[elt.id].exif.ExposureTime || _this.allFiles[elt.id].exif.ShutterSpeedValue ||
_this.allFiles[elt.id].exif.ShutterSpeed || '';
metadata.config.elements.push({label: "Shutter speed", value: info});
info = _this.allFiles[elt.id].exif.FNumber || _this.allFiles[elt.id].exif.Aperture ||
_this.allFiles[elt.id].exif.ApertureValue || '';
metadata.config.elements.push({label: "Aperture", value: info});
info = _this.allFiles[elt.id].exif.ISO || '';
metadata.config.elements.push({label: "ISO", value: info});
info = _this.allFiles[elt.id].exif.ExposureProgram || '';
metadata.config.elements.push({label: "Program", value: info});
info = _this.allFiles[elt.id].exif.Flash || '';
metadata.config.elements.push({label: "Flash", value: info});
info = _this.allFiles[elt.id].exif.Megapixels || '';
metadata.config.elements.push({label: "Megapixels", value: info});
info = _this.allFiles[elt.id].exif.ColorSpace || '';
metadata.config.elements.push({label: "Color space", value: info});
info = _this.allFiles[elt.id].exif.WhiteBalance || '';
metadata.config.elements.push({label: "White balance", value: info});
} else if (_this.allFiles[elt.id].exif.MIMEType.indexOf('video') >= 0) {
metadata.config.elements.push({label: "Video", type: "label"});
info = _this.allFiles[elt.id].exif.Duration || '';
metadata.config.elements.push({label: "Duration", value: info});
info = _this.allFiles[elt.id].exif.ImageSize || '';
metadata.config.elements.push({label: "ImageSize", value: info});
info = _this.allFiles[elt.id].exif.VideoFrameRate || '';
metadata.config.elements.push({label: "Frame rate", value: info});
info = _this.allFiles[elt.id].exif.AvgBitrate || '';
metadata.config.elements.push({label: "AvgBitrate", value: info});
info = _this.allFiles[elt.id].exif.MajorBrand || '';
metadata.config.elements.push({label: "Type", value: info});
info = _this.allFiles[elt.id].exif.CompressorName || '';
metadata.config.elements.push({label: "Video codec", value: info});
info = _this.allFiles[elt.id].exif.AudioFormat || '';
metadata.config.elements.push({label: "Audio codec", value: info});
info = _this.allFiles[elt.id].exif.AudioChannels || '';
metadata.config.elements.push({label: "Audio channels", value: info});
info = _this.allFiles[elt.id].exif.AudioBitsPerSample || '';
metadata.config.elements.push({label: "Audio bps", value: info});
info = _this.allFiles[elt.id].exif.AudioSampleRate || '';
metadata.config.elements.push({label: "Audio rate", value: info});
info = _this.allFiles[elt.id].exif.Encoder || '';
metadata.config.elements.push({label: "Encoder", value: info});
} else if (_this.allFiles[elt.id].exif.MIMEType.indexOf('application/pdf') >= 0) {
// Clear the panel
metadata.config.elements = [];
// Create a PDF section
metadata.config.elements.push({label: "PDF", type: "label"});
info = _this.allFiles[elt.id].exif.Title || '';
metadata.config.elements.push({label: "Title", value: info});
info = _this.allFiles[elt.id].exif.PageCount || '';
metadata.config.elements.push({label: "Pages", value: info});
info = _this.allFiles[elt.id].exif.Description || '';
metadata.config.elements.push({label: "Description", value: info});
info = _this.allFiles[elt.id].exif.Creator || '';
metadata.config.elements.push({label: "Creator", value: info});
info = _this.allFiles[elt.id].exif.Keywords || '';
metadata.config.elements.push({label: "Keywords", value: info});
info = _this.allFiles[elt.id].exif.PDFVersion || '';
metadata.config.elements.push({label: "Version", value: info});
info = _this.allFiles[elt.id].exif.CreatorTool || '';
metadata.config.elements.push({label: "CreatorTool", value: info});
info = _this.allFiles[elt.id].exif.Producer || '';
metadata.config.elements.push({label: "Producer", value: info});
info = _this.allFiles[elt.id].exif.Linearized || '';
metadata.config.elements.push({label: "Linearized", value: info});
} else if (_this.allFiles[elt.id].exif.MIMEType.indexOf('text/plain') >= 0) {
var key;
if (_this.allFiles[elt.id].exif.FileName.split(".").pop() === "note") {
metadata.config.elements.push({label: "note (QuickNote)", type: "label"});
for (key in _this.allFiles[elt.id].exif) {
info = _this.allFiles[elt.id].exif[key] || '';
metadata.config.elements.push({label: key, value: info});
}
} else {
metadata.config.elements.push({label: "Note", type: "label"});
for (key in _this.allFiles[elt.id].exif) {
info = _this.allFiles[elt.id].exif[key] || '';
metadata.config.elements.push({label: key, value: info});
}
}
} else if (_this.allFiles[elt.id].exif.MIMEType.indexOf('application/custom') >= 0) {
// Clear the panel
metadata.config.elements = [];
// Add an application section
metadata.config.elements.push({label: "Application", type: "label"});
info = _this.allFiles[elt.id].exif.metadata.title || '';
metadata.config.elements.push({label: "Title", value: info});
info = _this.allFiles[elt.id].exif.metadata.version || '';
metadata.config.elements.push({label: "Version", value: info});
info = _this.allFiles[elt.id].exif.metadata.license || '';
metadata.config.elements.push({label: "License", value: info});
// Parse email
info = _this.allFiles[elt.id].exif.metadata.author || '';
info = info.split('<');
if (info.length === 2) {
var email = info[1];
email = email.split('>')[0];
metadata.config.elements.push({label: "Email", value: email});
}
// Parse keywords
info = _this.allFiles[elt.id].exif.metadata.keywords || '';
metadata.config.elements.push({
label: "Keywords",
value: info.map(function(k) {
return " " + k;
}).toString()
});
// Parse file types
info = _this.allFiles[elt.id].exif.metadata.fileTypes;
if (info.length === 0) {
info = "-";
}
metadata.config.elements.push({label: "File types", value: info});
// Parse description
info = _this.allFiles[elt.id].exif.metadata.description || '';
metadata.config.elements.push({
label: info, type: "label",
css: {height: "100px"}
});
} else if (_this.allFiles[elt.id].exif.MIMEType.indexOf('sage2/url') >= 0) {
// Clear the panel
metadata.config.elements = [];
metadata.config.elements.push({label: "URL", type: "label"});
metadata.config.elements.push({label: "Link",
value: _this.allFiles[elt.id].sage2URL || '-'});
metadata.config.elements.push({label: "Author",
value: _this.allFiles[elt.id].exif.SAGE2user || '-'});
} else if (_this.allFiles[elt.id].exif.MIMEType.indexOf('sage2/session') >= 0) {
// Clear the panel
metadata.config.elements = [];
metadata.config.elements.push({label: "Metadata", type: "label"});
metadata.config.elements.push({label: "Author",
value: _this.allFiles[elt.id].exif.Creator || '-'});
metadata.config.elements.push({label: "File",
value: _this.allFiles[elt.id].exif.MIMEType || '-'});
}
// Done updating metadata
metadata.refresh();
// Update the thumbnail
var thumb = $$("thumb");
// what type of app is it
var sessionType = _this.allFiles[elt.id].exif.MIMEType === "sage2/session" ||
_this.allFiles[elt.id].exif.MIMEType === "sage2/url";
// default thumbnail
var thumbURL = _this.allFiles[elt.id].exif.SAGE2thumbnail;
// if it's a URL, try to get the favico of the site
if (_this.allFiles[elt.id].exif.MIMEType === "sage2/url") {
thumbURL = "https://icons.better-idea.org/icon?size=48..128..256&url=" +
_this.allFiles[elt.id].sage2URL;
}
thumb.data = {image: thumbURL, session: sessionType};
thumb.refresh();
});
this.allTable.attachEvent("onItemDblClick", function(id, e, node) {
// Open the selected content on the wall
_this.openItem(id.row);
});
// onItemClick onAfterSelect onBeforeSelect
this.tree.attachEvent("onSelectChange", function(evt) {
// Clear the search box
$$("search_text").setValue("");
// Get the selection
var treeSelection = _this.tree.getSelectedItem();
// If a media folder is selection
if (treeSelection) {
if (treeSelection.sage2URL) {
_this.allTable.filter(function(obj) {
// trying to match the base URL
return _this.allFiles[obj.id].sage2URL.lastIndexOf(treeSelection.sage2URL, 0) === 0;
});
return;
}
}
// Otherwise, regular search
updateSearch(evt[0]);
});
// this.tree.attachEvent("onItemClick", function(evt) {
// });
// The drag-and-drop context can have the next properties:
// from - the source object
// to - the target object
// source - the id of the dragged item(s)
// target - the id of the drop target, null for drop on empty space
// start - the id from which DND was started
this.allTable.attachEvent("onBeforeDrag", function(context, ev) {
// Only drag-drop if multiple selected items,
// or the source element is the same as the selected one (select and drag)
if (context.source.length > 1 ||
(_this.selectedItem && context.start === _this.selectedItem.id)) {
var elt;
context.html = "<div style='padding:8px;background:#d3e3ef'>";
if (context.source.length === 1) {
elt = _this.allFiles[context.start];
context.html += '<img width=96 src="' + elt.exif.SAGE2thumbnail + '_256.jpg" />';
context.html += '<br>' + elt.exif.FileName;
} else {
for (var i = 0; i < Math.min(context.source.length, 35); i++) {
elt = _this.allFiles[context.source[i]];
context.html += elt.exif.FileName + "<br>";
}
}
context.html += "</div>";
return true;
}
return false;
});
// Track the position of the dragged item
this.allTable.$dragPos = function(pos, event, node) {
// dragPosition used in drop function
_this.dragPosition = pos;
};
this.allTable.attachEvent("onBeforeDrop", function(context, ev) {
// No DnD
return false;
});
// Before the drop, test if it is a valid operation
this.tree.attachEvent("onBeforeDrop", function(context, ev) {
if (context.target.startsWith("Image:") ||
context.target.startsWith("PDF:") ||
context.target.startsWith("Note:") ||
context.target.startsWith("Video:") ||
context.target.startsWith("App:") ||
context.target.startsWith("Session:") ||
context.target.startsWith("Link:") ||
context.target.startsWith("Mine:")) {
// No DnD on search icons
return false;
}
// Move each file selected one by one
context.source.map(function(elt) {
wsio.emit('moveElementFromStoredFiles', {filename: elt, url: context.target});
});
// Dont do a real DnD, stop there
return false;
});
// Now, do the transfer
this.tree.attachEvent("onAfterDrop", function(context, native_event) {
// done in before drop for now
});
webix.event(this.allTable.$view, "drag", function(e) {
e.preventDefault();
});
webix.ui({
id: "uploadAPI",
view: "uploader",
upload: "/upload", // POST url
formData: {
open: false // do not open after upload
},
on: {
onFileUpload: function(item) {
console.log('uploaded file', item.name);
},
onUploadComplete: function(item) {
console.log('upload complete');
var d = $$("uploadlist");
d.data.each(function(obj) {
// if all good, remove from list
if (obj.status === 'server') {
var it = d.getItemNode(obj.id);
it.style.color = "green";
}
});
},
onFileUploadError: function(item) {
console.log('onFileUploadError', item);
}
},
link: "uploadlist",
apiOnly: true
});
$$("uploadAPI").addDropZone($$("uploadlist").$view);
this.tree.closeAll();
this.tree.open("treeroot");
webix.ui({
view: "contextmenu",
id: "cmenu",
data: ["Open", "Copy URL", "Open in Tab", "Download", { $template: "Separator" }, "Delete"],
on: {
onItemClick: function(id) {
var i;
var context = this.getContext();
var list = context.obj;
var listId = context.id;
var dItems = _this.allTable.getSelectedId(true);
if (id === "Download") {
// Go over the list of selected items
for (i = 0; i < dItems.length; i++) {
// Trigger the download command
downloadItem(dItems[i].id);
}
} else if (id === "Copy URL") {
copyURLItem(list.getItem(listId).id);
} else if (id === "Open in Tab") {
openURLItem(list.getItem(listId).id);
} else if (id === "Open") {
var tbo = [];
if (dItems.length === 0) {
// If no selection, use the item under the context menu
tbo.push(list.getItem(listId).id);
} else {
// otherwise take all selected items
for (i = 0; i < dItems.length; i++) {
tbo.push(dItems[i].id);
}
}
// Open all the content one at a time
tbo.map(function(tid) {
_this.openItem(tid);
});
} else if (id === "Delete") {
var tbd = [];
var textTbd = "<ol style=\"list-style-position: inside;padding:10px;text-align:left;\">";
var numItems = 0;
if (dItems.length === 0) {
// If no selection, use the item under the context menu
tbd.push(list.getItem(listId).id);
textTbd += list.getItem(listId).id;
numItems = 1;
} else {
// otherwise take all selected items
for (i = 0; i < dItems.length; i++) {
tbd.push(dItems[i].id);
// Only list first 15 items...
if (i < 14) {
textTbd += '<li>' + dItems[i].id + '</li>';
} else if (i === 14) {
textTbd += '<li>...</li>';
}
numItems++;
}
}
textTbd += "</ol>";
webix.confirm({
title: "Confirm deletion - " + numItems + " item(s)",
width: "75%",
ok: "Yes",
cancel: "No",
text: textTbd,
callback: function(yesno) {
if (yesno) {
// for all elements
tbd.map(function(tid) {
var apptype = _this.allFiles[tid].exif.MIMEType;
// Send delete message to server
wsio.emit('deleteElementFromStoredFiles', {
filename: tid,
application: apptype
});
// Element will be deleted from table by return message from server
// _this.allTable.remove(tid);
});
}
}
});
}
}
}
});
$$("cmenu").attachTo($$("all_table"));
this.main.config.height = Math.round(window.innerHeight * 0.80);
this.main.show();
this.main.adjust();
///////////////////////////////////////////////////////////////////////////////////
/**
* Setup the callbacks for a menu, using a closure (tricky one)
*
* @method attachCallbacks
* @param element {Object} webix menu object to attach the callbacks to
* @param actions {Object} object containing the callback for each id
*/
function attachCallbacks(element, actions) {
if (element) {
element.attachEvent("onItemClick", (function (act) {
// Create a closure to keep a local copy of the array 'actions'
return function(evt, e, node) {
if (evt in act) {
if (act[evt].callback) {
act[evt].callback();
}
}
};
}(actions)));
// pass the local variable to the closure
}
}
/**
* Build a submenu for a description object. Each entry with id and value fields.
*
* @method buildSubmenu
* @param actions {Object} object containing the callback for each id
* @return {Array} array of entries with id and value field
*/
function buildSubmenu(actions) {
var entries = [];
for (var a in actions) {
// test for a special value to build a separator
if (actions[a].value === "separator") {
entries.push({$template: "Separator"});
} else if (actions[a].submenu) {
entries.push({id: a,
value: actions[a].value,
config: {autowidth: true, zIndex: 9000},
submenu: actions[a].submenu,
tooltip: actions[a].tooltip
});
} else {
// otherwise just add the object
entries.push({id: a,
value: actions[a].value,
tooltip: actions[a].tooltip
});
}
}
return entries;
}
/**
* Return the tooltip field of an object or empty string
*
* @method showTooltip
* @param element {Object} object with tooltip value or not
* @return {String} tooltip string
*/
function showTooltip(obj) {
return obj.tooltip ? obj.tooltip : "";
}
/**
* Build some HTML to show info about the SAGE2 server
*
* @method buildAboutHTML
* @return {String} HTML popup showing version and info
*/
function buildAboutHTML() {
var versionText = "<p>";
// Add new information
versionText += "<p class='textDialog'><span style='font-weight:bold;'>Host</span>: " + displayUI.config.host + "</p>";
// Show the type of web browser
versionText += "<p class='textDialog'><span style='font-weight:bold;'>Browser</span>: " +
__SAGE2__.browser.browserType + " " + __SAGE2__.browser.version + "</p>";
versionText += "</p>";
// Configuration
versionText += "<p class='textDialog'><span style='font-weight:bold;'>Resolution</span>: " +
displayUI.config.totalWidth + " x " + displayUI.config.totalHeight + " pixels";
versionText += " (" + displayUI.config.layout.columns + " by " + displayUI.config.layout.rows + " tiles";
versionText += " - " + displayUI.config.resolution.width + " x " + displayUI.config.resolution.height + ")" + "</p>";
// Add version
versionText += "<p class='textDialog'><span style='font-weight:bold;'>SAGE2 Version: </span>";
if (sage2Version.branch && sage2Version.commit && sage2Version.date) {
versionText += "<b>v" + sage2Version.base + "-" + sage2Version.branch + "-" +
sage2Version.commit + "</b> " + sage2Version.date;
} else {
versionText += "<b>v" + sage2Version.base + "</b>";
}
return versionText;
}
/**
* Try to delete one or several selected files
*
* @method deleteFilesUI
*/
function deleteFilesUI() {
// Get selected items
var dItems = _this.allTable.getSelectedId(true);
var tbd = [];
var textTbd = "<ol style=\"list-style-position: inside;padding:10px;text-align:left;\">";
var numItems = 0;
if (dItems.length > 0) {
for (var i = 0; i < dItems.length; i++) {
tbd.push(dItems[i].id);
// Only list first 15 items...
if (i < 14) {
textTbd += '<li>' + dItems[i].id + '</li>';
} else if (i === 14) {
textTbd += '<li>...</li>';
}
numItems++;
}
textTbd += "</ol>";
webix.confirm({
title: "Confirm deletion - " + numItems + " item(s)",
width: "75%",
ok: "Yes",
cancel: "No",
text: textTbd,
callback: function(yesno) {
if (yesno) {
// for all elements
tbd.map(function(tid) {
var apptype = _this.allFiles[tid].exif.MIMEType;
// Send delete message to server
wsio.emit('deleteElementFromStoredFiles', {
filename: tid,
application: apptype
});
});
}
}
});
}
}
/**
* Try to create a folder inside the currently selected folder
*
* @method createFolderUI
*/
function createFolderUI() {
var item = _this.tree.getSelectedItem();
if (item && item.sage2URL) {
webix.ui({
view: "window",
id: "folder_form",
position: "center",
modal: true,
head: "New folder in " + item.sage2URL,
body: {
view: "form",
width: 400,
borderless: false,
elements: [
{view: "text", id: "folder_name", label: "Folder name", name: "folder"},
{margin: 5, cols: [
{view: "button", value: "Cancel", click: function() {
this.getTopParentView().hide();
}},
{view: "button", value: "Create", type: "form", click: function() {
createFolder(item, this.getFormView().getValues());
this.getTopParentView().hide();
}}
]}
],
elementsConfig: {
labelPosition: "top"
}
}
}).show();
// Attach handlers for keyboard
$$("folder_name").attachEvent("onKeyPress", function(code, e) {
// ESC closes
if (code === 27 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
this.getTopParentView().hide();
return false;
}
// ENTER activates
if (code === 13 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
createFolder(item, this.getFormView().getValues());
this.getTopParentView().hide();
return false;
}
});
$$('folder_name').focus();
} else {
webix.alert({
type: "alert-warning",
title: "SAGE2",
ok: "OK",
text: "Select a parent folder first"
});
}
}
this.openItem = function(tid, position) {
var appType = this.getApplicationFromId(tid);
// Opening an app
if (appType === "application/custom") {
wsio.emit('loadApplication', {
application: tid,
user: _this.uniqueID,
position: position
});
} else if (appType === "sage2/session") {
wsio.emit('loadFileFromServer', {
application: 'load_session',
filename: tid,
user: _this.uniqueID,
position: position
});
} else if (appType === "sage2/url") {
wsio.emit('openNewWebpage', {
url: tid,
user: _this.uniqueID,
position: position
});
} else {
// Opening a file
wsio.emit('loadFileFromServer', {
application: appType,
filename: tid,
user: _this.uniqueID,
position: position
});
}
};
this.getApplicationFromId = function(id) {
// default answer
var response = "application/custom";
// Lookup the asset
var elt = this.allFiles[id];
// if found
if (elt) {
if (elt.exif.MIMEType.indexOf('image') >= 0) {
response = "image_viewer";
} else if (elt.exif.MIMEType.indexOf('pdf') >= 0) {
response = "pdf_viewer";
} else if (elt.exif.MIMEType.indexOf('video') >= 0) {
response = "movie_player";
} else if (elt.exif.MIMEType.indexOf('sage2/session') >= 0) {
response = "load_session";
} else if (elt.exif.MIMEType.indexOf('sage2/url') >= 0) {
response = "sage2/url";
}
}
// send the result
return response;
};
/**
* Trigger a browser downlaod
*
* @method downloadItem
* @param {<type>} elt The element
* @return {Boolean} (description_of_the_return_value)
*/
function downloadItem(elt) {
var mimetype = _this.allFiles[elt].exif.MIMEType;
if (mimetype !== "sage2/url" &&
mimetype !== "application/custom") {
var url = _this.allFiles[elt].sage2URL;
if (url) {
// Download the file
var link = document.createElement('a');
link.href = url;
if (link.download !== undefined) {
// Set HTML5 download attribute. This will prevent file from opening if supported.
var fileName = url.substring(url.lastIndexOf('/') + 1, url.length);
link.download = fileName;
}
// Dispatching click event
if (document.createEvent) {
var me = document.createEvent('MouseEvents');
me.initEvent('click', true, true);
link.dispatchEvent(me);
return true;
}
}
} else {
showSAGE2Message("File cannot be downloaded");
}
}
/**
* Copy the URL of the item into the user's clipboard
*
* @method copyURLItem
* @param {<type>} elt The element
*/
function copyURLItem(elt) {
var sage2url = _this.allFiles[elt].sage2URL;
if (sage2url) {
var url;
if (_this.allFiles[elt].exif.MIMEType === 'sage2/url') {
url = sage2url;
} else {
url = window.location.origin + sage2url;
}
// Copy to clipboard (defined in SAGE2_runtime)
SAGE2_copyToClipboard(url);
}
}
/**
* Opens the content in a browser tab
*
* @method openURLItem
* @param {<type>} elt The element
*/
function openURLItem(elt) {
var sage2url = _this.allFiles[elt].sage2URL;
if (sage2url) {
var url;
if (_this.allFiles[elt].exif.MIMEType === 'sage2/url') {
url = sage2url;
} else {
url = window.location.origin + sage2url;
}
// open in a browser tab
window.open(url, '_blank');
}
}
function updateSearch(searchParam) {
if (searchParam === "Image:/") {
_this.allTable.filter(function(obj) {
return _this.allFiles[obj.id].exif.MIMEType.indexOf('image') >= 0;
});
} else if (searchParam === "PDF:/") {
_this.allTable.filter(function(obj) {
return _this.allFiles[obj.id].exif.MIMEType.indexOf('pdf') >= 0;
});
} else if (searchParam === "Note:/") {
_this.allTable.filter(function(obj) {
return (_this.allFiles[obj.id].sage2Type &&
(_this.allFiles[obj.id].sage2Type.indexOf('application/note') >= 0 ||
_this.allFiles[obj.id].sage2Type.indexOf('application/doodle') >= 0)
);
});
} else if (searchParam === "Video:/") {
_this.allTable.filter(function(obj) {
return _this.allFiles[obj.id].exif.MIMEType.indexOf('video') >= 0;
});
} else if (searchParam === "App:/") {
_this.allTable.filter(function(obj) {
return _this.allFiles[obj.id].exif.MIMEType.indexOf('application/custom') >= 0;
});
} else if (searchParam === "Session:/") {
_this.allTable.filter(function(obj) {
return _this.allFiles[obj.id].exif.MIMEType.indexOf('sage2/session') >= 0;
});
} else if (searchParam === "Link:/") {
_this.allTable.filter(function(obj) {
return _this.allFiles[obj.id].exif.MIMEType.indexOf('sage2/url') >= 0;
});
} else if (searchParam === "Mine:/") {
_this.allTable.filter(function(obj) {
var val = false;
if (_this.allFiles[obj.id].exif.SAGE2user) {
val = _this.allFiles[obj.id].exif.SAGE2user.indexOf(interactor.pointerColor) >= 0;
}
return val;
});
} else if (searchParam === "treeroot") {
// List everything
// _this.allTable.filter();
// List all but the applications
_this.allTable.filter(function(obj) {
return _this.allFiles[obj.id].exif.MIMEType.indexOf('application/custom') < 0;
});
} else {
// dunno
}
}
this.createSubFolderForFile = function(myFile) {
var df, folder;
// Look into the media folders for needed sub-folders
for (df in this.mediaFolders) {
folder = this.mediaFolders[df];
if (myFile.sage2URL.startsWith(folder.url)) {
// Create a subfolder if needed
// var filepath = myFile.sage2URL.split('/');
// var filepath = decodeURIComponent(myFile.sage2URL).split('/');
var filepath = myFile.sage2URL.split('/');
// Remove the fist two elements (root) and the last (filename)
var subdirArray = filepath.slice(2, -1);
var parent = folder.url;
subdirArray.forEach(function(sub) {
// Build the tree item
var newid = parent + '/' + sub;
// if it doesnt already exist
if (!_this.tree.getItem(newid)) {
var newElement = {
// id: newid, value: sub,
id: newid, value: decodeURIComponent(sub),
icon: "folder", open: true, sage2URL: newid,
data: [], onContext: {}
};
// Add to the tree
_this.tree.parse({ parent: parent, data: newElement});
}
parent = newid;
});
}
}
};
this.saveSession = function() {
// generate a default name
var template = "session_" + dateToYYYYMMDDHHMMSS(new Date());
// Build a webix dialog
webix.ui({
view: "window",
id: "session_popup",
position: "center",
modal: true,
zIndex: 9999,
head: "Save the current session",
width: 400,
body: {
view: "form",
borderless: false,
elements: [
{view: "text", value: template, id: "session_filename",
label: "Please enter a session name:", name: "session"},
{margin: 5, cols: [
{view: "button", value: "Cancel", click: function() {
this.getTopParentView().hide();
}},
{view: "button", value: "Save", type: "form", click: function() {
var values = this.getFormView().getValues();
wsio.emit('saveSession', values.session);
this.getTopParentView().hide();
}}
]}
],
elementsConfig: {
labelPosition: "top"
}
}
}).show();
// Attach handlers for keyboard
$$("session_filename").attachEvent("onKeyPress", function(code, e) {
// ESC closes
if (code === 27 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
this.getTopParentView().hide();
return false;
}
// ENTER activates
if (code === 13 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
var values = this.getFormView().getValues();
wsio.emit('saveSession', values.session);
this.getTopParentView().hide();
return false;
}
});
// Set focus on the text box
$$('session_filename').focus();
// select the text in the box (easier to type another name)
$$('session_filename').getInputNode().select();
};
// Server sends the media files list
this.updateFiles = function(data) {
var i, f;
// Clean the main data structures
this.allFiles = {};
this.allTable.clearAll();
// Add all the files in
for (i = 0; i < data.images.length; i++) {
f = data.images[i];
this.allFiles[f.id] = f;
this.createSubFolderForFile(f);
}
for (i = 0; i < data.videos.length; i++) {
f = data.videos[i];
this.allFiles[f.id] = f;
this.createSubFolderForFile(f);
}
for (i = 0; i < data.pdfs.length; i++) {
f = data.pdfs[i];
this.allFiles[f.id] = f;
this.createSubFolderForFile(f);
}
for (i = 0; i < data.applications.length; i++) {
f = data.applications[i];
this.allFiles[f.id] = f;
this.createSubFolderForFile(f);
}
for (i = 0; i < data.others.length; i++) {
f = data.others[i];
this.allFiles[f.id] = f;
this.createSubFolderForFile(f);
}
for (i = 0; i < data.sessions.length; i++) {
f = data.sessions[i];
this.allFiles[f.id] = f;
}
for (i = 0; i < data.links.length; i++) {
f = data.links[i];
this.allFiles[f.id] = f;
}
i = 0;
var mm, createDate;
for (var a in this.allFiles) {
f = this.allFiles[a];
// if it's an app
if (f.exif.MIMEType.indexOf('application/custom') >= 0) {
mm = moment();
f.exif.FileModifyDate = mm;
f.exif.FileSize = 0;
f.exif.Creator = f.exif.metadata.author;
this.allTable.data.add({id: f.id,
name: f.exif.FileName,
user: f.exif.SAGE2user ? f.exif.SAGE2user : "-",
date: mm.format("YYYY/MM/DD HH:mm:ss"),
ago: mm.fromNow(),
type: "APP",
size: fileSizeIEC(f.exif.FileSize)
});
} else if (f.exif.MIMEType.indexOf('sage2/session') >= 0) {
// It's a SAGE2 session
mm = moment(f.exif.FileDate, 'YYYY/MM/DD HH:mm:ssZ');
f.exif.FileModifyDate = mm;
this.allTable.data.add({id: f.id,
name: f.exif.FileName,
user: f.exif.SAGE2user ? f.exif.SAGE2user : "-",
date: mm.format("YYYY/MM/DD HH:mm:ss"),
ago: mm.fromNow(),
type: "SESSION",
size: fileSizeIEC(f.exif.FileSize)
});
} else if (f.exif.MIMEType.indexOf('sage2/url') >= 0) {
// It's a URL
mm = moment(f.exif.FileDate, 'YYYY/MM/DD HH:mm:ssZ');
f.exif.FileModifyDate = mm;
this.allTable.data.add({id: f.id,
name: f.exif.FileName,
user: f.exif.SAGE2user ? f.exif.SAGE2user : "-",
date: mm.format("YYYY/MM/DD HH:mm:ss"),
ago: mm.fromNow(),
type: "LINK",
size: fileSizeIEC(f.exif.FileSize)
});
} else {
// Any other asset type
// Try to find creation
createDate = f.exif.CreateDate ||
f.exif.DateTimeOriginal ||
f.exif.ModifyDate ||
f.exif.FileModifyDate;
mm = moment(createDate, 'YYYY:MM:DD HH:mm:ssZ');
if (!mm.isValid()) {
// sometimes a value is not valid
mm = moment(f.exif.FileModifyDate, 'YYYY:MM:DD HH:mm:ssZ');
}
f.exif.FileModifyDate = mm;
this.allTable.data.add({id: f.id,
name: f.exif.FileName,
user: f.exif.SAGE2user ? f.exif.SAGE2user : "-",
date: mm.format("YYYY/MM/DD HH:mm:ss"),
ago: mm.fromNow(),
type: f.exif.FileType,
size: fileSizeIEC(f.exif.FileSize)
});
}
i++;
}
// Clear the search box
$$("search_text").setValue("");
this.refresh();
// Get the existing selection
var treeSelection = _this.tree.getSelectedItem();
// If a media folder is selection
if (treeSelection) {
if (treeSelection.sage2URL) {
_this.allTable.filter(function(obj) {
// trying to match the base URL
return _this.allFiles[obj.id].sage2URL.lastIndexOf(treeSelection.sage2URL, 0) === 0;
});
return;
}
updateSearch(treeSelection.id);
}
};
function sortByDate1(a, b) {
// fileds are 'moment' objects
a = _this.allFiles[a.id].exif.FileModifyDate;
b = _this.allFiles[b.id].exif.FileModifyDate;
return a > b ? 1 : (a < b ? -1 : 0);
}
function sortByDate2(a, b) {
// fileds are 'moment' objects
a = _this.allFiles[a.id].exif.FileModifyDate;
b = _this.allFiles[b.id].exif.FileModifyDate;
return a > b ? 1 : (a < b ? -1 : 0);
}
function sortBySize(a, b) {
// File size in byte
a = _this.allFiles[a.id].exif.FileSize;
b = _this.allFiles[b.id].exif.FileSize;
return a > b ? 1 : (a < b ? -1 : 0);
}
this.refresh = function() {
this.tree.refresh();
this.allTable.refresh();
// Resort the table
if (typeof this.sorting.as === "string") {
this.allTable.sort('#' + this.sorting.by + '#', this.sorting.dir, this.sorting.as);
} else {
this.allTable.sort('', this.sorting.dir, this.sorting.as);
}
this.main.adjust();
};
function createFolder(item, values) {
if (item && values.folder) {
// Send order to the server
wsio.emit('createFolder', {root: item.sage2URL,
path: values.folder});
// Build the tree item
var newid = item.sage2URL + '/' + values.folder;
var newElement = {
id: newid, value: values.folder,
icon: "folder", open: true, sage2URL: newid,
data: [], onContext: {}
};
// Add to the tree
$$("tree1").parse({ parent: item.id, data: newElement });
}
}
var tmenu = webix.ui({
view: "contextmenu",
id: "tmenu",
data: ["New folder", { $template: "Separator" }, "Refresh"],
on: {
onItemClick: function(id) {
var context = this.getContext();
var list = context.obj;
var listId = context.id;
if (id === "New folder") {
webix.ui({
view: "window",
id: "folder_form",
position: "center",
modal: true,
zIndex: 9999,
head: "New folder in " + list.getItem(listId).sage2URL,
body: {
view: "form",
width: 400,
borderless: false,
elements: [
{
view: "text", id: "folder_name", label: "Folder name", name: "folder"
},
{
margin: 5, cols: [
{
view: "button", value: "Cancel", click: function() {
this.getTopParentView().hide();
}
},
{
view: "button", value: "Create", type: "form", click: function() {
createFolder(list.getItem(listId), this.getFormView().getValues());
this.getTopParentView().hide();
}
}
]
}
],
elementsConfig: {
labelPosition: "top"
}
}
}).show();
// Attach handlers for keyboard
$$("folder_name").attachEvent("onKeyPress", function(code, e) {
// ESC closes
if (code === 27 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
this.getTopParentView().hide();
return false;
}
// ENTER activates
if (code === 13 && !e.ctrlKey && !e.shiftKey && !e.altKey) {
createFolder(list.getItem(listId), this.getFormView().getValues());
this.getTopParentView().hide();
return false;
}
});
$$('folder_name').focus();
}
}
}
});
// Server sends the wall configuration
this.serverConfiguration = function(data) {
// Add the media folders to the tree
var f, folder;
this.json_cfg = data;
this.http_port = this.json_cfg.port === 80 ? "" : ":" + this.json_cfg.port;
this.mediaFolders = data.folders;
for (f in data.folders) {
folder = data.folders[f];
// Build the tree item
// folder Object {name: "system", path: "public/uploads/",
// url: "/uploads", upload: false}
var newElement = {
id: folder.url, value: folder.name + ":" + folder.url,
icon: "home", open: true, sage2URL: folder.url, data: [],
tooltip: folder.name + " folder",
onContext: {}
};
// Add the new folder item into the tree
this.tree.parse({ parent: null, data: newElement });
// Fold/close the folders not for upload
if (!folder.upload) {
this.tree.close(folder.url);
}
}
// refresh the tree
this.tree.refresh();
// Add context menu
tmenu.attachTo(this.tree);
// Hidding the 'create folder' on the root folder
this.tree.attachEvent('onBeforeContextMenu', function(id, e, node) {
if (id === 'treeroot' ||
(id.indexOf('Image:/') >= 0) ||
(id.indexOf('Video:/') >= 0) ||
(id.indexOf('PDF:/') >= 0) ||
(id.indexOf('Note:/') >= 0) ||
(id.indexOf('App:/') >= 0) ||
(id.indexOf('Mine:/') >= 0) ||
(id.indexOf('Link:/') >= 0) ||
(id.indexOf('Session:/') >= 0)) {
tmenu.hideItem('New folder');
} else {
tmenu.showItem('New folder');
}
return true;
});
// Adding list of diplay clients
var adminmenu = $$('advancedToolbar').getSubMenu('mainadmin_menu');
var displayList = [];
// add overview client
displayList[0] = {
id: "displayclient_00",
value: "Display Full Wall",
href: "http://" + window.location.hostname + this.http_port + "/display.html?clientID=-1",
target: "_blank"
};
// add a separator line
displayList[1] = {$template: "Separator"};
// add all display clients to list
for (var i = 0; i < this.json_cfg.displays.length; i++) {
displayList[i + 2] = {
id: "displayclient_" + i,
value: "Display " + i,
href: "http://" + window.location.hostname + this.http_port + "/display.html?clientID=" + i,
target: "_blank"
};
}
adminmenu.add({
id: "alldisplayclients_menu",
value: "Display Clients",
type: {subsign: true},
autowidth: true,
config: {zIndex: 9000},
submenu: displayList
});
};
}