forked from Botanical/BotanJS
Astro Classes
This commit is contained in:
453
botanjs/src/Astro/Blog/AstroEdit/Article.js
Normal file
453
botanjs/src/Astro/Blog/AstroEdit/Article.js
Normal file
@@ -0,0 +1,453 @@
|
||||
(function(){
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit" );
|
||||
|
||||
/** @type {System.Cycle} */
|
||||
var Cycle = __import( "System.Cycle" );
|
||||
/** @type {System.utils.EventKey} */
|
||||
var EventKey = __import( "System.utils.EventKey" );
|
||||
/** @type {System.Debug} */
|
||||
var debug = __import( "System.Debug" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
/** @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 Config = __import( "Astro.Blog.Config" );
|
||||
/** @type {Astro.Blog.Components.Bubble} */
|
||||
var Bubble = __import( "Astro.Blog.Components.Bubble" );
|
||||
|
||||
var postData = __import( "System.Net.postData" );
|
||||
var prettyDate = __import( "Astro.utils.Date.pretty" );
|
||||
|
||||
var Visualizer = ns[ NS_INVOKE ]( "Visualizer" );
|
||||
var Tag = ns[ NS_INVOKE ]( "Tag" );
|
||||
|
||||
var Article = function( processorSet )
|
||||
{
|
||||
var pBubble = new Bubble();
|
||||
|
||||
var Draft = ns[ NS_INVOKE ]( "Draft" );
|
||||
|
||||
var _title = "";
|
||||
var _content = "";
|
||||
|
||||
//// Classes & obj
|
||||
var _ae_tag = null;
|
||||
var _visualizer = null;
|
||||
var timestamp = new Date();
|
||||
|
||||
/** @type {_AstJson_.AJaxGetArticle.entry} */
|
||||
var ArticleModel = {
|
||||
title: ""
|
||||
, slug: ""
|
||||
, content: ""
|
||||
, date_modified: timestamp
|
||||
, date_published: timestamp
|
||||
, date_created: timestamp
|
||||
, archived: false
|
||||
, tags: null
|
||||
, draft: true
|
||||
, article_id: false
|
||||
};
|
||||
|
||||
var ae_content = Dand.id( "ae_content" );
|
||||
var ae_title = Dand.id( "ae_title" );
|
||||
|
||||
// Article info
|
||||
var ae_cdate = Dand.id( "ae_cdate" );
|
||||
var ae_mdate = Dand.id( "ae_mdate" );
|
||||
var ae_pdate = Dand.id( "ae_pdate" );
|
||||
var ae_status = Dand.id( "ae_status" );
|
||||
var ae_backup = Dand.id( "ae_backup_btn" );
|
||||
var ae_publish = Dand.id( "ae_publish_btn" );
|
||||
var ae_preview = Dand.id( "ae_preview" );
|
||||
|
||||
/** @type {_AstConf_.AstroEdit} */
|
||||
var a_conf = Config.get( "AstroEdit" );
|
||||
var base_path = Config.get( "BasePath" );
|
||||
|
||||
///// preview fields
|
||||
var ae_p_fields = {
|
||||
mtime: set_field_name( Dand.wrap( "input" ), "date_modified" )
|
||||
, ptime: set_field_name( Dand.wrap( "input" ), "date_published" )
|
||||
, title: set_field_name( Dand.wrap( "input" ), "title" )
|
||||
, content: set_field_name( Dand.wrap( "input" ), "content" )
|
||||
, tags: set_field_name( Dand.wrap( "input" ), "tags" )
|
||||
};
|
||||
|
||||
// Initialize id
|
||||
var __article_id = false;
|
||||
var canSave = false;
|
||||
|
||||
var temp;
|
||||
|
||||
for ( var i in ae_p_fields ) ae_preview.appendChild( ae_p_fields[i] );
|
||||
//// End preview fields
|
||||
|
||||
|
||||
var enableSaveFunction = function ()
|
||||
{
|
||||
ae_backup.className = "ae_iValue ae_dodgerblue flsf";
|
||||
canSave = true;
|
||||
}
|
||||
|
||||
, disableSaveFunction = function ()
|
||||
{
|
||||
ae_backup.className = "ae_iValue ae_disabled flsf";
|
||||
canSave = false;
|
||||
}
|
||||
|
||||
, contentUpdate = function ()
|
||||
{
|
||||
if( !canSave ) enableSaveFunction();
|
||||
// (_visualizer.saveRaw() != _content) ? enableSaveFunction() : disableSaveFunction();
|
||||
}
|
||||
|
||||
//// private methods
|
||||
////// Handlers ///////
|
||||
|
||||
, saveSuccess = function (obj)
|
||||
{
|
||||
disableSaveFunction();
|
||||
ae_mdate.innerHTML = prettyDate( new Date( obj.date_modified ) );
|
||||
|
||||
// Replace state of the content and title
|
||||
ArticleModel.title = _title;
|
||||
ArticleModel.content = _content;
|
||||
ArticleModel.date_modified = obj.date_modified;
|
||||
|
||||
// Set article id if this is a new document
|
||||
if ( obj.article_id )
|
||||
ArticleModel.article_id = __article_id = obj.article_id;
|
||||
|
||||
window.history.replaceState( ArticleModel, "", base_path + "astroedit/" + __article_id + "/" );
|
||||
}
|
||||
|
||||
, publishSuccess = function (obj)
|
||||
{
|
||||
ae_publish.innerHTML = "Done edit";
|
||||
ae_backup.innerHTML = "Backup(Ctrl + s)";
|
||||
|
||||
ArticleModel.date_published = obj.date_published;
|
||||
ae_pdate.innerHTML = prettyDate( new Date( obj.date_published ) );
|
||||
|
||||
this.contentUpdate && saveSuccess(obj);
|
||||
|
||||
new MessageBox("AstroEdit", "You have successfully published your article!", "Stay here", "Exit and goto article", publishAction).show();
|
||||
}
|
||||
|
||||
, publishAction = function (stay)
|
||||
{
|
||||
if (!stay)
|
||||
{
|
||||
window.open( base_path + "article/view/" + ArticleModel.slug + "/") && window.close();
|
||||
}
|
||||
}
|
||||
|
||||
, restoreArticle = function(obj)
|
||||
{
|
||||
debug.Info("[Document] Looking for stored data");
|
||||
if (obj)
|
||||
{
|
||||
debug.Info("[Document] .. data found");
|
||||
// Set stored article id
|
||||
__article_id = obj.article_id;
|
||||
setArticle( obj );
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!( ArticleModel && 0 < ArticleModel.article_id ))
|
||||
{
|
||||
debug.Info("[Document] .. data not found");
|
||||
// This is a state of new article
|
||||
var d = Math.floor(new Date().getTime()/1000);
|
||||
__article_id = false;
|
||||
setArticle({
|
||||
title:""
|
||||
, content:""
|
||||
, date_modified: d
|
||||
, date_published: 0
|
||||
, date_created: d
|
||||
, archived: false
|
||||
, tags: null
|
||||
, draft: true
|
||||
, article_id: false
|
||||
});
|
||||
window.history.replaceState( ArticleModel, "", base_path + "astroedit/new/" );
|
||||
}
|
||||
}
|
||||
}
|
||||
/** @param {_AstJson_.AJaxGetArticle} */
|
||||
, showArticle = function( obj )
|
||||
{
|
||||
if ( obj && obj.entry )
|
||||
{
|
||||
debug.Info( "[Document] Article Loaded" );
|
||||
if ( obj.backup )
|
||||
{
|
||||
pBubble.setColor( "royalblue" );
|
||||
pBubble.pop( "Using backup entry" );
|
||||
Cycle.delay( function () { pBubble.blurp() }, 3000 );
|
||||
}
|
||||
setArticle( obj.entry );
|
||||
if ( !obj.entry.article_id )
|
||||
{
|
||||
// sever will not return article_id
|
||||
// since it is an UPDATE
|
||||
// Store the article_id manually
|
||||
obj.entry.article_id = __article_id;
|
||||
}
|
||||
__statePusher( obj.entry, __article_id );
|
||||
}
|
||||
else
|
||||
{
|
||||
debug.Info( "[Document] Article: " + String( __article_id ) + " not found on server." );
|
||||
__article_id = false;
|
||||
}
|
||||
}
|
||||
|
||||
, setArticle = function ( entry )
|
||||
{
|
||||
ArticleModel = entry;
|
||||
ae_title.value = _title = ArticleModel.title;
|
||||
|
||||
_visualizer.visualizeData( _content = ArticleModel.content );
|
||||
|
||||
ae_mdate.innerHTML = prettyDate( new Date( ArticleModel.date_modified ) );
|
||||
ae_cdate.innerHTML = prettyDate( new Date( ArticleModel.date_created ) );
|
||||
|
||||
ae_pdate.innerHTML = ArticleModel.date_published
|
||||
? prettyDate( new Date( ArticleModel.date_published ) )
|
||||
: "Not published."
|
||||
;
|
||||
|
||||
ae_status.innerHTML =
|
||||
( ArticleModel.archived ? "Archived. " : "" )
|
||||
+ ( ArticleModel.draft ? "In draft" : "Published" )
|
||||
;
|
||||
|
||||
ae_publish.innerHTML = ArticleModel.draft ? "Publish" : "Done edit";
|
||||
ae_backup.innerHTML = ( ArticleModel.draft ? "Save" : "Backup" ) + "(Ctrl + s)";
|
||||
|
||||
|
||||
_ae_tag && _ae_tag.setTags( ArticleModel.tags );
|
||||
}
|
||||
|
||||
, deleteDraft = function (confirmed)
|
||||
{
|
||||
if (confirmed)
|
||||
{
|
||||
var _data = {
|
||||
"draft": ArticleModel.draft ? 1 : 0
|
||||
, "article_id": __article_id
|
||||
, "del": 1
|
||||
};
|
||||
|
||||
postData( processorSet, _data, deleteSuccess, serverFailed );
|
||||
}
|
||||
}
|
||||
|
||||
, deleteSuccess = function ()
|
||||
{
|
||||
location.reload(true);
|
||||
}
|
||||
|
||||
, serverFailed = function ( obj )
|
||||
{
|
||||
pBubble.setColor( "red" );
|
||||
pBubble.pop( obj["mesg"] );
|
||||
Cycle.delay( function () { pBubble.blurp() }, 3000 );
|
||||
}
|
||||
|
||||
, contentEmpty = function ()
|
||||
{
|
||||
return !Boolean( ae_content.hasChildNodes() );
|
||||
}
|
||||
;
|
||||
|
||||
// Bind properties
|
||||
|
||||
this.saveOrBackup = function ()
|
||||
{
|
||||
if (canSave)
|
||||
{
|
||||
// Store current content and title
|
||||
_title = ae_title.value.trim();
|
||||
_content = _visualizer.saveRaw();
|
||||
|
||||
/** @type {_AstJson_.AJaxGetArticle.entry} */
|
||||
var _data =
|
||||
{
|
||||
article_id: __article_id ? __article_id : ""
|
||||
, title: _title
|
||||
, content: _content
|
||||
, tags: _ae_tag.getTags()
|
||||
, draft: ArticleModel.draft ? 1 : 0
|
||||
};
|
||||
|
||||
if (ArticleModel.draft == 0)
|
||||
{
|
||||
// This a published article
|
||||
// action is Backup
|
||||
_data.backup = 1;
|
||||
}
|
||||
|
||||
postData( processorSet, _data, saveSuccess, serverFailed);
|
||||
}
|
||||
};
|
||||
|
||||
this.load = function ( aid, statePusher )
|
||||
{
|
||||
if( aid && __article_id != aid )
|
||||
{
|
||||
debug.Info( "[Document] Loading article: " + aid );
|
||||
__statePusher = statePusher;
|
||||
postData(
|
||||
a_conf.paths.get_article
|
||||
, { article_id: __article_id = aid }
|
||||
, showArticle
|
||||
, serverFailed
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
this.getArticleId = function () { return __article_id; }
|
||||
|
||||
this.preview = function ()
|
||||
{
|
||||
ae_p_fields.title.value = ae_title.value;
|
||||
ae_p_fields.content.value = _visualizer.saveRaw();
|
||||
ae_p_fields.mtime.value = ArticleModel.date_modified;
|
||||
ae_p_fields.ptime.value = Number( ArticleModel.date_published )
|
||||
? ArticleModel.date_published
|
||||
: Math.floor( 0.001*( new Date().getTime() ) )
|
||||
;
|
||||
ae_p_fields.tags.value = _ae_tag.getTags();
|
||||
|
||||
ae_preview.submit();
|
||||
};
|
||||
|
||||
this.invoke = function (_class)
|
||||
{
|
||||
if ( _class instanceof Draft ) _ae_draft = _class;
|
||||
if ( _class instanceof Visualizer )
|
||||
{
|
||||
_visualizer = _class;
|
||||
_visualizer.setContentDiv( ae_content );
|
||||
}
|
||||
if ( _class instanceof Tag )
|
||||
{
|
||||
_ae_tag = _class;
|
||||
ArticleModel && ArticleModel.tags && ( _ae_tag ).setTags( ArticleModel.tags );
|
||||
}
|
||||
};
|
||||
|
||||
this.saveAndPublish = function ()
|
||||
{
|
||||
if ( contentEmpty() ) return;
|
||||
|
||||
/** @type {_AstJson_.AJaxGetArticle.entry} */
|
||||
var _data = {
|
||||
article_id: __article_id ? __article_id : ""
|
||||
, draft: 0
|
||||
};
|
||||
|
||||
if ( !ArticleModel.draft )
|
||||
{
|
||||
// This is a published article
|
||||
// Do not backup
|
||||
_data.backup = 0;
|
||||
canSave = true;
|
||||
}
|
||||
|
||||
if ( canSave )
|
||||
{
|
||||
// Store current content and title
|
||||
_title = ae_title.value.trim();
|
||||
_content = _visualizer.saveRaw();
|
||||
|
||||
_data.title = _title;
|
||||
_data.content = _content;
|
||||
_data.tags = _ae_tag.getTags();
|
||||
|
||||
postData( processorSet, _data, publishSuccess.bind({ contentUpdate: true }), serverFailed );
|
||||
}
|
||||
else
|
||||
{
|
||||
// Do not submit uneccessary data!
|
||||
postData( processorSet, _data, publishSuccess, serverFailed );
|
||||
}
|
||||
};
|
||||
|
||||
this.drop = function ()
|
||||
{
|
||||
new MessageBox(
|
||||
"Delete draft"
|
||||
, "Are you sure you want to delete this draft? (Published article will only remove backup draft.)"
|
||||
, "Delete", "No"
|
||||
, deleteDraft
|
||||
).show();
|
||||
};
|
||||
|
||||
this.updateContent = contentUpdate;
|
||||
|
||||
// Setting Ctrl+s functions
|
||||
new IDOMObject(document).addEventListener(
|
||||
new EventKey("KeyDown", function(e)
|
||||
{
|
||||
// key Ctrl(17)
|
||||
if(e.ctrlKey == true && e.which == 83)
|
||||
{
|
||||
// key s (83)
|
||||
this.saveOrBackup();
|
||||
e.preventDefault();
|
||||
}
|
||||
/*
|
||||
else if(e.which == 66)
|
||||
{
|
||||
// key b(66)
|
||||
this.backup.bind(this)();
|
||||
return false;
|
||||
}
|
||||
*/
|
||||
}.bind(this))
|
||||
);
|
||||
|
||||
IDOMElement( ae_backup ).addEventListener( "Click", this.saveOrBackup );
|
||||
|
||||
window.addEventListener(
|
||||
"popstate"
|
||||
, function( event )
|
||||
{
|
||||
debug.Info( "[Document] Pop State fired" );
|
||||
restoreArticle( event.state );
|
||||
}
|
||||
);
|
||||
|
||||
ae_title.oninput = function ()
|
||||
{
|
||||
( ae_title.value != _title ) ? enableSaveFunction() : disableSaveFunction();
|
||||
}
|
||||
|
||||
temp = IDOMElement(ae_content);
|
||||
|
||||
temp.addEventListener( "Input", function() { enableSaveFunction(); } );
|
||||
|
||||
document.body.appendChild( pBubble.init() );
|
||||
|
||||
return this;
|
||||
};
|
||||
|
||||
var set_field_name = function ( elem, value )
|
||||
{
|
||||
elem.name = value;
|
||||
elem.type = "hidden";
|
||||
return elem;
|
||||
};
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Article", Article );
|
||||
})();
|
158
botanjs/src/Astro/Blog/AstroEdit/Draft.js
Normal file
158
botanjs/src/Astro/Blog/AstroEdit/Draft.js
Normal file
@@ -0,0 +1,158 @@
|
||||
(function(){
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit" );
|
||||
|
||||
/** @type {System.Cycle} */
|
||||
var Cycle = __import( "System.Cycle" );
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
|
||||
var postData = __import( "System.Net.postData" );
|
||||
|
||||
/** @param {Astro.Blog.AstroEdit.Article} article */
|
||||
var Draft = function ( article, draftsUri )
|
||||
{
|
||||
/** @type {Astro.Blog.AstroEdit.Article} */
|
||||
var Article = ns[ NS_INVOKE ]( "Article" );
|
||||
|
||||
if ( !( article instanceof Article ) ) return;
|
||||
|
||||
// Drafts Container
|
||||
var ae_expand = Dand.id("ae_expand")
|
||||
, ae_drafts = Dand.id("ae_user_drafts")
|
||||
, ae_drafts_h = null
|
||||
|
||||
////// Draft Section
|
||||
, showDrafts = function ()
|
||||
{
|
||||
showDrafts = function() { };
|
||||
// One-time trigger only.
|
||||
getDraftList({offset: 0});
|
||||
}
|
||||
|
||||
, getDraftList = function ( p )
|
||||
{
|
||||
postData( draftsUri, p, listDraft.bind(p), draftFailed );
|
||||
}
|
||||
|
||||
/** @param {_AstJson_.AJaxGetDrafts} obj */
|
||||
, listDraft = function ( obj )
|
||||
{
|
||||
var entries = obj.entries, entry;
|
||||
|
||||
for ( var i in entries )
|
||||
{
|
||||
/** @param {_AstJson_.AJaxGetDrafts.entry} */
|
||||
entry = entries[i];
|
||||
// Insert entries
|
||||
ae_drafts.appendChild(
|
||||
entry = Dand.wrapc(
|
||||
"ae_dEntry"
|
||||
, [
|
||||
Dand.wrapc(
|
||||
"ae_dEntry_title fls"
|
||||
, entry.active
|
||||
?
|
||||
[
|
||||
Dand.textNode( entry.title )
|
||||
, Dand.wrap( "span", null, "ae_dActive_bubble", "\u25CF" )
|
||||
]
|
||||
: entry.title
|
||||
)
|
||||
, Dand.wrapc( "ae_dEntry_content flsf", entry.content )
|
||||
, Dand.wrapc( "ae_dEntry_date fsf", entry.date )
|
||||
]
|
||||
, entry.active
|
||||
? [ new IKey ( "value", entry._id ), new IKey( "active" ) ]
|
||||
: new IKey( "value", entry._id ) )
|
||||
);
|
||||
|
||||
// Register on click function
|
||||
entry.addEventListener( "click", function() {
|
||||
article.load( entry.getAttribute( "value" ), __pushState );
|
||||
} );
|
||||
}
|
||||
|
||||
ae_drafts_h = ae_drafts.clientHeight;
|
||||
ae_drafts.style.height = 0;
|
||||
|
||||
Cycle.next(function(){
|
||||
// This doesn't make sense
|
||||
// but we need to actually access the clientHeight
|
||||
// to get the height animation working
|
||||
ae_drafts.clientHeight;
|
||||
ae_drafts.style.height = String( ae_drafts_h ) + "px";
|
||||
});
|
||||
}
|
||||
|
||||
, draftFailed = function (obj)
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
|
||||
// Handlers
|
||||
, setupExpand = function ()
|
||||
{
|
||||
ae_expand.className = "ae_expand_btn";
|
||||
var panel = Dand.id("ae_minor_panel");
|
||||
panel.onmouseover = function()
|
||||
{
|
||||
ae_expand.style.height = "20px";
|
||||
}
|
||||
panel.onmouseout = function()
|
||||
{
|
||||
ae_expand.style.height = "";
|
||||
}
|
||||
panel.onclick = function()
|
||||
{
|
||||
ae_expand.style.height = "";
|
||||
ae_drafts.style.height = String(ae_drafts_h) + "px";
|
||||
Cycle.delay(setupCollapse , 250);
|
||||
|
||||
// Disable mouse events
|
||||
panel.onmouseover = panel.onmouseout = panel.onclick = null;
|
||||
|
||||
showDrafts();
|
||||
}
|
||||
}
|
||||
|
||||
, setupCollapse = function ()
|
||||
{
|
||||
ae_expand.className = "ae_callapse_btn";
|
||||
Cycle.delay(function()
|
||||
{
|
||||
ae_expand.onclick = function()
|
||||
{
|
||||
ae_expand.style.backgroundColor = "";
|
||||
ae_drafts.style.height = "0";
|
||||
Cycle.delay(setupExpand, 250);
|
||||
|
||||
// Disable mouse events
|
||||
ae_expand.onmouseover = ae_expand.onmouseout = ae_expand.onclick = null;
|
||||
}
|
||||
ae_expand.onmouseover = function()
|
||||
{
|
||||
ae_expand.style.backgroundColor = "rgba(255, 255, 255, 0.2)";
|
||||
}
|
||||
ae_expand.onmouseout = function()
|
||||
{
|
||||
ae_expand.style.backgroundColor = "";
|
||||
}
|
||||
}, 250);
|
||||
}
|
||||
// End Handlers
|
||||
|
||||
|
||||
, __pushState = function ( obj, article_id )
|
||||
{
|
||||
window.history.pushState( obj, "", "../" + article_id + "/" );
|
||||
}
|
||||
|
||||
setupExpand();
|
||||
article.invoke( this );
|
||||
};
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Draft", Draft );
|
||||
})();
|
367
botanjs/src/Astro/Blog/AstroEdit/SiteLibrary.css
Normal file
367
botanjs/src/Astro/Blog/AstroEdit/SiteLibrary.css
Normal file
@@ -0,0 +1,367 @@
|
||||
#siteLibrary {
|
||||
position: fixed;
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
top: calc(-100% - 5px);
|
||||
}
|
||||
|
||||
#siteLibrary:hover {
|
||||
top: calc(-100% + 1.5em);
|
||||
}
|
||||
|
||||
#asl_viewer {
|
||||
width: calc(100% - 300px);
|
||||
height: 100%;
|
||||
|
||||
overflow-x: hidden;
|
||||
overflow-y: scroll;
|
||||
|
||||
float: left;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.asl_header {
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
|
||||
top: 100%;
|
||||
margin-top: -20px;
|
||||
|
||||
position: absolute;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
#asl_viewer > #canvasView {
|
||||
position: absolute;
|
||||
min-height: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.asl_viewer {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
background: #EEE;
|
||||
|
||||
-moz-box-shadow: 0 7px 5px black;
|
||||
-webkit-box-shadow: 0 7px 5px black;
|
||||
box-shadow: 0 7px 5px black;
|
||||
}
|
||||
|
||||
.asl_contentMenu {
|
||||
bottom: 0;
|
||||
position: absolute;
|
||||
padding: 1em;
|
||||
}
|
||||
|
||||
.asl_contentMenu > span {
|
||||
margin: 0 0.2em;
|
||||
padding: 0.5em 0.5em;
|
||||
|
||||
cursor: default;
|
||||
|
||||
color: white;
|
||||
background-color: rgba(0, 0, 0, 0.6);
|
||||
font-family: custom-serif;
|
||||
}
|
||||
|
||||
.asl_contentMenu > span:hover {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.asl_contentMenu > span[current] {
|
||||
background-color: rgba(0, 0, 0, 0.8);
|
||||
}
|
||||
|
||||
.asl_smask {
|
||||
height: 10px;
|
||||
background-color: royalblue;
|
||||
|
||||
position: absolute;
|
||||
bottom: -5px;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.asl_smask:before {content: '';
|
||||
width: 100%;
|
||||
height: 20px;
|
||||
|
||||
top: -10px;
|
||||
position: absolute;
|
||||
|
||||
z-index: -1;
|
||||
background-color: transparent;
|
||||
}
|
||||
|
||||
.asl_smask[expand] {
|
||||
background-image: url(http://file.astropenguin.net/blog/layout-images/collapse.png);
|
||||
background-position: center 2.5px;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
.asl_smask[expand]:hover {
|
||||
height: 20px;
|
||||
}
|
||||
|
||||
#siteLibrary .asl_title, .asl_intitle {
|
||||
font-size: 1.5em;
|
||||
|
||||
font-family: custom-sans;
|
||||
|
||||
overflow: hidden;
|
||||
|
||||
background-color: royalblue;
|
||||
color: white;
|
||||
}
|
||||
|
||||
#siteLibrary .asl_title {
|
||||
padding: 0.3em 0.5em;
|
||||
}
|
||||
|
||||
.asl_contentPanel {
|
||||
overflow: hidden;
|
||||
position: absolute;
|
||||
|
||||
height: calc(100% - 2.5em);
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
#siteLibrary .asl_title {
|
||||
cursor: default;
|
||||
|
||||
display: inline-block;
|
||||
position: absolute;;
|
||||
|
||||
right: 350px;
|
||||
bottom: -1.7em;
|
||||
|
||||
-moz-box-shadow: 2px 2px 5px black;
|
||||
-webkit-box-shadow: 2px 2px 5px black;
|
||||
box-shadow: 2px 2px 5px black;
|
||||
}
|
||||
|
||||
/*** ASL Canvases ***/
|
||||
.canvasImage > span {
|
||||
width: 100px;
|
||||
height: 100px;
|
||||
float: left;
|
||||
margin: 0.2em;
|
||||
|
||||
background-repeat: no-repeat;
|
||||
background-position: center;
|
||||
|
||||
border: 1px solid transparent;
|
||||
|
||||
}
|
||||
|
||||
.canvasImage > span[selected] {
|
||||
background-color: lightblue;
|
||||
border-color: royalblue;
|
||||
}
|
||||
|
||||
.canvasImage > span > span {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
display: block;
|
||||
}
|
||||
|
||||
.canvasImage > span > span:hover {
|
||||
background-color: rgba(0, 0, 0, 0.2) !important;
|
||||
border-color: #444 !important;
|
||||
}
|
||||
|
||||
.ci_album {
|
||||
-moz-box-shadow: 2px 3px 0 0 black;
|
||||
-webkit-box-shadow: 2px 3px 0 0 black;
|
||||
box-shadow: 2px 3px 0 0 #666;
|
||||
border: 1px solid #666 !important;
|
||||
}
|
||||
|
||||
|
||||
.canvasGeneral {
|
||||
padding: 0.2em;
|
||||
cursor: default;
|
||||
|
||||
color: #444;
|
||||
}
|
||||
|
||||
.canvasGeneral > div {
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
.canvasGeneral > div:hover {
|
||||
background-color: rgba(0, 0 ,0, 0.2);
|
||||
}
|
||||
|
||||
.canvasGeneral > div > span {
|
||||
display: inline-block;
|
||||
|
||||
width: 30%;
|
||||
padding: 0.2em 0;
|
||||
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.canvasGeneral > div > span:last-child {
|
||||
width: 10%;
|
||||
}
|
||||
|
||||
.canvasGeneral > div[selected] {
|
||||
background-color: orangered;
|
||||
color: white;
|
||||
}
|
||||
|
||||
/*** End ASL Canvases ***/
|
||||
|
||||
/*** Uploader ***/
|
||||
#asl_uploader {
|
||||
width: 300px;
|
||||
height: 100%;
|
||||
|
||||
float: right;
|
||||
|
||||
font-family: custom-sans;
|
||||
}
|
||||
|
||||
#asl_u_head {
|
||||
position: absolute;
|
||||
background: #EEE;
|
||||
z-index: 1;
|
||||
}
|
||||
|
||||
.upldr_title {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
.asl_fwrapper {
|
||||
overflow-y: scroll;
|
||||
|
||||
position: absolute;
|
||||
top: 0;
|
||||
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
/*
|
||||
-moz-box-shadow: inset 0 0 20px black;
|
||||
-webkit-box-shadow: inset 0 0 20px black;
|
||||
box-shadow: inset 0 0 20px black;
|
||||
*/
|
||||
}
|
||||
|
||||
.asl_fileList {
|
||||
font-family: sans-serif;
|
||||
color: #444;;
|
||||
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.asl_fileList > div {
|
||||
/* 0.5em for fwrapper padding */
|
||||
margin-right: 50%;
|
||||
padding: 0.5em;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.asl_uItem:hover {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.asl_uItemStat {
|
||||
padding: 0 0.5em 0 0;
|
||||
color: orange;
|
||||
}
|
||||
|
||||
.asl_split {
|
||||
position: relative;
|
||||
height: 80px;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.asl_split > div {
|
||||
height: 100%;
|
||||
padding: 0.5em;
|
||||
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
.asl_left {
|
||||
float: left;
|
||||
width: 135px;
|
||||
}
|
||||
|
||||
.asl_right {
|
||||
float: right;
|
||||
width: calc(100% - 135px);
|
||||
}
|
||||
|
||||
.asl_fileName {
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.asl_preview {
|
||||
padding: 0.2em;
|
||||
background-color: white;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
/* Progress indicator */
|
||||
.asl_progress {
|
||||
padding: 0.5em 0;
|
||||
}
|
||||
|
||||
.asl_ptext {
|
||||
font-size: 0.8em;
|
||||
}
|
||||
|
||||
.asl_pbar {
|
||||
background-color: white;
|
||||
position: relative;
|
||||
height: 1em;
|
||||
margin-top: 0.2em;
|
||||
}
|
||||
|
||||
.asl_pbar_fill {
|
||||
background: greenyellow;
|
||||
position: absolute;
|
||||
width: 0%;
|
||||
height: 100%;
|
||||
}
|
||||
|
||||
.asl_go_up {
|
||||
width: 0;
|
||||
height: 0;
|
||||
|
||||
border-top: 0 solid transparent;
|
||||
border-bottom: 0.5em solid transparent;
|
||||
border-left: 0.5em solid #FFF;
|
||||
|
||||
position: absolute;
|
||||
|
||||
left: 0;
|
||||
}
|
||||
|
||||
.asl_btn {
|
||||
padding: 0.3em;
|
||||
text-align: center;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.asl_btn:hover {
|
||||
background-color: rgba( 0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.asl_instruction {
|
||||
width: 100%;
|
||||
height: 100%;
|
||||
|
||||
font-size: 0.8em;
|
||||
}
|
745
botanjs/src/Astro/Blog/AstroEdit/SiteLibrary.js
Normal file
745
botanjs/src/Astro/Blog/AstroEdit/SiteLibrary.js
Normal file
@@ -0,0 +1,745 @@
|
||||
(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" );
|
||||
|
||||
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
|
||||
|
||||
, 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
|
||||
, 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)
|
||||
{
|
||||
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 "http://file.astropenguin.net/blog/site-library/" + canvasView.idata.href; }
|
||||
, copyHash = function () { return canvasView.idata.hash; }
|
||||
|
||||
, openAction = function ()
|
||||
{
|
||||
if(canvasView.idata.isCollection) openCollection(IDOMElement(canvasView.idata.stage).getDAttribute("id"));
|
||||
else window.open("http://file.astropenguin.net/blog/site-library/" + 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];
|
||||
}
|
||||
|
||||
// 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 );
|
||||
})();
|
27
botanjs/src/Astro/Blog/AstroEdit/Tag.css
Normal file
27
botanjs/src/Astro/Blog/AstroEdit/Tag.css
Normal file
@@ -0,0 +1,27 @@
|
||||
.tag_active {
|
||||
color: white;
|
||||
opacity: 1 !important;
|
||||
}
|
||||
|
||||
.ae_tag_delete {
|
||||
color: white;
|
||||
padding: 0 0.5em 0 0;
|
||||
}
|
||||
|
||||
.ae_tag_delete:hover {
|
||||
color: red;
|
||||
}
|
||||
|
||||
.ae_tag_add {
|
||||
color: white;
|
||||
cursor: default;
|
||||
font-weight: 200;
|
||||
}
|
||||
|
||||
.ae_tag_add:hover {
|
||||
color: dodgerblue;
|
||||
}
|
||||
|
||||
#ae_tags > span {
|
||||
float: left;
|
||||
}
|
197
botanjs/src/Astro/Blog/AstroEdit/Tag.js
Normal file
197
botanjs/src/Astro/Blog/AstroEdit/Tag.js
Normal file
@@ -0,0 +1,197 @@
|
||||
(function(){
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit" );
|
||||
|
||||
/** @type {System.Debug} */
|
||||
var debug = __import( "System.Debug" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Astro.Blog.Config} */
|
||||
var Config = __import( "Astro.Blog.Config" );
|
||||
|
||||
var postData = __import( "System.Net.postData" );
|
||||
|
||||
/** @param {Astro.Blog.AstroEdit.Article} */
|
||||
var Tag = function ( ae_article, tagCountUri )
|
||||
{
|
||||
var Article = ns[ NS_INVOKE ]( "Article" );
|
||||
|
||||
if ( !( ae_article instanceof Article ) )
|
||||
return false;
|
||||
|
||||
/** @type {_AstConf_.AstroEdit} */
|
||||
var a_conf = Config.get( "AstroEdit" );
|
||||
|
||||
var ae_document = ae_article;
|
||||
|
||||
var ae_addTag = Dand.id( "ae_addTags" );
|
||||
var ae_tags = Dand.id( "ae_tags" );
|
||||
|
||||
// Store tags for future use
|
||||
var tags = {};
|
||||
|
||||
////// Handlers
|
||||
ae_addTag.onclick = function ()
|
||||
{
|
||||
|
||||
// Input fields
|
||||
var ae_tagInput;
|
||||
|
||||
// Popup MessageBox
|
||||
new MessageBox(
|
||||
"Add new tag(s)"
|
||||
, Dand.wrape([
|
||||
Dand.wrapc(
|
||||
"v_instruction flsf"
|
||||
, "Tags are separated by \\n. (existing tags will be ignored.)"
|
||||
)
|
||||
, ae_tagInput = Dand.wrap( "textarea", null, "v_snippet_input" )
|
||||
])
|
||||
, "OK", "Cancel"
|
||||
, parseTags.bind( ae_tagInput )
|
||||
).show();
|
||||
};
|
||||
|
||||
var deleteTag = function (e)
|
||||
{
|
||||
var p = { tag: this.nodeValue, stage: this.parentNode };
|
||||
postData( tagCountUri, p, confirmDelete.bind( p ), serverFailed );
|
||||
e.stopPropagation();
|
||||
};
|
||||
|
||||
var confirmDelete = function (obj)
|
||||
{
|
||||
new MessageBox(
|
||||
"Delete Tag"
|
||||
, [
|
||||
Dand.wrapc("ae_blockswitch",
|
||||
[
|
||||
Dand.textNode( "Are you sure you want to delete " )
|
||||
, Dand.wrap( "span", null, "tag_active", Dand.textNode( this.tag ) )
|
||||
, Dand.textNode( " ?." )
|
||||
]
|
||||
)
|
||||
, obj.count > 0
|
||||
? Dand.wrape([
|
||||
Dand.textNode( "This will affect " )
|
||||
, Dand.wrap(
|
||||
"span", null, "ae_affected_count", Dand.textNode( obj.count )
|
||||
)
|
||||
, Dand.textNode(" article(s).")
|
||||
])
|
||||
: null
|
||||
]
|
||||
, "Delete", "No"
|
||||
, doDelete.bind(this)
|
||||
).show();
|
||||
};
|
||||
|
||||
var doDelete = function( confirmed )
|
||||
{
|
||||
if ( confirmed )
|
||||
{
|
||||
postData(
|
||||
a_conf.paths.set_tag
|
||||
, { tag: this.tag, del: 1 }
|
||||
, deleteSuccess.bind( this )
|
||||
, serverFailed
|
||||
);
|
||||
}
|
||||
};
|
||||
|
||||
var deleteSuccess = function(obj)
|
||||
{
|
||||
// Remove element
|
||||
this.stage.parentNode.removeChild(this.stage);
|
||||
// Delete reference
|
||||
delete tags[this.tag];
|
||||
};
|
||||
|
||||
var parseTags = function ()
|
||||
{
|
||||
// Filter invalid tags
|
||||
var ntags = this.value.trim().match(/[^\n]+/g), d, e;
|
||||
for (var i in ntags)
|
||||
{
|
||||
if(!tags[(i = ntags[i]).toLowerCase()])
|
||||
{
|
||||
tags[i] = Dand.wrap("span", null, "tag_active",
|
||||
[d = Dand.wrap("span", null, "ae_tag_delete", "\u00D7"), e = Dand.textNode(i)]
|
||||
);
|
||||
// Seperator
|
||||
ae_tags.appendChild(Dand.textNode(" "));
|
||||
ae_tags.appendChild(tags[i]);
|
||||
|
||||
tags[i].onclick = function() { toggleTag(this) }.bind(tags[i]);
|
||||
d.onclick = deleteTag.bind(e);
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
debug.Info("Tag exist: " + i);
|
||||
// Hightlight these tags
|
||||
tags[i.toLowerCase()].className = "tag_active";
|
||||
}
|
||||
}
|
||||
|
||||
};
|
||||
|
||||
var toggleTag = function (tag)
|
||||
{
|
||||
var isEnabled = tag.className == "tag_active" ? true : false;
|
||||
tag.className = isEnabled ? "ae_disabled" : "tag_active";
|
||||
};
|
||||
|
||||
var serverFailed = function (obj) { };
|
||||
|
||||
|
||||
|
||||
var ctag, ae_children = ae_tags.childNodes;
|
||||
for (var i in ae_children)
|
||||
{
|
||||
if((ctag = ae_children[i]).nodeType == 1)
|
||||
{
|
||||
tags[ctag.lastChild.nodeValue.toLowerCase()] = ctag;
|
||||
IDOMElement( ctag ).addEventListener( "Click", function() { toggleTag( this ); }.bind( ctag ) );
|
||||
// Bind the last child (x button) to firstChild (textNode: tagname)
|
||||
IDOMElement( ctag.firstChild ).addEventListener( "Click", deleteTag.bind( ctag.lastChild ) );
|
||||
}
|
||||
}
|
||||
|
||||
this.getTags = function ()
|
||||
{
|
||||
// Compile tag list
|
||||
var tlist = [];
|
||||
|
||||
// Return names
|
||||
for (var i in tags)
|
||||
{
|
||||
if(tags[i].className == "tag_active")
|
||||
tlist[tlist.length] = tags[i].lastChild.nodeValue;
|
||||
}
|
||||
|
||||
return tlist.join("\n");
|
||||
}
|
||||
|
||||
this.setTags = function (tagList)
|
||||
{
|
||||
// Disable all tags first
|
||||
for (var i in tags) tags[i].className = "ae_disabled";
|
||||
|
||||
// Set tags from tagList
|
||||
for (i in tagList)
|
||||
if (tagList[i]) tags[tagList[i].toLowerCase()].className = "tag_active";
|
||||
}
|
||||
|
||||
ae_document.invoke(this);
|
||||
}
|
||||
|
||||
Tag.prototype.getTags = function () { };
|
||||
Tag.prototype.setTags = function (tagList) { };
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Tag", Tag );
|
||||
|
||||
})();
|
241
botanjs/src/Astro/Blog/AstroEdit/Uploader.js
Normal file
241
botanjs/src/Astro/Blog/AstroEdit/Uploader.js
Normal file
@@ -0,0 +1,241 @@
|
||||
(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.EventKey} */
|
||||
var EventKey = __import( "System.utils.EventKey" );
|
||||
/** @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 {Astro.Blog.Config} */
|
||||
var Conf = __import( "Astro.Blog.Config" );
|
||||
/** @type {System.utils.Perf} */
|
||||
var Perf = __import( "System.utils.Perf" );
|
||||
|
||||
var postFile = __import( "System.Net.postFile" );
|
||||
|
||||
|
||||
var Uploader = function ( set_file_uri )
|
||||
{
|
||||
/** @type {_AstConf_.SiteFile} */
|
||||
var config = Conf.get( "SiteFile" );
|
||||
|
||||
// linkage
|
||||
var busy = false
|
||||
, placedFiles = []
|
||||
, currentFile
|
||||
|
||||
|
||||
// Prepare structure for dockpanel
|
||||
, ptext = Dand.id( "asl_ptext" )
|
||||
, pbar = Dand.id( "asl_pbar_fill" )
|
||||
, ppreview = Dand.id( "asl_preview" )
|
||||
, pfileName = Dand.id( "asl_fileName" )
|
||||
, instruction = Dand.id( "asl_instruction" )
|
||||
, p_status = Dand.id( "asl_u_head" )
|
||||
|
||||
, fileList = Dand.id( "asl_fileList" )
|
||||
, stage = Dand.id( "asl_uploader" )
|
||||
|
||||
|
||||
, uploadProgress = function(e)
|
||||
{
|
||||
var done = e.position || e.loaded
|
||||
, total = e.totalSize || e.total
|
||||
, percentage = String( Math.floor( done / total * 1000 )/10 ) + "%";
|
||||
|
||||
// Set progress
|
||||
ptext.innetText
|
||||
= ptext.textContent
|
||||
= pbar.style.width
|
||||
= percentage;
|
||||
}
|
||||
|
||||
, uploadComplete = function ( response )
|
||||
{
|
||||
try
|
||||
{
|
||||
var obj = JSON.parse( response );
|
||||
if(obj.status)
|
||||
{
|
||||
currentFile.setStatus( "ok", config.f_host + obj.destination );
|
||||
}
|
||||
else
|
||||
{
|
||||
currentFile.setStatus( "error", obj.message );
|
||||
}
|
||||
new ContextMenu( currentFile.stage, currentFile.menuKeys, "LMB", stage );
|
||||
}
|
||||
catch ( ex )
|
||||
{
|
||||
currentFile.setStatus( "error", ex.message );
|
||||
debug.Error( ex );
|
||||
}
|
||||
beginUpload();
|
||||
}
|
||||
|
||||
, beginUpload = function()
|
||||
{
|
||||
busy = true;
|
||||
if( placedFiles.length )
|
||||
{
|
||||
currentFile = placedFiles.pop();
|
||||
if( currentFile )
|
||||
{
|
||||
var file = currentFile.file;
|
||||
|
||||
pfileName.textContent = pfileName.innetText = file.name;
|
||||
|
||||
var fd = new FormData();
|
||||
fd.append( "uploadFile", file );
|
||||
postFile( set_file_uri, fd, { progress: uploadProgress, complete: uploadComplete } );
|
||||
|
||||
currentFile.setStatus("active");
|
||||
instruction.style.marginTop = "-80px";
|
||||
}
|
||||
else
|
||||
{
|
||||
// deleted file, skip it
|
||||
beginUpload();
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
busy = false;
|
||||
instruction.style.marginTop = "";
|
||||
}
|
||||
}
|
||||
|
||||
, clearFileList = function ()
|
||||
{
|
||||
while( fileList.hasChildNodes() )
|
||||
{
|
||||
fileList.removeChild( fileList.firstChild );
|
||||
}
|
||||
}
|
||||
|
||||
, retryUpload = function ()
|
||||
{
|
||||
this.setStatus("pending");
|
||||
placedFiles[placedFiles.length] = this;
|
||||
new ContextMenu( this.stage, this.menuKeys, "RMB", stage );
|
||||
if( !busy ) beginUpload();
|
||||
}
|
||||
|
||||
, removeItem = function ()
|
||||
{
|
||||
this.stage.style.marginTop = "-2em";
|
||||
this.stage.style.opacity = "0";
|
||||
|
||||
if( placedFiles.indexOf(this) != -1 )
|
||||
{
|
||||
delete placedFiles[placedFiles.indexOf(this)];
|
||||
}
|
||||
|
||||
Cycle.delay(function () {
|
||||
fileList.removeChild(this);
|
||||
}.bind(this.stage), 250);
|
||||
}
|
||||
;
|
||||
|
||||
fileList.style.paddingTop = String(p_status.clientHeight) + "px";
|
||||
|
||||
|
||||
var docDom = IDOMObject( document );
|
||||
// Drag/drop handlers
|
||||
docDom.addEventListener( "DragOver", function ( e )
|
||||
{
|
||||
e.preventDefault();
|
||||
this.className = "dragged_over";
|
||||
} );
|
||||
docDom.addEventListener( "DragEnd", function () { this.className = ""; } );
|
||||
docDom.addEventListener( "Drop", function ( e )
|
||||
{
|
||||
e.preventDefault();
|
||||
this.className = "";
|
||||
|
||||
// Push files
|
||||
var list = e.dataTransfer.files;
|
||||
for(var i in list)
|
||||
{
|
||||
if(list[i].type != undefined)
|
||||
{
|
||||
var fileItem = new ASLFileItem(list[i], {clear: clearFileList, remove: removeItem, retry: retryUpload});
|
||||
placedFiles[placedFiles.length] = fileItem;
|
||||
|
||||
fileList.appendChild(fileItem.stage);
|
||||
new ContextMenu(fileItem.stage, fileItem.menuKeys, "LMB", stage);
|
||||
}
|
||||
}
|
||||
|
||||
if(!busy) beginUpload();
|
||||
|
||||
return false;
|
||||
} );
|
||||
};
|
||||
|
||||
var ASLFileItem = function (file, callbacks)
|
||||
{
|
||||
var statusblob = Dand.wrap("span", null, "asl_uItemStat", "\u25CF")
|
||||
, msg
|
||||
, _items = [
|
||||
new EventKey("Remove this item", callbacks.remove.bind(this)) // Reserved for remove item
|
||||
, null // Reserved for retry/ Open link
|
||||
, null // Reserved for get Error message
|
||||
, new EventKey("Clear all", callbacks.clear)
|
||||
]
|
||||
|
||||
, popMessage = function ()
|
||||
{
|
||||
new MessageBox("Upload error", msg).show();
|
||||
}
|
||||
|
||||
, getFileLink = function ()
|
||||
{
|
||||
return msg;
|
||||
}
|
||||
;
|
||||
|
||||
this.stage = Dand.wrap( null, "asl_item" + Perf.uuid, "asl_uItem", [ statusblob, Dand.textNode(file.name) ] );
|
||||
this.file = file;
|
||||
this.menuKeys = _items;
|
||||
|
||||
this.setStatus = function (st, message)
|
||||
{
|
||||
msg = message;
|
||||
switch(st)
|
||||
{
|
||||
case "active":
|
||||
statusblob.style.color = "cornflowerblue";
|
||||
break;
|
||||
case "error":
|
||||
statusblob.style.color = "red";
|
||||
|
||||
_items[1] = new EventKey( "Retry", callbacks.retry.bind(this) );
|
||||
_items[2] = new EventKey( "Whats wrong ?", popMessage );
|
||||
|
||||
break;
|
||||
case "ok":
|
||||
statusblob.style.color = "greenyellow";
|
||||
|
||||
_items[1] = new EventKey( "Copy file link", getFileLink );
|
||||
|
||||
break;
|
||||
default:// pending
|
||||
delete _items[1];
|
||||
delete _items[2];
|
||||
statusblob.style.color = "";
|
||||
}
|
||||
|
||||
}
|
||||
};
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Uploader", Uploader );
|
||||
|
||||
})();
|
@@ -0,0 +1,110 @@
|
||||
(function ()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
|
||||
|
||||
var acquirelib = function(insertSnippet, snippetWrap, createContext, override)
|
||||
{
|
||||
var temp, i, j
|
||||
|
||||
, handler = function ()
|
||||
{
|
||||
// Input fields
|
||||
var input_text = Dand.wrap('input', null, "v_snippet_input_single", null, new IKey("type", "text"));
|
||||
|
||||
if (this._stage)
|
||||
{
|
||||
input_text.value = this._text;
|
||||
}
|
||||
|
||||
// Popup MessageBox
|
||||
new MessageBox(
|
||||
"Acquire library" + ( this._stage ? " (Edit)" : "" )
|
||||
, Dand.wrape([ Dand.wrapc( "v_instruction flsf", "Module" ) , input_text ])
|
||||
, "OK", "Cancel"
|
||||
, visualizer.bind({ text:input_text, stage: this._stage })
|
||||
).show();
|
||||
}
|
||||
|
||||
, visualizer = function (submitted, override)
|
||||
{
|
||||
var src = override ? override.value : this.text.value
|
||||
, stage = this.stage;
|
||||
|
||||
if (submitted && src)
|
||||
{
|
||||
// Shared clause
|
||||
|
||||
if (!stage)
|
||||
{
|
||||
if (!src) return;
|
||||
|
||||
|
||||
// Visualize component
|
||||
temp = Dand.wrap(
|
||||
'span'
|
||||
, null
|
||||
, "flsf"
|
||||
, "AcquireLib: " + src
|
||||
, [
|
||||
new DataKey( "value", src )
|
||||
, new IKey(
|
||||
"style", "background-color: #444; color: white; padding: 0.2em 0.5em;"
|
||||
)
|
||||
]
|
||||
);
|
||||
insertSnippet(j = snippetWrap("AcquireLib", temp, false, 'span'), Boolean(override));
|
||||
}
|
||||
else
|
||||
{
|
||||
IDOMElement(stage).setAttribute( new DataKey("value", src) );
|
||||
|
||||
stage.removeChild(stage.firstChild);
|
||||
stage.appendChild(Dand.textNode("AcquireLib: " + src));
|
||||
|
||||
// set temp back to stage
|
||||
temp = stage;
|
||||
}
|
||||
|
||||
i = {_text: src, _stage: temp};
|
||||
|
||||
// Set context menu
|
||||
createContext(i, j, handler);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
if (override)
|
||||
{
|
||||
visualizer(true, override);
|
||||
override = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var compile = function (stage)
|
||||
{
|
||||
var element = IDOMElement(stage);
|
||||
|
||||
return "[acquirelib]" + element.getDAttribute("value") + "[/acquirelib]";
|
||||
};
|
||||
|
||||
__static_method( acquirelib, "compile", compile );
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "AcquireLib", acquirelib );
|
||||
})();
|
191
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Code.js
Normal file
191
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Code.js
Normal file
@@ -0,0 +1,191 @@
|
||||
(function ()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
|
||||
var escapeStr = ns[ NS_INVOKE ]( "escapeStr" );
|
||||
|
||||
var code = function ( insertSnippet, snippetWrap, createContext, override )
|
||||
{
|
||||
var temp, i, j
|
||||
, codeLangs = IKey.quickDef(
|
||||
"Plain text" , "plain"
|
||||
, "AS3" , "as3"
|
||||
, "bash" , "bash"
|
||||
, "C#" , "c#"
|
||||
, "C/C++" , "c"
|
||||
, "CSS" , "css"
|
||||
, "php" , "php"
|
||||
, "Python" , "python"
|
||||
, "Perl" , "perl"
|
||||
, "Ruby" , "ruby"
|
||||
, "Html/Xml" , "html"
|
||||
, "Java" , "java"
|
||||
, "JavaScript" , "js"
|
||||
, "SQL" , "sql"
|
||||
)
|
||||
|
||||
// Private methods
|
||||
, compileListItems = function ()
|
||||
{
|
||||
var arr = [];
|
||||
for ( i in codeLangs )
|
||||
{
|
||||
arr[ arr.length ] = Dand.wrapne(
|
||||
"option"
|
||||
, codeLangs[i].keyName
|
||||
, new IKey( "value", codeLangs[i].keyValue )
|
||||
);
|
||||
}
|
||||
return arr;
|
||||
}
|
||||
|
||||
// Snippet Class structure: handler & visualizer
|
||||
, handler = function ()
|
||||
{
|
||||
// Input fields
|
||||
var v_snippetInput = Dand.wrap( "textarea", null, "v_snippet_input" )
|
||||
, v_codelang = Dand.wrap( "select", null, "v_select flsf", compileListItems() );
|
||||
|
||||
if ( this._stage )
|
||||
{
|
||||
if ( this._lang )
|
||||
{
|
||||
for ( i = 0; i < codeLangs.length; i ++ )
|
||||
{
|
||||
if ( codeLangs[i].keyValue == this._lang )
|
||||
{
|
||||
v_codelang.selectedIndex = i;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
v_snippetInput.value = this._content || "";
|
||||
}
|
||||
else
|
||||
{
|
||||
// Remember the last choice
|
||||
if ( typeof( this.pSnippeCodeChoice ) == "number" )
|
||||
v_codelang.selectedIndex = this.pSnippeCodeChoice;
|
||||
}
|
||||
|
||||
// Popup MessageBox
|
||||
new MessageBox(
|
||||
( this._stage ? "Edit" : "Insert" ) + " code snippet"
|
||||
, Dand.wrapc(
|
||||
"v_trimmer"
|
||||
, [
|
||||
Dand.wrapc( "v_instruction", v_codelang )
|
||||
, v_snippetInput
|
||||
]
|
||||
)
|
||||
, "OK", "Cancel"
|
||||
// Switcher
|
||||
, visualizer.bind({ code:v_snippetInput, lang: v_codelang, stage: this._stage })
|
||||
).show();
|
||||
}
|
||||
|
||||
|
||||
, visualizer = function ( submitted, override )
|
||||
{
|
||||
var lang, code
|
||||
, stage = this.stage;
|
||||
|
||||
if ( override )
|
||||
{
|
||||
lang = override.lang;
|
||||
code = override.value;
|
||||
}
|
||||
else
|
||||
{
|
||||
lang = this.lang[this.pSnippeCodeChoice = this.lang.selectedIndex].value;
|
||||
code = this.code.value;
|
||||
}
|
||||
|
||||
|
||||
if ( submitted && code )
|
||||
{
|
||||
if (!stage)
|
||||
{
|
||||
// Visualize component
|
||||
temp = Dand.wrapc(
|
||||
"v_box"
|
||||
, [
|
||||
Dand.wrapne( "pre", code )
|
||||
, Dand.wrapc( "v_description", "Script language: " + lang )
|
||||
]
|
||||
, [
|
||||
new DataKey( "value", code )
|
||||
, new DataKey( "lang", lang )
|
||||
]
|
||||
);
|
||||
insertSnippet( j = snippetWrap( "Code", temp ), Boolean( override ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
IDOMElement( stage ).setAttribute(
|
||||
[
|
||||
new DataKey( "value", code )
|
||||
, new DataKey( "lang", lang )
|
||||
]
|
||||
);
|
||||
|
||||
temp = stage.firstChild;
|
||||
temp.removeChild( temp.firstChild );
|
||||
stage.firstChild.appendChild( Dand.textNode( code ) );
|
||||
|
||||
temp = stage.lastChild;
|
||||
temp.removeChild( temp.firstChild );
|
||||
temp.appendChild( Dand.textNode( "Script language: " + lang ) );
|
||||
|
||||
temp = stage;
|
||||
|
||||
}
|
||||
|
||||
i = { _lang: lang, _content: code, _stage: temp };
|
||||
|
||||
// Set context menu
|
||||
createContext( i, j, handler );
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
if ( override )
|
||||
{
|
||||
visualizer( true, override );
|
||||
override = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var compile = function ( stage )
|
||||
{
|
||||
// [code lang=\"" + lang + "\"]" + code + "[/code]"
|
||||
var element = IDOMElement( stage )
|
||||
, lang = element.getDAttribute( "lang" );
|
||||
|
||||
return "[code"
|
||||
+ (lang ? (" lang=\"" + lang + "\"") : "") + "]"
|
||||
+ escapeStr( element.getDAttribute( "value" ) )
|
||||
+ "[/code]"
|
||||
;
|
||||
};
|
||||
|
||||
__static_method( code, "compile", compile );
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Code", code );
|
||||
})();
|
107
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Html.js
Normal file
107
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Html.js
Normal file
@@ -0,0 +1,107 @@
|
||||
(function ()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
|
||||
var escapeStr = ns[ NS_INVOKE ]( "escapeStr" );
|
||||
|
||||
var html = function (insertSnippet, snippetWrap, createContext, override)
|
||||
{
|
||||
var temp, i, j
|
||||
|
||||
, handler = function ()
|
||||
{
|
||||
// Input fields
|
||||
var v_snippetInput = Dand.wrap( "textarea", null, "v_snippet_input" );
|
||||
|
||||
if ( this._stage )
|
||||
{
|
||||
v_snippetInput.value = this._code;
|
||||
}
|
||||
|
||||
// Popup MessageBox
|
||||
new MessageBox(
|
||||
"Insert Html snippet"
|
||||
, v_snippetInput
|
||||
, "OK", "Cancel"
|
||||
, visualizer.bind({ code: v_snippetInput, stage: this._stage })
|
||||
).show();
|
||||
}
|
||||
|
||||
, visualizer = function (submitted, override)
|
||||
{
|
||||
|
||||
var code, stage = this.stage;
|
||||
|
||||
code = override ? override.value : this.code.value;
|
||||
|
||||
if (submitted && code)
|
||||
{
|
||||
if (!stage)
|
||||
{
|
||||
// Visualize component
|
||||
temp = Dand.wrapc(
|
||||
"v_box"
|
||||
, [
|
||||
Dand.wrapne( "pre", code )
|
||||
, Dand.wrapc( "v_description", "Raw Html Codes" )
|
||||
]
|
||||
, [
|
||||
new DataKey( "value", code )
|
||||
, new IKey( "style", "max-height: 150px;" )
|
||||
]
|
||||
);
|
||||
insertSnippet(j = snippetWrap("Html", temp), Boolean(override));
|
||||
}
|
||||
else
|
||||
{
|
||||
IDOMElement( stage ).setAttribute(new DataKey( "value", code ));
|
||||
|
||||
temp = stage.firstChild;
|
||||
temp.removeChild(temp.firstChild);
|
||||
stage.firstChild.appendChild(Dand.textNode( code ));
|
||||
|
||||
temp = stage;
|
||||
|
||||
}
|
||||
|
||||
i = { _code: code, _stage: temp };
|
||||
|
||||
// Set context menu
|
||||
createContext( i, j, handler );
|
||||
}
|
||||
};
|
||||
|
||||
if ( override )
|
||||
{
|
||||
visualizer( true, override );
|
||||
override = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
return true;
|
||||
|
||||
};
|
||||
|
||||
var compile = function (stage)
|
||||
{
|
||||
// [html][/html]
|
||||
return "[html]" + escapeStr( IDOMElement(stage).getDAttribute("value") ) + "[/html]";
|
||||
};
|
||||
|
||||
__static_method( html, "compile", compile );
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Html", html );
|
||||
})();
|
157
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Image.js
Normal file
157
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Image.js
Normal file
@@ -0,0 +1,157 @@
|
||||
(function ()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
|
||||
var image = function( insertSnippet, snippetWrap, createContext, override )
|
||||
{
|
||||
var temp, i, j
|
||||
|
||||
, handler = function ()
|
||||
{
|
||||
// Input fields
|
||||
var input_url = Dand.wrap(
|
||||
"input", null, "v_snippet_input_single", null, new IKey( "type", "text" )
|
||||
)
|
||||
, input_a = Dand.wrap(
|
||||
"input", null, "v_snippet_input_single", null, new IKey( "type", "text" )
|
||||
);
|
||||
|
||||
if (this._stage)
|
||||
{
|
||||
input_url.value = this._url;
|
||||
input_a.value = this._href;
|
||||
}
|
||||
|
||||
// Popup MessageBox
|
||||
new MessageBox(
|
||||
( this._stage ? "Edit" : "Insert" ) + " image snippet",
|
||||
Dand.wrape([
|
||||
Dand.wrapc( "v_instruction flsf", "Link to the image:" )
|
||||
, input_url
|
||||
, Dand.wrapc( "v_instruction flsf", "Ancohr link(optional):" )
|
||||
, input_a
|
||||
]
|
||||
)
|
||||
, "OK", "Cancel"
|
||||
, visualizer.bind({ url:input_url, href:input_a, stage: this._stage })
|
||||
).show();
|
||||
}
|
||||
|
||||
, visualizer = function ( submitted, override )
|
||||
{
|
||||
var src, href
|
||||
, stage = this.stage;
|
||||
|
||||
if ( override )
|
||||
{
|
||||
src = override.value;
|
||||
href = override.href;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = this.url.value;
|
||||
href = this.href.value;
|
||||
}
|
||||
|
||||
if ( submitted && src )
|
||||
{
|
||||
|
||||
// Shared clause
|
||||
i = Dand.textNode(href ? ("link to: " + href): "No link");
|
||||
|
||||
if ( !stage )
|
||||
{
|
||||
if ( !src ) return;
|
||||
|
||||
|
||||
// Visualize component
|
||||
temp = Dand.wrapc(
|
||||
"v_box"
|
||||
, [
|
||||
Dand.wrapna(
|
||||
"img"
|
||||
, [
|
||||
new IKey("src", src)
|
||||
, new IKey("style", "max-width: 100%")
|
||||
]
|
||||
)
|
||||
// caption
|
||||
, Dand.wrapc( "v_description", i )
|
||||
]
|
||||
, [
|
||||
new DataKey("value", src)
|
||||
, new DataKey("href", href)
|
||||
]
|
||||
);
|
||||
insertSnippet( j = snippetWrap( "Image", temp ), Boolean( override ) );
|
||||
}
|
||||
else
|
||||
{
|
||||
IDOMElement( stage ).setAttribute
|
||||
([
|
||||
new DataKey( "value", src )
|
||||
, new DataKey( "href", href )
|
||||
]);
|
||||
|
||||
stage.firstChild.setAttribute("src", src);
|
||||
|
||||
temp = stage.lastChild;
|
||||
temp.removeChild(temp.firstChild);
|
||||
temp.appendChild(i);
|
||||
|
||||
// set temp back to stage
|
||||
temp = stage;
|
||||
}
|
||||
|
||||
i = { _url: src, _href: href, _stage: temp };
|
||||
|
||||
// Set context menu
|
||||
createContext( i, j, handler );
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
if ( override )
|
||||
{
|
||||
visualizer( true, override );
|
||||
override = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var compile = function ( stage )
|
||||
{
|
||||
// [img href=\"" + this.href.value + "\"]" + this.url.value + "[/img]
|
||||
var element = IDOMElement( stage )
|
||||
, href = element.getDAttribute( "href" );
|
||||
|
||||
return "[img"
|
||||
+ ( href ? (" href=\"" + href + "\"") : "" )
|
||||
+ "]"
|
||||
+ element.getDAttribute( "value" ) + "[/img]"
|
||||
;
|
||||
};
|
||||
|
||||
// Alias
|
||||
var alias = "img";
|
||||
|
||||
__static_method( image, "compile", compile );
|
||||
__const( image, "alias", alias );
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Image", image );
|
||||
})();
|
131
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Link.js
Normal file
131
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Link.js
Normal file
@@ -0,0 +1,131 @@
|
||||
(function ()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
|
||||
var link = function(insertSnippet, snippetWrap, createContext, override)
|
||||
{
|
||||
var temp, i, j
|
||||
|
||||
, handler = function ()
|
||||
{
|
||||
// Input fields
|
||||
var input_text = Dand.wrap('input', null, "v_snippet_input_single", null, new IKey("type", "text"))
|
||||
, input_a = Dand.wrap('input', null, "v_snippet_input_single", null, new IKey("type", "text"));
|
||||
|
||||
if (this._stage)
|
||||
{
|
||||
input_text.value = this._text;
|
||||
input_a.value = this._href;
|
||||
}
|
||||
|
||||
// Popup MessageBox
|
||||
new MessageBox(
|
||||
(this._stage ? "Edit" : "Insert") + " link",
|
||||
Dand.wrape([
|
||||
Dand.wrapc("v_instruction flsf", "Text")
|
||||
, input_text
|
||||
, Dand.wrapc("v_instruction flsf", "Link to:")
|
||||
, input_a
|
||||
]
|
||||
)
|
||||
, "OK", "Cancel", visualizer.bind({text:input_text, href:input_a, stage: this._stage})).show();
|
||||
}
|
||||
|
||||
, visualizer = function (submitted, override)
|
||||
{
|
||||
var src, href
|
||||
, stage = this.stage;
|
||||
|
||||
if (override)
|
||||
{
|
||||
src = override.value;
|
||||
href = override.href;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = this.text.value;
|
||||
href = this.href.value;
|
||||
}
|
||||
|
||||
if (submitted && src && href)
|
||||
{
|
||||
|
||||
// Shared clause
|
||||
|
||||
if (!stage)
|
||||
{
|
||||
if (!src) return;
|
||||
|
||||
|
||||
// Visualize component
|
||||
temp =
|
||||
Dand.wrapne('span', src
|
||||
, [
|
||||
new DataKey("value", src)
|
||||
, new DataKey("href", href)
|
||||
]
|
||||
);
|
||||
insertSnippet(j = snippetWrap("Link", temp, false, 'span'), Boolean(override));
|
||||
}
|
||||
else
|
||||
{
|
||||
IDOMElement(stage).setAttribute
|
||||
(
|
||||
[
|
||||
new DataKey("value", src)
|
||||
, new DataKey("href", href)
|
||||
]
|
||||
);
|
||||
|
||||
stage.removeChild(stage.firstChild);
|
||||
stage.appendChild(Dand.textNode(src));
|
||||
|
||||
// set temp back to stage
|
||||
temp = stage;
|
||||
}
|
||||
|
||||
i = {_text: src, _href: href, _stage: temp};
|
||||
|
||||
// Set context menu
|
||||
createContext(i, j, handler);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
if (override)
|
||||
{
|
||||
visualizer(true, override);
|
||||
override = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var compile = function (stage)
|
||||
{
|
||||
// [link href=\"" + this.href.value + "\"]" + text + "[/link]
|
||||
var element = IDOMElement(stage)
|
||||
, href = element.getDAttribute("href");
|
||||
|
||||
return "[link" + (href ? (" href=\"" + href + "\"") : "") + "]" + element.getDAttribute("value") + "[/link]";
|
||||
};
|
||||
|
||||
|
||||
__static_method( link, "compile", compile );
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Link", link );
|
||||
})();
|
174
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/SiteFile.js
Normal file
174
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/SiteFile.js
Normal file
@@ -0,0 +1,174 @@
|
||||
(function ()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
/** @type {Astro.Blog.Config} */
|
||||
var Config = __import( "Astro.Blog.Config" );
|
||||
/** @type {System.utils.Perf} */
|
||||
var Perf = __import( "System.utils.Perf" );
|
||||
/** @type {Astro.utils.Date} */
|
||||
var XDate = __import( "Astro.utils.Date" );
|
||||
|
||||
|
||||
var escapeStr = ns[ NS_INVOKE ]( "escapeStr" );
|
||||
|
||||
var getData = __import( "System.Net.getData" );
|
||||
|
||||
/** @type {_AstConf_.SiteFile} */
|
||||
var config = null;
|
||||
|
||||
var sitefile = function ( insertSnippet, snippetWrap, createContext, override )
|
||||
{
|
||||
config = Config.get( "SiteFile" );
|
||||
if( !config ) throw new Error( "config is not defined" );
|
||||
|
||||
var temp, i, j
|
||||
|
||||
, handler = function ()
|
||||
{
|
||||
// Input fields
|
||||
var v_snippetInput = Dand.wrap("input", null, "v_snippet_input_single", null, new IKey("type", "text"));
|
||||
|
||||
// Popup MessageBox
|
||||
new MessageBox("Insert site file", v_snippetInput, "OK", "Cancel", visualizer.bind({code: v_snippetInput})).show();
|
||||
}
|
||||
|
||||
, __applyData = function (e)
|
||||
{
|
||||
var finfo = JSON.parse(e).file, s, m, l
|
||||
, content = this.stage.firstChild
|
||||
, desc = this.stage.lastChild
|
||||
, _hash = this.hash;
|
||||
|
||||
switch ( finfo.type )
|
||||
{
|
||||
case "image":
|
||||
|
||||
this.stage.removeChild(content);
|
||||
// Default size is large
|
||||
var _image = Dand.wrapna("img", new IKey("src", config.path.image.large + _hash + ".jpg"))
|
||||
, _stage = IDOMElement(this.stage)
|
||||
, keys = [ new IKey( "type", "radio" ), new IKey( "name", "size_grp" + Perf.uuid ) ]
|
||||
, sid
|
||||
, selectionChanged = function ()
|
||||
{
|
||||
_stage.setAttribute(new DataKey("size", this.size));
|
||||
//// Handles the size selection
|
||||
switch(this.size)
|
||||
{
|
||||
case "small":
|
||||
_image.setAttribute("src", config.path.image.small + _hash + ".jpg");
|
||||
break;
|
||||
case "medium":
|
||||
_image.setAttribute("src", config.path.image.medium + _hash + ".jpg");
|
||||
break;
|
||||
case "large":
|
||||
_image.setAttribute("src", config.path.image.large + _hash + ".jpg");
|
||||
break;
|
||||
}
|
||||
};
|
||||
|
||||
this.stage.insertBefore(_image, desc);
|
||||
|
||||
desc.removeChild(desc.firstChild);
|
||||
desc.appendChild(
|
||||
Dand.wrape([
|
||||
Dand.textNode("Size: ")
|
||||
, s = Dand.wrapna("input", keys.concat( new IKey("id", sid = "size_" + Perf.uuid) ))
|
||||
, Dand.wrapne("label", "small", new IKey("for", sid))
|
||||
, m = Dand.wrapna("input", keys.concat( new IKey("id", sid = "size_" + Perf.uuid) ))
|
||||
, Dand.wrapne("label", "medium", new IKey("for", sid))
|
||||
, l = Dand.wrapna("input", keys.concat( new IKey("checked", "1"), new IKey("id", sid = "size_" + Perf.uuid) ))
|
||||
, Dand.wrapne("label", "large (default)", new IKey("for", sid))
|
||||
])
|
||||
);
|
||||
|
||||
// ad handlers to handles size change event
|
||||
IDOMElement(s).addEventListener("Change", selectionChanged.bind({size: "small"}));
|
||||
IDOMElement(m).addEventListener("Change", selectionChanged.bind({size: "medium"}));
|
||||
IDOMElement(l).addEventListener("Change", selectionChanged.bind({size: "large"}));
|
||||
break;
|
||||
case "audio":
|
||||
// TODO
|
||||
break;
|
||||
default:
|
||||
content.firstChild.nodeValue = "Regular file: " + finfo.name;
|
||||
content.style.paddingBottom = "2em";
|
||||
content.appendChild( Dand.wrap( "br" ) );
|
||||
content.appendChild( Dand.textNode( "Date: " + XDate.pretty( new Date( finfo.date_created ), true ) ) );
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
, loadFailed = function (e) { }
|
||||
|
||||
, visualizer = function (submitted, override)
|
||||
{
|
||||
|
||||
var hash = override ? override.value : this.code.value
|
||||
, _obj = {file: hash};
|
||||
|
||||
if ( submitted && hash )
|
||||
{
|
||||
// Visualize component
|
||||
|
||||
temp = Dand.wrapc("v_box"
|
||||
, [
|
||||
Dand.wrape("Getting information from Server ...")
|
||||
, Dand.wrapc("v_description", "Site file (hash): " + hash)
|
||||
]
|
||||
, [
|
||||
new DataKey("value", hash)
|
||||
, new DataKey("size", "large")
|
||||
, new IKey("style", "max-height: 150px;")
|
||||
]
|
||||
);
|
||||
|
||||
// Get data from site library
|
||||
getData( config.path.info + hash, __applyData.bind({stage: temp, hash: hash}), loadFailed );
|
||||
|
||||
insertSnippet(j = snippetWrap("SiteFile", temp), Boolean(override));
|
||||
|
||||
// Set context menu
|
||||
createContext(null, j);
|
||||
}
|
||||
};
|
||||
|
||||
if (override)
|
||||
{
|
||||
visualizer(true, override);
|
||||
override = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
return true;
|
||||
|
||||
};
|
||||
|
||||
var compile = function ( stage )
|
||||
{
|
||||
stage = IDOMElement( stage );
|
||||
// [html][/html]
|
||||
return "[sitefile"
|
||||
+ " size=\"" + stage.getDAttribute( "size" ) + "\"" + "]"
|
||||
+ escapeStr( stage.getDAttribute( "value" ) )
|
||||
+ "[/sitefile]";
|
||||
};
|
||||
|
||||
__static_method( sitefile, "compile", compile );
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "SiteFile", sitefile );
|
||||
|
||||
})();
|
146
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Sound.js
Normal file
146
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Sound.js
Normal file
@@ -0,0 +1,146 @@
|
||||
(function ()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
|
||||
var compileProp = ns[ NS_INVOKE ]( "compileProp" );
|
||||
|
||||
var sound = function (insertSnippet, snippetWrap, createContext, override)
|
||||
{
|
||||
var temp, i, j
|
||||
, defaultArt = "http://file.astropenguin.net/blog/layout-images/disc_s.png"
|
||||
, handler = function ()
|
||||
{
|
||||
// Input fields
|
||||
var input_url = Dand.wrap('input', null, "v_snippet_input_single", null, new IKey("type", "text"))
|
||||
, input_albumArt = Dand.wrap('input', null, "v_snippet_input_single", null, new IKey("type", "text"))
|
||||
, input_lrc = Dand.wrap('input', null, "v_snippet_input_single", null, new IKey("type", "text"))
|
||||
;
|
||||
|
||||
if (this._stage)
|
||||
{
|
||||
input_url.value = this._url;
|
||||
input_albumArt.value = this._albumArt;
|
||||
input_lrc.value = this._lrc;
|
||||
}
|
||||
|
||||
new MessageBox(
|
||||
(this._stage ? "Edit" : "Insert") + " sound snippet"
|
||||
, Dand.wrape([
|
||||
Dand.wrapc("v_instruction flsf", "Link to sound:")
|
||||
, input_url
|
||||
|
||||
, Dand.wrapc("v_instruction flsf", "Link to album art(optional):")
|
||||
, input_albumArt
|
||||
|
||||
, Dand.wrapc("v_instruction flsf", "Link to lrc(optional):")
|
||||
, input_lrc
|
||||
]
|
||||
)
|
||||
, "OK", "Cancel", visualizer.bind({url:input_url, albumArt:input_albumArt, lrc:input_lrc, stage: this._stage})).show();
|
||||
}
|
||||
|
||||
, visualizer = function (submitted)
|
||||
{
|
||||
|
||||
var src, albumArt , lrc
|
||||
, stage = this.stage;
|
||||
|
||||
if (override)
|
||||
{
|
||||
src = override.url;
|
||||
albumArt = override.albumArt;
|
||||
lrc = override.lrc;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = this.url.value;
|
||||
albumArt = this.albumArt.value;
|
||||
lrc = this.lrc.value;
|
||||
}
|
||||
|
||||
if (submitted && src)
|
||||
{
|
||||
|
||||
if (!stage)
|
||||
{
|
||||
// Visualize component
|
||||
temp = Dand.wrapc('v_box'
|
||||
, [
|
||||
Dand.wrape(null, new IKey
|
||||
(
|
||||
"style", "height: 75px; background-size: auto 75px; background-repeat: no-repeat;"
|
||||
+ "background-image: url(" + (albumArt ? albumArt : defaultArt) + ")"
|
||||
)
|
||||
)
|
||||
, Dand.wrapc('v_description', "Sound snippet")
|
||||
]
|
||||
, [
|
||||
new DataKey("value", "")
|
||||
, new DataKey("url", src)
|
||||
, new DataKey("albumArt", albumArt)
|
||||
, new DataKey("lrc", lrc)
|
||||
]
|
||||
);
|
||||
insertSnippet(j = snippetWrap("Sound", temp), Boolean(override));
|
||||
}
|
||||
else
|
||||
{
|
||||
// Edit properties
|
||||
stage.firstChild.style.backgroundImage = "url(" + (albumArt ? albumArt : defaultArt) + ")" ;
|
||||
|
||||
IDOMElement(stage).setAttribute
|
||||
(
|
||||
[
|
||||
new DataKey("url", src)
|
||||
, new DataKey("albumArt", albumArt)
|
||||
, new DataKey("lrc", lrc)
|
||||
]
|
||||
);
|
||||
|
||||
}
|
||||
|
||||
i = {_url: src, _albumArt: albumArt, _lrc: lrc, _stage: temp};
|
||||
|
||||
// Set context menu
|
||||
createContext(i, j, handler);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
if (override)
|
||||
{
|
||||
visualizer(true, override);
|
||||
override = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var compile = function (stage)
|
||||
{
|
||||
// [sound url="" albumArt="" lrc="" ][/sound]");
|
||||
var element = IDOMElement(stage)
|
||||
, props = ["url", "albumArt", "lrc"];
|
||||
|
||||
return "[sound" + compileProp( element, props ) + "][/sound]";
|
||||
};
|
||||
|
||||
|
||||
__static_method( sound, "compile", compile );
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Sound", sound );
|
||||
})();
|
154
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Spoiler.js
Normal file
154
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Spoiler.js
Normal file
@@ -0,0 +1,154 @@
|
||||
(function ()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
|
||||
var compileProp = ns[ NS_INVOKE ]( "compileProp" );
|
||||
|
||||
var spoiler = function(insertSnippet, snippetWrap, createContext, override)
|
||||
{
|
||||
var temp, i, j
|
||||
|
||||
, handler = function ()
|
||||
{
|
||||
// Input fields
|
||||
var v_snippetInput = Dand.wrap('textarea', null, "v_snippet_input")
|
||||
, input_title = Dand.wrap('input', null, "v_snippet_input_single", null, new IKey("type", "text"))
|
||||
, input_expanded = Dand.wrapna('input', new IKey("type", "checkbox"))
|
||||
|
||||
if (this._stage)
|
||||
{
|
||||
v_snippetInput.value = this._content;
|
||||
input_title.value = this._title;
|
||||
input_expanded.checked = (this._expanded == "on");
|
||||
}
|
||||
|
||||
// Popup MessageBox
|
||||
new MessageBox("Insert spoiler content"
|
||||
, Dand.wrape([
|
||||
Dand.wrapc("v_instruction flsf", "Title")
|
||||
, input_title
|
||||
|
||||
, Dand.wrapc("v_instruction flsf", "Content")
|
||||
, v_snippetInput
|
||||
|
||||
, Dand.wrape([ input_expanded, Dand.textNode( "Expanded" ) ])
|
||||
]
|
||||
)
|
||||
, "OK", "Cancel", visualizer.bind({title: input_title, content:v_snippetInput, expanded: input_expanded, stage: this._stage})).show();
|
||||
}
|
||||
|
||||
, visualizer = function (submitted, override)
|
||||
{
|
||||
var content, title, expanded
|
||||
, stage = this.stage;
|
||||
|
||||
if (override)
|
||||
{
|
||||
content = override.value;
|
||||
title = override.title;
|
||||
expanded = override.expanded ? "on" : "";
|
||||
}
|
||||
else
|
||||
{
|
||||
content = this.content.value;
|
||||
title = this.title.value;
|
||||
expanded = this.expanded.checked ? "on" : "";
|
||||
}
|
||||
|
||||
if (submitted && content)
|
||||
{
|
||||
// Shared Clause
|
||||
i = Dand.textNode(title || "Spoiler");
|
||||
if (!stage)
|
||||
{
|
||||
if (!content) return;
|
||||
|
||||
// Visualize component
|
||||
temp = Dand.wrapc('v_box',
|
||||
[
|
||||
// caption
|
||||
Dand.wrapc('v_caption', i)
|
||||
, Dand.textNode(content)
|
||||
],
|
||||
[
|
||||
new DataKey("value", content)
|
||||
, new DataKey("title", title)
|
||||
, new DataKey("expanded", expanded)
|
||||
]
|
||||
);
|
||||
insertSnippet(j = snippetWrap("Spoiler", temp), Boolean(override));
|
||||
}
|
||||
else
|
||||
{
|
||||
IDOMElement(stage).setAttribute
|
||||
(
|
||||
[
|
||||
new DataKey("value", content)
|
||||
, new DataKey("title", title)
|
||||
, new DataKey("expanded", expanded)
|
||||
]
|
||||
);
|
||||
|
||||
temp = stage.firstChild;
|
||||
temp.removeChild(temp.firstChild);
|
||||
temp.appendChild(i);
|
||||
|
||||
stage.removeChild(stage.lastChild);
|
||||
stage.appendChild(Dand.textNode(content));
|
||||
|
||||
// set temp back to stage
|
||||
temp = stage;
|
||||
}
|
||||
|
||||
i = {
|
||||
_title: title
|
||||
, _content: content
|
||||
, _expanded: expanded || "off"
|
||||
, _stage: temp
|
||||
};
|
||||
|
||||
// Set context menu
|
||||
createContext(i, j, handler);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
if (override)
|
||||
{
|
||||
visualizer(true, override);
|
||||
override = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var compile = function ( stage )
|
||||
{
|
||||
var element = IDOMElement( stage )
|
||||
, props = ["title", "expanded"];
|
||||
|
||||
return "[spoiler"
|
||||
+ compileProp( element, props )
|
||||
+ "]"
|
||||
+ element.getDAttribute( "value" )
|
||||
+ "[/spoiler]";
|
||||
};
|
||||
|
||||
__static_method( spoiler, "compile", compile );
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Spoiler", spoiler );
|
||||
})();
|
214
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Swf.js
Normal file
214
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Swf.js
Normal file
@@ -0,0 +1,214 @@
|
||||
(function ()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
|
||||
var compileProp = ns[ NS_INVOKE ]( "compileProp" );
|
||||
|
||||
var swf = function (insertSnippet, snippetWrap, createContext, override)
|
||||
{
|
||||
var
|
||||
temp, i, j
|
||||
|
||||
// Pending
|
||||
, defaultArt = ""
|
||||
|
||||
, handler = function ()
|
||||
{
|
||||
// Input fields
|
||||
var input_w = Dand.wrapna('input', new IKey("type", "number"))
|
||||
, input_h = Dand.wrapna('input', new IKey("type", "number"))
|
||||
, input_title = Dand.wrap('input', null, "v_snippet_input_single", null, [new IKey("type", "text"), new IKey("placeHolder", "optional")] )
|
||||
, input_desc = Dand.wrap('input', null, "v_snippet_input_single", null, [new IKey("type", "text"), new IKey("placeHolder", "optional")] )
|
||||
, input_api = Dand.wrapna('input', new IKey("type", "checkbox"))
|
||||
, input_preview = Dand.wrap('input', null, "v_snippet_input_single", null, [new IKey("type", "text"), new IKey("placeHolder", "optional")] )
|
||||
, input_src = Dand.wrap('input', null, "v_snippet_input_single", null, new IKey("type", "text"))
|
||||
, stage = this._stage;
|
||||
|
||||
|
||||
if (stage)
|
||||
{
|
||||
input_src.value = this._src;
|
||||
input_w.value = this._width;
|
||||
input_h.value = this._height;
|
||||
input_title.value = this._title;
|
||||
input_desc.value = this._desc;
|
||||
input_preview.value = this._preview;
|
||||
input_api.checked = (this._extAPI == "on");
|
||||
}
|
||||
|
||||
new MessageBox(
|
||||
"Insert swf object",
|
||||
Dand.wrape([
|
||||
Dand.wrape([Dand.textNode("Dimensions: "), input_w, Dand.textNode("\u00D7"), input_h, Dand.textNode("px")])
|
||||
|
||||
, Dand.wrapc("v_instruction flsf", "Title:")
|
||||
, input_title
|
||||
|
||||
, Dand.wrapc("v_instruction flsf", "Description:")
|
||||
, input_desc
|
||||
|
||||
, Dand.wrapc("v_instruction flsf", "Preview image:")
|
||||
, input_preview
|
||||
|
||||
, Dand.wrapc("v_instruction flsf", "Link to swf:")
|
||||
, input_src
|
||||
|
||||
, Dand.wrape([ input_api, Dand.textNode("Use external API") ] )
|
||||
]
|
||||
)
|
||||
, "OK", "Cancel", visualizer.bind({src:input_src, width:input_w, height:input_h, title: input_title, desc: input_desc, extAPI: input_api, preview: input_preview, stage: this._stage})).show();
|
||||
}
|
||||
|
||||
, visualizer = function (submitted, override)
|
||||
{
|
||||
var src, width, height, title, desc, preview, extAPI
|
||||
, stage = this.stage;
|
||||
|
||||
if (override)
|
||||
{
|
||||
src = override.value;
|
||||
width = override.width;
|
||||
height = override.height;
|
||||
title = override.title;
|
||||
desc = override.desc;
|
||||
preview = override.preview;
|
||||
extAPI = override.useExtAPI;
|
||||
}
|
||||
else
|
||||
{
|
||||
src = this.src.value;
|
||||
width = this.width.value;
|
||||
height = this.height.value;
|
||||
title = this.title.value;
|
||||
desc = this.desc.value;
|
||||
preview = this.preview.value;
|
||||
extAPI = this.extAPI.checked ? "on" : "";
|
||||
}
|
||||
|
||||
if (submitted && width && height && src)
|
||||
{
|
||||
|
||||
if (!stage)
|
||||
{
|
||||
// Visualize component
|
||||
|
||||
temp = Dand.wrapc('v_box'
|
||||
, Dand.wrapc('v_description'
|
||||
, [
|
||||
Dand.wrap('span', null, 'fls', title)
|
||||
, Dand.textNode(" ")
|
||||
, Dand.wrap('span', null, 'v_caption_desc flsf', desc)
|
||||
]
|
||||
, new IKey('style', 'font-size: 2em')
|
||||
)
|
||||
, [
|
||||
new DataKey("value", src)
|
||||
, new DataKey("width", width)
|
||||
, new DataKey("height", height)
|
||||
, new DataKey("title", title)
|
||||
, new DataKey("desc", desc)
|
||||
, new DataKey("preview", preview)
|
||||
, new DataKey("useExtAPI", extAPI)
|
||||
|
||||
, new IKey
|
||||
(
|
||||
"style"
|
||||
, "background-position: center; background-repeat: no-repeat; "
|
||||
+ "width: " + width +"px; height: " + height + "px; "
|
||||
+ "background-image: url(" + (preview ? preview : defaultArt) + ")"
|
||||
)
|
||||
]
|
||||
);
|
||||
insertSnippet(j = snippetWrap("Swf", temp), Boolean(override));
|
||||
}
|
||||
else
|
||||
{
|
||||
IDOMElement(stage).setAttribute
|
||||
(
|
||||
[
|
||||
new DataKey("value", src)
|
||||
, new DataKey("width", width)
|
||||
, new DataKey("height", height)
|
||||
, new DataKey("title", title)
|
||||
, new DataKey("desc", desc)
|
||||
, new DataKey("preview", preview)
|
||||
, new DataKey("useExtAPI", extAPI)
|
||||
]
|
||||
);
|
||||
|
||||
stage.style.width = width + "px";
|
||||
stage.style.height = height + "px";
|
||||
stage.style.backgroundImage = "url(" + (preview ? preview : defaultArt) + ")";
|
||||
|
||||
// Title
|
||||
temp = stage.firstChild.firstChild;
|
||||
temp.removeChild(temp.firstChild);
|
||||
temp.appendChild(Dand.textNode(title));
|
||||
|
||||
// Desc
|
||||
temp = stage.firstChild.lastChild;
|
||||
temp.removeChild(temp.firstChild);
|
||||
temp.appendChild(Dand.textNode(desc));
|
||||
|
||||
temp = stage;
|
||||
}
|
||||
|
||||
|
||||
i = {
|
||||
_src: src
|
||||
, _width: width
|
||||
, _height: height
|
||||
, _title: title
|
||||
, _desc: desc
|
||||
, _preview: preview
|
||||
, _extAPI: extAPI || "off"
|
||||
, _stage: temp
|
||||
};
|
||||
|
||||
// Set context menu
|
||||
createContext(i, j, handler);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
if (override)
|
||||
{
|
||||
visualizer(true, override);
|
||||
override = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var compile = function (stage)
|
||||
{
|
||||
// [swf width="" height="" title="" desc="" preview="" useExtAPI="" ]src[/swf];
|
||||
var element = IDOMElement(stage)
|
||||
, props = ["width", "height", "title", "desc", "preview", "useExtAPI"];
|
||||
|
||||
return "[swf"
|
||||
+ compileProp( element, props )
|
||||
+ "]"
|
||||
+ element.getDAttribute("value")
|
||||
+ "[/swf]"
|
||||
;
|
||||
};
|
||||
|
||||
__static_method( swf, "compile", compile );
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Swf", swf );
|
||||
})();
|
137
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Video.js
Normal file
137
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/Video.js
Normal file
@@ -0,0 +1,137 @@
|
||||
(function ()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
|
||||
var video = function (insertSnippet, snippetWrap, createContext, override)
|
||||
{
|
||||
var temp, i, j
|
||||
|
||||
, getVimeoThumbnail = function (vtag)
|
||||
{
|
||||
getData("http://vimeo.com/api/oembed.json?url=http%3A//vimeo.com/" + vtag.getAttribute("data-value"), setThumbnail.bind(vtag), noThumb.bind(vtag));
|
||||
}
|
||||
|
||||
, noThumb = function ()
|
||||
{
|
||||
|
||||
}
|
||||
|
||||
, setThumbnail = function (str)
|
||||
{
|
||||
this.style.background = "black url(" + JSON.parse(str)["thumbnail_url"] + ") center center no-repeat";
|
||||
|
||||
}
|
||||
|
||||
, handler = function ()
|
||||
{
|
||||
// Input fields
|
||||
var input_url = Dand.wrap('input', null, "v_snippet_input_single", null, new IKey("type", "text"));
|
||||
|
||||
// Popup MessageBox
|
||||
new MessageBox("Insert video snippet"
|
||||
, Dand.wrape([ Dand.wrapc("v_instruction flsf", "Paste a vimeo/Youtube link below:"), input_url ])
|
||||
, "OK", "Cancel", visualizer.bind(input_url)
|
||||
).show();
|
||||
}
|
||||
|
||||
, visualizer = function (submitted, override)
|
||||
{
|
||||
var t, v;
|
||||
|
||||
if (override)
|
||||
{
|
||||
v = override.value;
|
||||
i = override.type;
|
||||
}
|
||||
else
|
||||
{
|
||||
t = this.value;
|
||||
// Match youtube links
|
||||
v = t.match(/\/\/(www\.)?youtube\.com\/watch\?.*?v=([^\&\?\/\#]+)/) || t.match(/\/\/(www\.)?youtube\.com\/embed\/([^\&\?\/]+)/)
|
||||
|| t.match(/\/\/(www\.)?youtube\.com\/v\/([^\&\?\/]+)/) || t.match(/\/\/(www\.)?youtu\.be\/([^\&\?\/]+)/);
|
||||
if (v)
|
||||
{
|
||||
i = "youtube";
|
||||
v = v[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
// match vimeo links
|
||||
v = t.match(/\/\/(www\.)?vimeo.com\/(\d+)($|\/)/);
|
||||
if (v)
|
||||
{
|
||||
i = "vimeo";
|
||||
v = v[2];
|
||||
}
|
||||
else
|
||||
{
|
||||
// None matched, do nothing
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (submitted)
|
||||
{
|
||||
|
||||
// Visualize component
|
||||
temp = Dand.wrapc('v_box', Dand.wrapc('v_description', "Video(url): " + t)
|
||||
, [
|
||||
new DataKey("value", v)
|
||||
, new DataKey("type", i)
|
||||
, new IKey("style"
|
||||
, "width: 640px; height: 390px;"
|
||||
+ ( (i[0] == "v") ? "" : ("background: black url(http://img.youtube.com/vi/" + v + "/hqdefault.jpg) no-repeat center center;") )
|
||||
)
|
||||
]
|
||||
);
|
||||
|
||||
if (i[0] == "v")
|
||||
{
|
||||
getVimeoThumbnail(temp);
|
||||
}
|
||||
|
||||
insertSnippet(j = snippetWrap("Video", temp), Boolean(override));
|
||||
|
||||
// Set context menu
|
||||
createContext(null, j);
|
||||
}
|
||||
}
|
||||
;
|
||||
|
||||
if (override)
|
||||
{
|
||||
visualizer(true, override);
|
||||
override = false;
|
||||
}
|
||||
else
|
||||
{
|
||||
return handler;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
var compile = function (stage)
|
||||
{
|
||||
// [video type=\"youtube\"]" + v[2] + "[/video]
|
||||
var element = IDOMElement(stage)
|
||||
, type = element.getDAttribute("type");
|
||||
|
||||
return "[video type=\"" + type + "\"]" + element.getDAttribute("value") + "[/video]";
|
||||
};
|
||||
|
||||
__static_method( video, "compile", compile );
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Video", video );
|
||||
})();
|
25
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/_this.js
Normal file
25
botanjs/src/Astro/Blog/AstroEdit/Visualizer/Snippet/_this.js
Normal file
@@ -0,0 +1,25 @@
|
||||
(function()
|
||||
{
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit.Visualizer.Snippet" );
|
||||
|
||||
var escapeStr = function ( str )
|
||||
{
|
||||
return str.replace( /\[/g, "[" ).replace( /\]/g, "]" );
|
||||
};
|
||||
|
||||
var compileProp = function ( _iDOM, keys )
|
||||
{
|
||||
var i, j = "", k;
|
||||
for (i in keys)
|
||||
{
|
||||
if( ( k = _iDOM.getDAttribute(keys[i]) ) )
|
||||
{
|
||||
j += " " + keys[i] + "=\"" + k + "\"";
|
||||
}
|
||||
}
|
||||
return j;
|
||||
};
|
||||
|
||||
ns[ NS_EXPORT ]( EX_FUNC, "escapeStr", escapeStr );
|
||||
ns[ NS_EXPORT ]( EX_FUNC, "compileProp", compileProp );
|
||||
})();
|
101
botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.css
Normal file
101
botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.css
Normal file
@@ -0,0 +1,101 @@
|
||||
.v_snippet_input {
|
||||
width: 600px;
|
||||
height: 350px;
|
||||
}
|
||||
|
||||
.v_boundary {
|
||||
cursor: default;
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
.v_box {
|
||||
min-height: 3em;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.v_caption, .v_description {
|
||||
background: rgba(0, 0, 0, 0.8);
|
||||
padding: 0.2em;
|
||||
color: white;
|
||||
|
||||
width: 100%;
|
||||
|
||||
font-family: sans-serif;
|
||||
font-size: 1em;
|
||||
}
|
||||
|
||||
.v_caption {
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.v_description {
|
||||
position: absolute;
|
||||
left: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
.v_caption_desc {
|
||||
font-size: 60%;
|
||||
}
|
||||
|
||||
.v_boundary:hover {
|
||||
background-color: rgba(0, 0, 0, 0.2);
|
||||
}
|
||||
|
||||
.v_snippet_input_single {
|
||||
width: 600px;
|
||||
margin-bottom: 0.5em;
|
||||
}
|
||||
|
||||
.v_instruction {
|
||||
padding: 0.2em 0;
|
||||
}
|
||||
|
||||
.v_trimmer {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.v_select {
|
||||
width: 100%;
|
||||
background-color: #222;
|
||||
font-size: 1em;
|
||||
color: white;
|
||||
|
||||
background-image: none;
|
||||
border: none;
|
||||
box-shadow: none;
|
||||
-webkit-appearance: none;
|
||||
}
|
||||
|
||||
div[data-type="token"] {
|
||||
background-color: #111;
|
||||
color: #EEE;
|
||||
|
||||
padding: 0.25em 0.5em;
|
||||
margin-right: 100%;
|
||||
|
||||
min-width: 8em;
|
||||
|
||||
display: inline-block;
|
||||
|
||||
position: relative;
|
||||
}
|
||||
|
||||
div[data-type="token"]:hover {
|
||||
background-color: #444;
|
||||
}
|
||||
|
||||
div[data-type="token"]:after {
|
||||
content: "Loading";
|
||||
position: absolute;
|
||||
|
||||
color: rgba( 255, 255, 255, 0.2 );
|
||||
|
||||
right: 0;
|
||||
bottom: 0;
|
||||
}
|
||||
|
||||
div[data-type="token"]:hover:after {
|
||||
color: rgba( 255, 255, 255, 0.5 );
|
||||
}
|
496
botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.js
Normal file
496
botanjs/src/Astro/Blog/AstroEdit/Visualizer/_this.js
Normal file
@@ -0,0 +1,496 @@
|
||||
(function(){
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit" );
|
||||
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Dandelion.IDOMElement} */
|
||||
var IDOMElement = __import( "Dandelion.IDOMElement" );
|
||||
/** @type {System.Debug} */
|
||||
var debug = __import( "System.Debug" );
|
||||
/** @type {System.utils} */
|
||||
var utils = __import( "System.utils" );
|
||||
/** @type {System.utils.Perf} */
|
||||
var Perf = __import( "System.utils.Perf" );
|
||||
/** @type {System.utils.DataKey} */
|
||||
var DataKey = __import( "System.utils.DataKey" );
|
||||
/** @type {System.utils.EventKey} */
|
||||
var EventKey = __import( "System.utils.EventKey" );
|
||||
/** @type {System.utils.IKey} */
|
||||
var IKey = __import( "System.utils.IKey" );
|
||||
/** @type {System.Net.ClassLoader} */
|
||||
var Loader = __import( "System.Net.ClassLoader" );
|
||||
/** @type {Components.MessageBox} */
|
||||
var MessageBox = __import( "Components.MessageBox" );
|
||||
/** @type {Components.Mouse.ContextMenu} */
|
||||
var ContextMenu = __import( "Components.Mouse.ContextMenu" );
|
||||
/** @type {Astro.Blog.Config} */
|
||||
var Config = __import( "Astro.Blog.Config" );
|
||||
|
||||
var snippetList = IKey.quickDef(
|
||||
"Code" , "background: white; color: cornflowerblue;"
|
||||
, "Image" , "background: #ff0084;"
|
||||
, "Sound" , "background: YellowGreen;"
|
||||
, "Video" , "background: Crimson;"
|
||||
, "Spoiler" , "background: cornflowerblue;"
|
||||
, "Swf" , "background: #333;"
|
||||
, "Link" , "background: blue;"
|
||||
, "AcquireLib" , "background: black;"
|
||||
, "Html" , "background: coral;"
|
||||
, "SiteFile" , "background: royalblue;"
|
||||
);
|
||||
|
||||
var snippetNs = "Astro.Blog.AstroEdit.Visualizer.Snippet.";
|
||||
//// Document Visualizer visualize snippets, used in AstroEdit and comments
|
||||
var Visualizer = function ( e_document, snippetControls, service_uri )
|
||||
{
|
||||
var Article = ns[ NS_INVOKE ]( "Article" );
|
||||
var loadedModule = {};
|
||||
|
||||
//// Constants
|
||||
var article;
|
||||
// "[^]" does not work in IE
|
||||
var stackMatch = /\[([a-z][0-9a-z]*?)([\s\S]*?)\]([\s\S]*?)\[\/\1\]/ig;
|
||||
var typeMatch = /([a-z][0-9a-z]*)\=\"([^"]+)\"/ig;
|
||||
|
||||
var snippetTokenQueue = {};
|
||||
|
||||
if ( e_document instanceof Article )
|
||||
{
|
||||
article = e_document;
|
||||
// Allow Html snippet
|
||||
}
|
||||
else if ( e_document instanceof CeDocument )
|
||||
{
|
||||
article = e_document;
|
||||
}
|
||||
else return;
|
||||
|
||||
////// Variables
|
||||
var contentDiv = Dand.wrap()
|
||||
var selRange;
|
||||
var snippetExists = false;
|
||||
var lastOffset = 0;
|
||||
var raw;
|
||||
|
||||
///// private methods
|
||||
var snippetWrap = function( snippetType, element, editable, _with )
|
||||
{
|
||||
var snippet = Dand.wrap(
|
||||
_with || "div"
|
||||
, Perf.uuid
|
||||
, "comp v_boundary"
|
||||
, element
|
||||
, [
|
||||
new IKey( "contentEditable", editable ? "true" : "false" )
|
||||
, new DataKey( "type", snippetType )
|
||||
]
|
||||
);
|
||||
|
||||
return snippet;
|
||||
};
|
||||
|
||||
var appendLinebreak = function ()
|
||||
{
|
||||
this.parentNode.insertBefore(Dand.wrap("br"), this.nextSibling);
|
||||
}
|
||||
|
||||
var insertLinebreak = function ()
|
||||
{
|
||||
this.parentNode.insertBefore(Dand.wrap("br"), this);
|
||||
};
|
||||
|
||||
var snippetDelete = function ()
|
||||
{
|
||||
this.parentNode.removeChild(this);
|
||||
};
|
||||
|
||||
var snippetBBCode = function()
|
||||
{
|
||||
var snippet = IDOMElement( this );
|
||||
var type = snippet.getDAttribute( "type" ).toLowerCase();
|
||||
/** @type {Astro.Blog.AstroEdit.Visualizer.Snippet.Model} */
|
||||
var module = loadedModule[ type ];
|
||||
var title = "An error occurred";
|
||||
var message = "No such module";
|
||||
|
||||
if( module )
|
||||
{
|
||||
title = "BBCode for Snippet: " + type;
|
||||
message = module.compile( this.firstChild );
|
||||
}
|
||||
|
||||
new MessageBox( title, Dand.wrapne( "pre", message ) ).show();
|
||||
};
|
||||
|
||||
var createSnippetMenu = function ( snippetProp, snippet, editHandler, snippetActions )
|
||||
{
|
||||
var contextItems = [
|
||||
editHandler && new EventKey( "Edit", editHandler.bind( snippetProp ) )
|
||||
, new EventKey( "Insert a linebreak", insertLinebreak.bind( snippet ) )
|
||||
, new EventKey( "Append a linebreak", appendLinebreak.bind( snippet ) )
|
||||
, new EventKey( "Delete", snippetDelete.bind( snippet ) )
|
||||
, new EventKey( "View BBCode", snippetBBCode.bind( snippet ) )
|
||||
];
|
||||
|
||||
e_document.updateContent();
|
||||
|
||||
if ( snippetActions instanceof Array )
|
||||
{
|
||||
contextItems = snippetActions.concat( contextItems );
|
||||
}
|
||||
|
||||
return new ContextMenu( snippet, contextItems, "RMB" );
|
||||
};
|
||||
|
||||
var _savSelection = function ()
|
||||
{
|
||||
contentDiv.focus();
|
||||
if ( window.getSelection )
|
||||
{
|
||||
var sel = window.getSelection();
|
||||
if ( sel.getRangeAt && sel.rangeCount )
|
||||
{
|
||||
selRange = sel.getRangeAt(0);
|
||||
}
|
||||
}
|
||||
else if ( document.selection && document.selection.createRange )
|
||||
{
|
||||
selRange = document.selection.createRange();
|
||||
}
|
||||
else
|
||||
{
|
||||
selRange = null;
|
||||
}
|
||||
};
|
||||
|
||||
var _resSelection = function ()
|
||||
{
|
||||
if ( selRange )
|
||||
{
|
||||
if ( window.getSelection )
|
||||
{
|
||||
var sel = window.getSelection();
|
||||
sel.removeAllRanges();
|
||||
sel.addRange( selRange );
|
||||
}
|
||||
else if ( document.selection && selRange.select )
|
||||
{
|
||||
selRange.select();
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
var lastLine = Dand.wrap( "br", "v_linebreak" );
|
||||
|
||||
var ensureLastLinebreak = function ()
|
||||
{
|
||||
if( !Dand.id( "v_linebreak" ) )
|
||||
{
|
||||
insertSnippet( lastLine, true );
|
||||
}
|
||||
else
|
||||
{
|
||||
insertSnippet( contentDiv.removeChild( lastLine ), true );
|
||||
}
|
||||
};
|
||||
|
||||
var insertAtCaret = function( element )
|
||||
{
|
||||
var sel, range;
|
||||
|
||||
sel = window.getSelection();
|
||||
if ( sel.getRangeAt && sel.rangeCount )
|
||||
{
|
||||
range = sel.getRangeAt(0);
|
||||
range.deleteContents();
|
||||
range.insertNode( element );
|
||||
range.setStartAfter( element );
|
||||
range.setEndAfter( element );
|
||||
range.collapse( false );
|
||||
sel.removeAllRanges();
|
||||
sel.addRange( range );
|
||||
}
|
||||
|
||||
e_document.updateContent();
|
||||
ensureLastLinebreak();
|
||||
};
|
||||
|
||||
var insertSnippet = function( element, override )
|
||||
{
|
||||
if ( override )
|
||||
{
|
||||
contentDiv.appendChild( element );
|
||||
return;
|
||||
}
|
||||
|
||||
contentDiv.focus();
|
||||
_resSelection();
|
||||
insertAtCaret( element );
|
||||
};
|
||||
|
||||
var replaceToken = function( element )
|
||||
{
|
||||
contentDiv.insertBefore( element, this.token );
|
||||
contentDiv.removeChild( this.token );
|
||||
};
|
||||
|
||||
var parseKeys = function ( match, name, value )
|
||||
{
|
||||
this[ name ] = value;
|
||||
};
|
||||
|
||||
var snippetQueue = function( type, alias )
|
||||
{
|
||||
var q = snippetTokenQueue[ type ] || [];
|
||||
|
||||
if( alias )
|
||||
{
|
||||
if( !( alias instanceof Array ) ) alias = [ alias ];
|
||||
|
||||
for( var i in alias )
|
||||
{
|
||||
q = snippetTokenQueue[ alias[i] ] || [];
|
||||
if( q.length ) return q;
|
||||
}
|
||||
}
|
||||
|
||||
return ( snippetTokenQueue[ type ] = q );
|
||||
};
|
||||
|
||||
var parseSnippet = function( match, type, properties, _value, offset )
|
||||
{
|
||||
var temp, i, j;
|
||||
// Texts goes first
|
||||
if ( lastOffset != offset )
|
||||
{
|
||||
// innerText does not work in firefox:(
|
||||
temp = Dand.wrape( raw.substr( lastOffset, offset - lastOffset ) );
|
||||
// innerHTML will escape html entities, now replace linebreaks to br
|
||||
temp.innerHTML = temp.innerHTML.replace(/[\r\n]/g, "<br>");
|
||||
IDOMElement( contentDiv ).lootChildren( temp );
|
||||
}
|
||||
|
||||
lastOffset = offset + match.length;
|
||||
|
||||
// Snippet Args
|
||||
temp = { value: _value };
|
||||
// to ekeys
|
||||
properties.replace( typeMatch, parseKeys.bind( temp ) );
|
||||
|
||||
// Now deal with snippet
|
||||
/** @type {Astro.Blog.AstroEdit.Visualizer.Snippet.Model} */
|
||||
var _module = loadedModule[ type ];
|
||||
if ( _module )
|
||||
{
|
||||
// Visualize snippet
|
||||
new ( _module )( insertSnippet, snippetWrap, createSnippetMenu, temp );
|
||||
}
|
||||
else
|
||||
{
|
||||
// no such module, or module is not loaded yet
|
||||
debug.Info( "[Visualizer] Queueing: " + type );
|
||||
var token = snippetWrap( "token", type, false );
|
||||
token.setAttribute( "class", token.getAttribute( "class" ) + " flsf" );
|
||||
snippetQueue( type ).push([ token, temp ]);
|
||||
|
||||
insertSnippet( token, true );
|
||||
}
|
||||
};
|
||||
|
||||
var linebreakNodes = ["P", "DIV"];
|
||||
var linebreakNode = function( name )
|
||||
{
|
||||
if( -1 < linebreakNodes.indexOf( name.toUpperCase() ) ) return "\n";
|
||||
return "";
|
||||
};
|
||||
|
||||
var ensureGoodness = function ()
|
||||
{
|
||||
_savSelection();
|
||||
ensureLastLinebreak();
|
||||
};
|
||||
|
||||
var stepContent = function ( element, level )
|
||||
{
|
||||
var j , snippetType
|
||||
, elements = element.childNodes
|
||||
, output = "";
|
||||
|
||||
for (var i = 0, l = elements.length; i < l; i ++)
|
||||
{
|
||||
j = elements[i];
|
||||
|
||||
// do nothing on lastline
|
||||
if (j == lastLine) continue;
|
||||
|
||||
if (j.nodeType == 1)
|
||||
{
|
||||
snippetType = IDOMElement( j ).getDAttribute( "type" );
|
||||
if( snippetType && loadedModule[ snippetType = snippetType.toLowerCase() ] )
|
||||
{
|
||||
output += loadedModule[ snippetType ].compile( j.firstChild );
|
||||
}
|
||||
else if ( j.firstChild )
|
||||
{
|
||||
// Text
|
||||
output += linebreakNode( j.nodeName ) + stepContent(j, ++level);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Handle special <div><br></div> => one line break
|
||||
if(l == 1 && j.nodeName.toUpperCase() == "BR") continue;
|
||||
|
||||
// Line breaks
|
||||
output += "\n";
|
||||
}
|
||||
}
|
||||
// Text
|
||||
else if (j.nodeType == 3)
|
||||
{
|
||||
output += j.nodeValue;
|
||||
}
|
||||
}
|
||||
|
||||
return output;
|
||||
};
|
||||
|
||||
///// Initializations
|
||||
var snippetReady = function ( e )
|
||||
{
|
||||
// Initialize modules
|
||||
var mod_name = e.substr( e.lastIndexOf(".") + 1, e.length ).toLowerCase()
|
||||
/** @type {Astro.Blog.AstroEdit.Visualizer.Snippet.Model} */
|
||||
var _module = __import( e );
|
||||
var alias = _module.alias;
|
||||
|
||||
// Implement module if valid and available
|
||||
if ( _module && _module.compile )
|
||||
{
|
||||
loadedModule[ mod_name ] = _module;
|
||||
debug.Info( "[Visualizer] Module loaded: " + mod_name );
|
||||
// Set alias
|
||||
if ( alias )
|
||||
{
|
||||
alias = ( alias instanceof Array ) ? alias : [ alias ];
|
||||
|
||||
for ( var k in alias )
|
||||
{
|
||||
loadedModule[ alias[k] ] = _module;
|
||||
debug.Info( "[Visualizer] Alias: " + mod_name + " => " + alias );
|
||||
}
|
||||
}
|
||||
|
||||
// Append module"s control
|
||||
temp = Dand.wrapne(
|
||||
"span"
|
||||
, mod_name
|
||||
, new IKey(
|
||||
"style"
|
||||
, utils.objSearch(
|
||||
snippetList
|
||||
/** @param {System.utils.IKey} a */
|
||||
, function( a ) { return a.keyName.toLowerCase() == mod_name }
|
||||
, "keyValue"
|
||||
)
|
||||
)
|
||||
);
|
||||
|
||||
snippetControls.appendChild( temp );
|
||||
snippetControls.appendChild( Dand.textNode( "\t" ) );
|
||||
temp.onclick = new ( _module )( insertSnippet, snippetWrap, createSnippetMenu );
|
||||
|
||||
var queue = snippetQueue( mod_name, _module.alias );
|
||||
for( var i in queue )
|
||||
{
|
||||
var token = queue[i];
|
||||
new ( _module )( replaceToken.bind({ token: token[0] }), snippetWrap, createSnippetMenu, token[1] );
|
||||
delete queue[i];
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if ( _module )
|
||||
{
|
||||
delete loadedModule[ mod_name ];
|
||||
debug.Info( "[Visualizer] Module discarded: invalid module \"" + mod_name + "\"" );
|
||||
}
|
||||
else
|
||||
{
|
||||
debug.Info( "[Visualizer] Module \"" + mod_name + "\" does not exists" );
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
this.setContentDiv = function( element )
|
||||
{
|
||||
contentDiv = element;
|
||||
// listeners that return values cannot use addEventListener
|
||||
contentDiv.onkeypress = function(e)
|
||||
{
|
||||
if (e.which == 13)
|
||||
{
|
||||
insertAtCaret( Dand.wrap( "br" ) );
|
||||
_savSelection();
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
};
|
||||
|
||||
temp = IDOMElement( contentDiv );
|
||||
temp.addEventListener( "Input", ensureGoodness );
|
||||
temp.addEventListener( "KeyUp", ensureGoodness );
|
||||
temp.addEventListener( "Click", ensureGoodness );
|
||||
|
||||
contentDiv.focus();
|
||||
ensureGoodness();
|
||||
|
||||
try {
|
||||
document.execCommand( "insertBrOnReturn", false, "true" );
|
||||
} catch(e) {
|
||||
debug.Info( "Not firefox" );
|
||||
}
|
||||
};
|
||||
|
||||
this.saveRaw = function ()
|
||||
{
|
||||
return stepContent( contentDiv, 0 );
|
||||
};
|
||||
|
||||
this.visualizeData = function ( data )
|
||||
{
|
||||
if ( !data ) return;
|
||||
|
||||
lastOffset = 0;
|
||||
// clear content
|
||||
contentDiv.innerHTML = "";
|
||||
|
||||
( raw = data ).replace( stackMatch, parseSnippet );
|
||||
if ( lastOffset != raw.length )
|
||||
{
|
||||
// innerText does not work in firefox:(
|
||||
temp = Dand.wrape( raw.substr( lastOffset, raw.length - lastOffset ) );
|
||||
// innerHTML will escape html entities, now replace linebreaks to br
|
||||
temp.innerHTML = temp.innerHTML.replace( /[\r\n]/g, "<br>" );
|
||||
IDOMElement( contentDiv ).lootChildren( temp );
|
||||
}
|
||||
temp = null;
|
||||
raw = null;
|
||||
};
|
||||
|
||||
this.saveSelection = _savSelection;
|
||||
this.restoreSelection = _resSelection;
|
||||
|
||||
article.invoke(this);
|
||||
|
||||
var modules = [];
|
||||
for( var i in snippetList )
|
||||
{
|
||||
modules[ modules.length ] = snippetNs + snippetList[i].keyName;
|
||||
}
|
||||
|
||||
var ldr = new Loader( service_uri, "r" );
|
||||
ldr.load( modules, snippetReady );
|
||||
};
|
||||
|
||||
ns[ NS_EXPORT ]( EX_CLASS, "Visualizer", Visualizer );
|
||||
})();
|
244
botanjs/src/Astro/Blog/AstroEdit/_this.css
Normal file
244
botanjs/src/Astro/Blog/AstroEdit/_this.css
Normal file
@@ -0,0 +1,244 @@
|
||||
.ae_panel_section {
|
||||
padding: 0 1em;
|
||||
color: white;
|
||||
}
|
||||
|
||||
.ae_section_prop {
|
||||
margin: 0.5em 0;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ae_prop_value {
|
||||
font-size: 1.2em;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
/* Interactive value */
|
||||
.ae_iValue {
|
||||
text-align: center;
|
||||
padding: 0.5em;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.ae_background {
|
||||
background-color: #fff;
|
||||
background-image:
|
||||
linear-gradient(90deg, transparent 1em, #666 1em, #666 1.2em, transparent 1.2em),
|
||||
linear-gradient(#EEE .1em, transparent .1em);
|
||||
background-size: 100% 1.5em;
|
||||
}
|
||||
|
||||
|
||||
/* Buttons */
|
||||
.ae_purple { background: purple; }
|
||||
.ae_purple:hover { background: darkmagenta; }
|
||||
.ae_coral { background: orangered; }
|
||||
.ae_coral:hover { background: darkorange; }
|
||||
.ae_dodgerblue { background: dodgerblue; }
|
||||
.ae_caution { color: red; }
|
||||
.ae_caution:hover { background: #333; }
|
||||
.ae_dodgerblue:hover { background: cornflowerblue; }
|
||||
/* End buttons */
|
||||
|
||||
|
||||
.ae_disabled {
|
||||
color: grey;
|
||||
background: none;
|
||||
}
|
||||
|
||||
.ae_blockswitch {
|
||||
line-height: 2em;
|
||||
}
|
||||
|
||||
.ae_blockswitch > span {
|
||||
white-space: nowrap;
|
||||
/* text-transform:uppercase; */
|
||||
font-family: custom-sans;
|
||||
padding: 0.2em 0.5em;
|
||||
cursor: default;
|
||||
opacity: 0.5;
|
||||
}
|
||||
|
||||
.ae_blockswitch > span:hover {
|
||||
background-color: black;
|
||||
opacity: 1;
|
||||
}
|
||||
|
||||
.ae_body {
|
||||
max-height: 100%;
|
||||
|
||||
overflow-y: scroll;
|
||||
|
||||
position: fixed;
|
||||
}
|
||||
|
||||
.ae_content {
|
||||
width: auto;
|
||||
background: SkyBlue;
|
||||
}
|
||||
|
||||
.ae_panel {
|
||||
width: 300px;
|
||||
height: auto;
|
||||
min-height: 100%;
|
||||
background: #222;
|
||||
color: white;
|
||||
|
||||
position: absolute;
|
||||
|
||||
top: 0;
|
||||
right: 0;
|
||||
|
||||
/* will handel mouse scroll later*/
|
||||
overflow: hidden;
|
||||
|
||||
-moz-box-shadow: -2px 0 5px black;
|
||||
-webkit-box-shadow: -2px 0 5px black;
|
||||
box-shadow: -2px 0 5px black;
|
||||
}
|
||||
|
||||
.ae_topbar {
|
||||
width: 100%;
|
||||
color: #222;
|
||||
padding: 0.35em 0;
|
||||
overflow: hidden;
|
||||
border-bottom: 7px solid #222;
|
||||
}
|
||||
|
||||
|
||||
.ae_title, .ae_stitle {
|
||||
padding: 0.35em;
|
||||
}
|
||||
|
||||
.ae_title {
|
||||
position: relative;
|
||||
top: 0.25em;
|
||||
font-size: 2em;
|
||||
}
|
||||
|
||||
.ae_stitle {
|
||||
font-size: 1.5em;
|
||||
}
|
||||
|
||||
#ae_title {
|
||||
font-size: 2.5em;
|
||||
color: #444;
|
||||
}
|
||||
|
||||
#ae_content {
|
||||
font-size: 100%;
|
||||
}
|
||||
|
||||
#ae_title, #ae_content {
|
||||
background: none;
|
||||
width: 100%;
|
||||
|
||||
-webkit-box-sizing: border-box;
|
||||
-moz-box-sizing: border-box;
|
||||
box-sizing: border-box;
|
||||
}
|
||||
|
||||
#ae_title:focus {
|
||||
background: rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
#ae_content:focus {
|
||||
background: rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
#ae_bgdimmer {
|
||||
background: rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
#ae_content, #ae_bgdimmer {
|
||||
color: #555;
|
||||
padding: 1em 1em 2em 1em;
|
||||
}
|
||||
|
||||
.ae_preview {
|
||||
display: block;
|
||||
color: white;
|
||||
text-decoration: none;
|
||||
padding: 0.4em;
|
||||
font-size: 100%;
|
||||
width: 100%;
|
||||
}
|
||||
|
||||
.ae_user_info {
|
||||
background: #111;
|
||||
overflow: hidden;
|
||||
position: relative;
|
||||
}
|
||||
|
||||
.ae_draft_section {
|
||||
padding: 0.5em;
|
||||
}
|
||||
|
||||
.ae_draft_logo {
|
||||
font-size: 3em;
|
||||
position: absolute;
|
||||
opacity: 0.2;
|
||||
cursor: default;
|
||||
}
|
||||
|
||||
.ae_name {
|
||||
text-align: right;
|
||||
padding: 0.2em;
|
||||
}
|
||||
|
||||
.ae_user_content {
|
||||
padding: 0.2em
|
||||
}
|
||||
|
||||
#ae_user_drafts {
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.ae_dEntry {
|
||||
cursor: default;
|
||||
padding: 0.2em;
|
||||
background: rgba(255, 255, 255, 0);
|
||||
}
|
||||
|
||||
.ae_dEntry:hover {
|
||||
background: rgba(255, 255, 255, 0.2);
|
||||
}
|
||||
|
||||
.ae_dEntry_date {
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
.ae_expand_btn, .ae_callapse_btn {
|
||||
background: url(http://file.astropenguin.net/blog/layout-images/collapse.png) center 2.5px no-repeat;
|
||||
width: 100%;
|
||||
height: 10px;
|
||||
}
|
||||
|
||||
.ae_expand_btn {
|
||||
-webkit-transform: rotate(180deg);
|
||||
-moz-transform: rotate(180deg);
|
||||
transform: rotate(180deg);
|
||||
}
|
||||
|
||||
.ae_callapse_btn {
|
||||
-webkit-transform: rotate(0deg);
|
||||
-moz-transform: rotate(0deg);
|
||||
transform: rotate(0deg);
|
||||
}
|
||||
|
||||
.ae_affected_count {
|
||||
color: red;
|
||||
}
|
||||
|
||||
/*Active draft notation*/
|
||||
.ae_dActive_bubble {
|
||||
float: right;
|
||||
color: yellowgreen;
|
||||
text-shadow: 0 0 5px yellowgreen;
|
||||
font-size: 80%;
|
||||
}
|
||||
|
||||
body {
|
||||
margin: 0 auto;
|
||||
min-width: 1200px;
|
||||
}
|
99
botanjs/src/Astro/Blog/AstroEdit/_this.js
Normal file
99
botanjs/src/Astro/Blog/AstroEdit/_this.js
Normal file
@@ -0,0 +1,99 @@
|
||||
(function(){
|
||||
var ns = __namespace( "Astro.Blog.AstroEdit" );
|
||||
|
||||
/** @type {System.Cycle} */
|
||||
var Cycle = __import( "System.Cycle" );
|
||||
/** @type {Dandelion} */
|
||||
var Dand = __import( "Dandelion" );
|
||||
/** @type {Astro.Bootstrap} */
|
||||
var Bootstrap = __import( "Astro.Bootstrap" );
|
||||
/** @type {Astro.Blog.Config} */
|
||||
var Config = __import( "Astro.Blog.Config" );
|
||||
/** @type {Astro.Blog.AstroEdit.Article} */
|
||||
var Article = __import( "Astro.Blog.AstroEdit.Article" );
|
||||
/** @type {Astro.Blog.AstroEdit.Draft} */
|
||||
var Draft = __import( "Astro.Blog.AstroEdit.Draft" );
|
||||
/** @type {Astro.Blog.AstroEdit.Tag} */
|
||||
var Tag = __import( "Astro.Blog.AstroEdit.Tag" );
|
||||
/** @type {Astro.Blog.AstroEdit.Visualizer} */
|
||||
var Visualizer = __import( "Astro.Blog.AstroEdit.Visualizer" );
|
||||
/** @type {Astro.Blog.AstroEdit.Uploader} */
|
||||
var Uploader = __import( "Astro.Blog.AstroEdit.Uploader" );
|
||||
/** @type {Astro.Blog.AstroEdit.SiteLibrary} */
|
||||
var SiteLibrary = __import( "Astro.Blog.AstroEdit.SiteLibrary" );
|
||||
|
||||
var wh, ww, cw, html, article;
|
||||
|
||||
var init = function ()
|
||||
{
|
||||
//// Component initializations
|
||||
/** @type {_AstConf_.AstroEdit} */
|
||||
var a_conf = Config.get( "AstroEdit" );
|
||||
var base_path = Config.get( "BasePath" );
|
||||
|
||||
Cycle.next(
|
||||
function()
|
||||
{
|
||||
article.load(
|
||||
a_conf.article_id
|
||||
, function( obj, id )
|
||||
{
|
||||
window.history.replaceState( obj, "", base_path + "astroedit/" + id + "/" );
|
||||
}
|
||||
);
|
||||
}
|
||||
);
|
||||
|
||||
article = new Article( a_conf.paths.set_article );
|
||||
|
||||
// Article modules
|
||||
new Draft( article, a_conf.paths.get_drafts );
|
||||
new Tag( article, a_conf.paths.tag_count );
|
||||
new Visualizer(
|
||||
article
|
||||
, Dand.id( "ae_visual_snippets" )
|
||||
, Config.get( "ServiceUri" )
|
||||
);
|
||||
|
||||
// Independent modules
|
||||
new Uploader( a_conf.paths.set_file );
|
||||
new SiteLibrary(
|
||||
Config.get( "BasePath" )
|
||||
, a_conf.paths.get_files
|
||||
, a_conf.paths.set_file
|
||||
);
|
||||
|
||||
var title = Dand.id("ae_title");
|
||||
var content = Dand.id("ae_content");
|
||||
|
||||
// content height
|
||||
content.style.minHeight = String(screen.availHeight) + "px";
|
||||
|
||||
html = document.body.parentNode;
|
||||
|
||||
window.onresize = adjustLayout;
|
||||
|
||||
// Setting event handlers
|
||||
title.onblur = content.onblur = function () { Dand.id("ae_bgdimmer").style.background = ""; };
|
||||
content.onfocus = content.onfocus = function ()
|
||||
{
|
||||
Dand.id("ae_bgdimmer").style.background = "rgba(255, 255, 255, 0.2)";
|
||||
};
|
||||
|
||||
Dand.id( "ae_publish_btn" ).onclick = function () { article.saveAndPublish(); };
|
||||
Dand.id( "ae_preview_btn" ).onclick = function () { article.preview(); };
|
||||
Dand.id( "ae_drop_btn" ).onclick = function () { article.drop(); };;
|
||||
|
||||
adjustLayout();
|
||||
};
|
||||
|
||||
var adjustLayout = function ()
|
||||
{
|
||||
ww = html.clientWidth;
|
||||
wh = html.clientHeight;
|
||||
cw = ww - 300;
|
||||
Dand.id("ae_body").style.width = String(cw) + "px";
|
||||
};
|
||||
|
||||
Bootstrap.regInit( init );
|
||||
})();
|
Reference in New Issue
Block a user