(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 ); })();