AstroJS/botanjs/src/Astro/Blog/AstroEdit/SiteLibrary.js

770 lines
20 KiB
JavaScript

(function(){
var ns = __namespace( "Astro.Blog.AstroEdit" );
/** @type {System.Cycle} */
var Cycle = __import( "System.Cycle" );
/** @type {System.Debug} */
var debug = __import( "System.Debug" );
/** @type {System.utils.Perf} */
var Perf = __import( "System.utils.Perf" );
/** @type {System.utils.IKey} */
var IKey = __import( "System.utils.IKey" );
/** @type {System.utils.DataKey} */
var DataKey = __import( "System.utils.DataKey" );
/** @type {System.utils.EventKey} */
var EventKey = __import( "System.utils.EventKey" );
/** @type {Components.MessageBox} */
var MessageBox = __import( "Components.MessageBox" );
/** @type {Components.Mouse.ContextMenu} */
var ContextMenu = __import( "Components.Mouse.ContextMenu" );
/** @type {Dandelion} */
var Dand = __import( "Dandelion" );
/** @type {Dandelion.IDOMObject} */
var IDOMObject = __import( "Dandelion.IDOMObject" );
/** @type {Dandelion.IDOMElement} */
var IDOMElement = __import( "Dandelion.IDOMElement" );
/** @type {Astro.Blog.Config} */
var Conf = __import( "Astro.Blog.Config" );
var postData = __import( "System.Net.postData" );
var prettyDate = __import( "Astro.utils.Date.pretty" );
var SiteLibrary = function ( basePath, processorGet, processorSet ) {
var
view_index = []
, currentView
, inCollection = 0
, indexingItem
, itemSelected = false
, holdingCtrl = false
, holdingShift = false
/** @type {_AstConf_.SiteFile} */
, config = Conf.get( "SiteFile" )
, contentPanel = Dand.id("asl_viewer")
, canvasView
, contextMenu
, stage = Dand.id( "siteLibrary", true )
, asl_smask = Dand.id( "asl_smask", true )
, getItemKeys = function (data)
{
return [
new DataKey("id", data.id)
, new DataKey("title", data.name)
, new DataKey("author", data.author)
, new DataKey("hash", data.hash)
];
}
, bindData = function(target, source, data)
{
IDOMElement(source).addEventListener(new EventKey("MouseDown", function (e)
{
// pass neccessary informations for contextMenu to read
target.idata = this;
if(e.which == 1 || (e.which == 3 && !this.stage.hasAttribute("selected")))
{
// Mousedown event will bubble up to parent node, set itemselected to true
itemSelected = true;
if( !holdingCtrl ) deselectAllItem.bind( target )();
if(holdingShift) rangedSelect();
else indexingItem = this.stage;
selectItem.bind(target)();
}
}.bind(
{
stage: source
, id: data.id
, href: data.src_location
, hash: data.hash
, author: data.author
, name: data.name
, date: data.date_created
, isCollection: 0 < data.cCount
}
)));
}
////// Canvas builders
, resetCanvas = function (name)
{
if(canvasView)
{
contentPanel.removeChild(canvasView);
contentPanel.appendChild(canvasView = Dand.wrap(null, "canvasView", name || canvasView.getAttribute("class"), null, new DataKey("name", currentView)));
}
else
{
contentPanel.appendChild(canvasView = Dand.wrap(null, "canvasView", name, null, new DataKey("name", currentView)));
}
IDOMElement(canvasView).addEventListener(
new EventKey("Click", function (e)
{
if(e.which == 1)
{
if(!itemSelected)
{
deselectAllItem.bind(canvasView)();
canvasView.idata = null;
}
itemSelected = false;
}
}
)
);
}
, buildAudioCanvas = function (e)
{
// TODO
resetCanvas("canvasAudio");
}
/** @param {_AstJson_.AJaxGetFiles} */
, buildImageCanvas = function ( e )
{
var f = e.files;
resetCanvas( "canvasImage" );
for( var i in f )
{
/** @param {_AstJson_.AJaxGetFiles.file} */
var file = f[i];
// id: i, name: file.name, hash: file.hash, sorce: file.src_location, date: file.date_created
var img = Number( file.cCount )
////// Album item
? Dand.wrap(
"span", "img_" + Perf.uuid, "ci_album", Dand.wrap("span")
, [
new IKey("style", "background-image: url(" + basePath + "image/s100/" + file.hash + ".jpg);" )
, new IKey("title"
, "Album: " + file.name
+ "\n" + file.cCount + " file(s)"
+ "\nDate: " + prettyDate( new Date( file.date_created ), true )
+ "\nCreated by: " + file.author
)
, new IKey("collection", 1)
].concat( getItemKeys( file ) )
)
//////// Normal filele
: Dand.wrap(
"span", "img_" + Perf.uuid, null, Dand.wrap( "span" )
, [
new IKey("style", "background-image: url(" + basePath + "image/s100/" + file.hash + ".jpg);" )
, new IKey("title"
, "File: " + file.name
+ "\nDate: " + prettyDate( new Date( file.date_created ), true )
+ "\nCreated by: " + file.author
)
].concat( getItemKeys( file ) )
);
canvasView.appendChild( img );
bindData( canvasView, img, file );
}
contextMenu = new ContextMenu(canvasView, [
new EventKey("Open", openAction)
, {
name: "Copy"
, items: [
new EventKey("Copy source link", copyItemLink)
, new EventKey("Copy hash", copyHash)
]
}
, {
name: "Selection"
, items: [
{
name: "Select"
, items: [
new EventKey("all", selectAllItem)
, new EventKey("none", deselectAllItem)
, new EventKey("Invert selection", reverseSelection)
]
}
,{
name: "By type"
, items:
[
new EventKey("Only albums", selectAllCollections)
, new EventKey("Only files", selectAllFiles)
]
}
]
}
, {
name: "Action"
, items: [
new EventKey("Group selected file(s)", setCollection)
, new EventKey("Add file(s) to collection", insertCollection)
// TODO: in-group file action changes
, new EventKey("Move file(s) to collection", function(){})
, new EventKey("Remove files(s) from collection", excludeCollection)
]
}
,new EventKey("Refresh", refreshCanvas)
, new EventKey("Rename", popupRename)
, new EventKey("Delete", confirmDelete)
], "RMB");
}
// General file, list view
/** @param {_AstJson_.AJaxGetFiles} */
, buildGeneralCanvas = function ( e )
{
if( !e ) return;
var f = e.files, dateStamp;
resetCanvas( "canvasGeneral" );
for(var i in f)
{
/** @param {_AstJson_.AJaxGetFiles.file} */
var file = f[i];
dateStamp = Dand.wrap( "span" );
dateStamp.innerHTML = prettyDate( new Date( file.date_created ) ) ;
var li = Dand.wrap(
null, "g_item" + Perf.uuid, null
, [
Dand.wrapne( "span", file.name )
, dateStamp
, Dand.wrapne( "span", file.author )
]
, getItemKeys( file )
);
canvasView.appendChild( li );
bindData( canvasView, li, file );
}
contextMenu = new ContextMenu(canvasView, [
{
name: "Copy"
, items: [
new EventKey("Copy source link", copyItemLink)
, new EventKey("Copy hash", copyHash)
]
}
, new EventKey("Delete file", confirmDelete)
], "RMB");
}
, selHasCollection = false
// Return the selected files
, selections = function(return_id) {
var s = [];
selHasCollection = false;
IDOMElement(canvasView).foreach(1, function(elem) {
// Save the hashes
if(elem.hasAttribute("selected"))
{
s[s.length] = return_id ? IDOMElement(elem).getDAttribute("id") : elem;
if(elem.hasAttribute("collection")) selHasCollection = true;
}
});
return s;
}
/// Menu item handlers
, confirmDelete = function ()
{
new MessageBox("Confirm delete"
, [
Dand.wrape("Are you sure you want to delete the selected item(s)?")
, Dand.wrape("Warning: This action cannot be undone! Make sure you have de-referenced them from your articles.", new IKey("style", "color: yellow;"))
]
, "Delete it", "No"
, requestDelete.bind({files: selections()})).show();
}
, popupRename = function ()
{
var name_field = Dand.wrap("input", null, "v_snippet_input_single", null, new IKey("type", "text"));
new MessageBox("Rename \"" + canvasView.idata.name + "\"", name_field, "OK", "Cancel", requestRename.bind(
{
name: name_field
, stage: canvasView.idata.stage
, isCollection: canvasView.idata.isCollection
}
)).show();
}
, copyItemLink = function () { return config.f_host + canvasView.idata.href; }
, copyHash = function ()
{
var data = canvasView.idata;
return data.isCollection ? data.id : data.hash;
}
, openAction = function ()
{
if(canvasView.idata.isCollection) openCollection(IDOMElement(canvasView.idata.stage).getDAttribute("id"));
else window.open( config.f_host + canvasView.idata.href);
}
//// ContextMenu Handlers: Selections
, selectItem = function()
{
canvasView.idata.stage.hasAttribute("selected") ? canvasView.idata.stage.removeAttribute("selected") : canvasView.idata.stage.setAttribute("selected", 1);
}
, selectAllItem = function ()
{
IDOMElement(canvasView).foreach(1, function(target)
{
target.setAttribute("selected", 1);
});
}
, selectAllCollections = function ()
{
IDOMElement(canvasView).foreach(1, function(target)
{
target.hasAttribute("collection") ? target.setAttribute("selected", 1) : target.removeAttribute("selected");
});
}
, selectAllFiles = function ()
{
IDOMElement(canvasView).foreach(1, function(target)
{
target.hasAttribute("collection") ? target.removeAttribute("selected") : target.setAttribute("selected", 1);
});
}
, rangedSelect = function ()
{
var items = canvasView.childNodes;
var k = indexingItem;
if(Array.prototype.indexOf.call(items, k) < Array.prototype.indexOf.call(items, canvasView.idata.stage))
{
while(k != canvasView.idata.stage)
{
k.setAttribute("selected", 1);
k = k.nextSibling;
}
}
else
{
while(k != canvasView.idata.stage)
{
k.setAttribute("selected", 1);
k = k.previousSibling;
}
}
}
, deselectAllItem = function ()
{
IDOMElement(canvasView).foreach(1, function(target)
{
target.removeAttribute("selected");
});
}
, reverseSelection = function ()
{
IDOMElement(canvasView).foreach(1, function(target)
{
target.hasAttribute("selected") ? target.removeAttribute("selected") : target.setAttribute("selected", 1);
});
}
//// ContextMenu Handlers: Collections
, setCollection = function ()
{
var s = selections( true )
var name_field = Dand.wrap(
"input", null
, "v_snippet_input_single", null
, new IKey( "type", "text" )
);
new MessageBox(
"Collection name"
, name_field
, "OK", "Cancel"
, requestCollection.bind({ name: name_field, files: s.join(",") })
).show();
}
, openCollection = function ( id ) {
refreshCanvas( id, true );
}
, excludeCollection = function() {
}
, insertCollection = function() {
var collections = []
, ul = Dand.wrapc( "canvasGeneral", null, new IKey( "style", "color: #BBB;" ) )
;
// Get current albums to list
IDOMElement(canvasView).foreach(1, function(target)
{
if(target.hasAttribute("collection"))
{
var t = IDOMElement(target)
// item structure
, li = Dand.wrap(
null, "g_item" + Perf.uuid, null
, [
Dand.wrapne("span", t.getDAttribute("title"), new IKey("style", "width: 75%;"))
, Dand.wrapne("span", t.getDAttribute("author"), new IKey("style", "width: 25%;"))
]
, new DataKey("id", t.getDAttribute("id"))
);
// Set selection behaviour
IDOMElement(li).addEventListener("Click", function(e) {
IDOMElement(ul).foreach(1, function(elem) { elem.hasAttribute("selected") && elem.removeAttribute("selected"); });
this.setAttribute("selected", 1);
}.bind(li));
ul.appendChild(li);
}
});
new MessageBox("Select a collection", ul, "OK", "Cancel", requestInsert.bind({ albumList: ul, collection: selections(true) })).show();
}
//// ContextMenu Handlers: General actions
, requestRename = function( confirmed )
{
if( confirmed )
{
var pData = {
"name": this.name.value
, "id": IDOMElement( this.stage ).getDAttribute( "id" )
};
if(this.isCollection) pData.group = "rename";
else pData.file = "rename";
postData( processorSet, pData, refreshCanvas, loadFailed );
}
}
, requestDelete = function (confirmed)
{
if(confirmed || this.reConfirmed)
{
if(this.files.length < 2)
{
var file = this.files[0];
if(selHasCollection)
{
new MessageBox("Also delete files?"
, "Do you also want to delete the files within the collections?"
, "Delete all files", "Only delete collection"
, delCollection.bind(file)).show();
}
else
{
postData(
processorSet
, { "file": "remove", "hash": IDOMElement(file).getDAttribute("hash") }
, fileDeleted.bind(file), loadFailed
);
}
}
else
{
if(!this.reConfirmed && selHasCollection)
{
// Set the reconfirmation attr
this.reConfirmed = true;
new MessageBox("Also delete files?"
, "You have also selected collection(s), do you want to also delete files inside?"
, "Delete all files", "Only delete collection"
, requestDelete.bind(this)).show();
return;
}
var files = this.files;
for(var i in files)
{
if(files[i].hasAttribute("collection"))
{
// redirect confirmation to delCollection handler
// delete all things when true
delCollection.bind(files[i])(confirmed);
}
else
{
// redirect to self
requestDelete.bind({files: [files[i]]})(true);
}
}
}
}
}
, requestInsert = function(confirmed)
{
if( confirmed )
{
var selectedAlbum = IDOMElement(
IDOMElement( this.albumList ).first( 1, function(elem) {
return elem.hasAttribute("selected");
} ) ).getDAttribute( "id" );
postData(
processorSet
, { "group": "insert", "id": selectedAlbum , "files": this.collection.join(",") }
, refreshCanvas, loadFailed
);
}
}
, delCollection = function (confirmed)
{
var album_id = IDOMElement(this).getDAttribute("id");
if( confirmed )
{
postData( processorGet, { group: "get", aid: album_id }, getFilestoDelete.bind( this ), loadFailed );
}
else
{
postData( processorSet, { group: "remove", id: album_id }, refreshCanvas, loadFailed );
}
}
, getFilestoDelete = function ( e )
{
var l = Object.keys(e.files).length
, fc = 0
, _self = this
, echoDeleted = function()
{
debug.Info("[ASL] File deleted: " + this.name);
fc ++;
if(l == fc) delCollection.bind(_self)(false);
}
, deleteFailed = function ()
{
debug.Error( new Error( "[ASL] Failed to delete: " + this.name ) );
fc ++;
if(l == fc) delCollection.bind(_self)(false);
}
;
for(var i in e.files)
{
postData(
processorSet
, { "file": "remove", "hash": e.files[i]}, echoDeleted.bind({ "name": i })
, deleteFailed.bind({ "name": i })
);
}
}
, fileDeleted = function () { this.parentNode.removeChild(this); }
, requestCollection = function ()
{
if(this.name.value)
{
postData(
processorSet
, { "group": "create", "name": this.name.value, "files": this.files }
, refreshCanvas, loadFailed
);
}
}
////// End canvas builders
, refreshCanvas = function ( view, openCollection )
{
if( typeof view != "string" && !openCollection ) view = null;
// prepare postData
/** @type {_AstJson_.AJaxGetFiles.Request} */
var pdata = {};
if( openCollection )
{
// Set and remove to prevent invalid content set to currentView
inCollection = view;
view = false;
}
currentView = view || ( currentView || "application" );
//// postData parameters
// if we are in collection
if( inCollection )
{
pdata.group = "list";
pdata.aid = inCollection;
}
// else we are in root
else pdata.listFiles = currentView;
switch( currentView )
{
case "image":
postData( processorGet, pdata, buildImageCanvas, loadFailed );
break;
case "audio":
postData( processorGet, pdata, buildAudioCanvas, loadFailed );
break;
default:
postData( processorGet, pdata, buildGeneralCanvas, loadFailed );
break;
}
}
/** @param {_AstJson_.AJaxGetFiles} e */
, panelSwitch = function ( e )
{
if( view_index.length < 1 )
{
var menuBar = Dand.id( "asl_contentMenu" )
, f = e.files, first;
// button mime/type ( counts )
for( var i in f )
{
var elem = Dand.wrap(
"span", null, "asl_menuItem"
, i + "(" + f[i] + ")"
, new DataKey( "name", i ) );
view_index[view_index.length] = [i, elem];
menuBar.appendChild(elem);
IDOMElement(elem).addEventListener(new EventKey("Click", switchView.bind(IDOMElement(elem))));
if( !first ) first = [ i, elem ];
}
if( !first )
{
debug.Info( "No files" );
return;
}
// begin load index
refreshCanvas( first[0] );
// Set style
first[1].setAttribute("current", 1);
}
else
{
// Should update the menu buttons
debug.Info( "Should update the menu buttons" );
}
}
, switchView = function ()
{
// Do nothing if current
if(this.getDAttribute("name") == currentView) return;
for(var i in view_index)
{
if(view_index[i][0] == currentView)
{
view_index[i][1].removeAttribute("current");
}
}
// switching view, reset collection
inCollection = 0;
this.setAttribute("current", 1);
refreshCanvas(this.getDAttribute("name"));
}
, showLibrary = new EventKey("Click"
, function ()
{
stage.style.top = "0";
asl_smask.setAttribute( "expand", 1 );
// Switch behaviour
stage.removeEventListener( showLibrary );
Cycle.delay(function () {
Dand.id( "ae_body" ).style.display = Dand.id( "ae_panel" ).style.display = "none";
asl_smask.addEventListener( hideLibrary );
// load library statistics
loadLibStats( panelSwitch, loadFailed );
}, 500);
}
)
, hideLibrary = new EventKey(
"Click"
, function ()
{
stage.style.top = "";
asl_smask.removeAttribute( "expand" );
// Switch behaviour
asl_smask.removeEventListener( hideLibrary );
Dand.id("ae_body").style.display = Dand.id( "ae_panel" ).style.display = "";
Cycle.delay(function () {
stage.addEventListener( showLibrary );
}, 500);
}
)
, loadFailed = function (e)
{
// TODO: make some notifications here
}
, loadLibStats = function ( handler, failedHandler )
{
postData( processorGet, { "countTypes": 1 }, handler, failedHandler );
}
, keyHold = function(e) { holdingCtrl = e.ctrlKey; holdingShift = e.shiftKey; }
, dKeyUp = new EventKey( "KeyUp", keyHold )
, dKeyDown = new EventKey( "KeyDown", keyHold )
;
Dand.id( "asl_homeBtn", true ).addEventListener( "click", function( e ) { refreshCanvas( 0, true ); } );
Dand.id( "asl_refresh", true ).addEventListener( "click", function( e ) { refreshCanvas( 0 ); } );
new IDOMObject( document ).addEventListeners([ dKeyUp, dKeyDown ]);
stage.addEventListener(showLibrary);
};
ns[ NS_EXPORT ]( EX_CLASS, "SiteLibrary", SiteLibrary );
})();