penguin/AstroJS

Javascript framework for my blog

commit 1d812de551ae9652c967a857c54c79d3cb41db36

author斟酌 鵬兄 <tgckpg@gmail.com>
date2015-09-22T11:31:53Z
subjectGeneralize tags to flags
commit 1d812de551ae9652c967a857c54c79d3cb41db36
Author: 斟酌 鵬兄 <tgckpg@gmail.com>
Date:   2015-09-22T11:31:53Z

    Generalize tags to flags
---
 botanjs/src/Astro/Blog/AstroEdit/Article.js        |  98 ++++++++--
 .../src/Astro/Blog/AstroEdit/{Tag.css => Flag.css} |  12 +-
 botanjs/src/Astro/Blog/AstroEdit/Flag.js           | 187 +++++++++++++++++++
 botanjs/src/Astro/Blog/AstroEdit/Tag.js            | 197 ---------------------
 botanjs/src/Astro/Blog/AstroEdit/_this.css         |   6 +
 botanjs/src/Astro/Blog/AstroEdit/_this.js          |  13 +-
 .../src/externs/Astro.Blog.AstroEdit.IPlugin.js    |   8 +
 botanjs/src/externs/Astro.Blog.AstroEdit.Tag.js    |   6 -
 botanjs/src/externs/_AstConf_.AstroEdit.js         |  16 +-
 botanjs/src/externs/_AstJson_.AJaxGetArticle.js    |   2 +
 10 files changed, 315 insertions(+), 230 deletions(-)

diff --git a/botanjs/src/Astro/Blog/AstroEdit/Article.js b/botanjs/src/Astro/Blog/AstroEdit/Article.js
index cfe7210..5cfde04 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/Article.js
+++ b/botanjs/src/Astro/Blog/AstroEdit/Article.js
@@ -20,11 +20,11 @@
 	/** @type {Astro.Blog.Components.Bubble} */
 	var Bubble                           = __import( "Astro.Blog.Components.Bubble" );
 
-	var opostData                         = __import( "System.Net.postData" );
+	var opostData                        = __import( "System.Net.postData" );
 	var prettyDate                       = __import( "Astro.utils.Date.pretty" );
 
 	var Visualizer = ns[ NS_INVOKE ]( "Visualizer" );
-	var Tag = ns[ NS_INVOKE ]( "Tag" );
+	var Flag = ns[ NS_INVOKE ]( "Flag" );
 
 
 	// Editor Override
@@ -34,7 +34,43 @@
 		opostData( processor, data, success, failed );
 	};
 
-	var Article = function( processorSet )
+	// Wrappers for every plugins
+	var PluginBundles = function( article, plugins )
+	{
+		this.plugins = plugins;
+		for( var i in this.plugins )
+		{
+			/* @type {Astro.Blog.AstroEdit.IPlugins} */
+			var g = this.plugins[i];
+			g.bindArticle = article;
+		}
+	};
+
+	PluginBundles.prototype.setForView = function( pluginId, data )
+	{
+		for( var i in this.plugins )
+		{
+			var p = this.plugins[i];
+			if( p.id == pluginId )
+			{
+			   p.setForView( data );
+			}
+		}
+	};
+
+	PluginBundles.prototype.getSetData = function( pluginId, data )
+	{
+		for( var i in this.plugins )
+		{
+			var p = this.plugins[i];
+			if( p.id == pluginId )
+			{
+			   p.getSetData( data );
+			}
+		}
+	};
+
+	var Article = function( processorSet, plugins )
 	{
 		var pBubble = new Bubble();
 
@@ -44,7 +80,6 @@
 		var _content = "";
 
 		//// Classes & obj
-		var _ae_tag = null;
 		var _visualizer = null;
 		var timestamp = new Date();
 
@@ -58,6 +93,7 @@
 			, date_created: timestamp
 			, archived: false
 			, tags: null
+			, section: null
 			, draft: true
 			, article_id: false
 		};
@@ -78,7 +114,7 @@
 		var a_conf = Config.get( "AstroEdit" );
 		var base_path = Config.get( "BasePath" );
 
-		///// preview fields
+		/*{{{ preview fields */
 		var ae_p_fields = {
 			mtime:     set_field_name( Dand.wrap( "input" ), "date_modified" )
 			, ptime:   set_field_name( Dand.wrap( "input" ), "date_published" )
@@ -94,8 +130,42 @@
 		var temp;
 
 		for ( var i in ae_p_fields ) ae_preview.appendChild( ae_p_fields[i] );
-		//// End preview fields
+		/* End preview fields }}}*/
 
+		/*{{{ Button sections */
+		var ae_stitles = Dand.glass( "ae_stitle", true );
+		var ae_panel_section = Dand.glass( "ae_panel_section", true );
+
+		var l = ae_stitles.length;
+		for( var i = 0; i < l; i ++ )
+		{
+			var t = ae_stitles[i];
+			var p = ae_panel_section[i];
+			t.addEventListener( "Click", function( e )
+			{
+				var p = this.p;
+				if( this.t.expanded = !this.t.expanded )
+				{
+					p.style.height = "auto";
+					Cycle.next(
+						function(){
+							p.style.height = this.h + "px";
+						}.bind({ h: p.element.clientHeight })
+					);
+					p.style.height = 0;
+				}
+				else
+				{
+					p.style.height = 0;
+				}
+			}.bind({ t: t, p: p }) );
+		}
+
+		ae_stitles[0].element.click();
+		/* End Button sections }}}*/
+
+		// Install plugins
+		plugins = new PluginBundles( this, plugins );
 
 		var enableSaveFunction = function ()
 		{
@@ -253,8 +323,8 @@
 			ae_publish.innerHTML = ArticleModel.draft ? "Publish" : "Done edit";
 			ae_backup.innerHTML = ( ArticleModel.draft ? "Save" : "Backup" ) + "(Ctrl + s)";
 
-
-			_ae_tag && _ae_tag.setTags( ArticleModel.tags );
+			plugins.setForView( "tags", ArticleModel.tags );
+			plugins.setForView( "section", ArticleModel.section );
 		}
 
 		, deleteDraft = function ( confirmed )
@@ -311,10 +381,12 @@
 					article_id: __article_id ? __article_id : ""
 					, title: _title
 					, content: _content
-					, tags: _ae_tag.getTags()
 					, draft: 1
 				};
 
+				plugins.getSetData( "tags", _data );
+				plugins.getSetData( "section", _data );
+
 				postData( processorSet, _data, saveSuccess, serverFailed );
 			}
 		};
@@ -345,7 +417,7 @@
 				? ArticleModel.date_published
 				: Math.floor( 0.001*( new Date().getTime() ) )
 				;
-			ae_p_fields.tags.value = _ae_tag.getTags();
+			ae_p_fields.tags.value = _ae_tag.getFlags();
 
 			ae_preview.submit();
 		};
@@ -358,10 +430,10 @@
 				_visualizer = _class;
 				_visualizer.setContentDiv( ae_content );
 			}
-			if ( _class instanceof Tag )
+			if ( _class instanceof Flag )
 			{
 				_ae_tag = _class;
-				ArticleModel && ArticleModel.tags && ( _ae_tag ).setTags( ArticleModel.tags );
+				ArticleModel && ArticleModel.tags && ( _ae_tag ).setFlags( ArticleModel.tags );
 			}
 		};
 
@@ -389,7 +461,7 @@
 
 				_data.title = _title;
 				_data.content = _content;
-				_data.tags = _ae_tag.getTags();
+				_data.tags = _ae_tag.getFlags();
 
 				postData( processorSet, _data, publishSuccess.bind({ contentUpdate: true }), serverFailed );
 			}
diff --git a/botanjs/src/Astro/Blog/AstroEdit/Tag.css b/botanjs/src/Astro/Blog/AstroEdit/Flag.css
similarity index 63%
rename from botanjs/src/Astro/Blog/AstroEdit/Tag.css
rename to botanjs/src/Astro/Blog/AstroEdit/Flag.css
index 10b6b7b..5968bfd 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/Tag.css
+++ b/botanjs/src/Astro/Blog/AstroEdit/Flag.css
@@ -1,27 +1,27 @@
-.tag_active {
+.flag_active {
 	color: white;
 	opacity: 1 !important;
 }
 
-.ae_tag_delete {
+.ae_flag_delete {
 	color: white;
 	padding: 0 0.5em 0 0;
 }
 
-.ae_tag_delete:hover {
+.ae_flag_delete:hover {
 	color: red;
 }
 
-.ae_tag_add {
+.ae_flag_add {
 	color: white;
 	cursor: default;
 	font-weight: 200;
 }
 
-.ae_tag_add:hover {
+.ae_flag_add:hover {
 	color: dodgerblue;
 }
 
-#ae_tags > span {
+.ae_flags > span {
     float: left;
 }
diff --git a/botanjs/src/Astro/Blog/AstroEdit/Flag.js b/botanjs/src/Astro/Blog/AstroEdit/Flag.js
new file mode 100644
index 0000000..63081ee
--- /dev/null
+++ b/botanjs/src/Astro/Blog/AstroEdit/Flag.js
@@ -0,0 +1,187 @@
+(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" );
+
+	/* @type {AstroEdit.IPlugins} */
+	var Flag = function ( id, target, flagConf )
+	{
+		this.id = id;
+		var stage = Dand.id( target );
+		var ae_addFlag = Dand.glass( "ae_flag_add" , true, stage )[0];
+		var ae_flags = Dand.glass( "ae_flags" , false, stage )[0];
+
+		// Store flags for future use
+		var flags = {};
+
+		////// Handlers
+		ae_addFlag.addEventListener(
+			"Click", function ( e )
+			{
+				e.stopPropagation();
+				// Input fields
+				var ae_flagInput;
+
+				// Popup MessageBox
+				new MessageBox(
+					"Add new flag(s)"
+					, Dand.wrape([
+						Dand.wrapc(
+							"v_instruction flsf"
+							, "Flags are separated by \\n. (existing flags will be ignored.)"
+						)
+						, ae_flagInput = Dand.wrap( "textarea", null, "v_snippet_input" )
+					])
+					, "OK", "Cancel"
+					, parseFlags.bind( ae_flagInput )
+				).show();
+			}
+		);
+
+		var	deleteFlag = function (e)
+		{
+			var p = { flag: this.nodeValue, sflage: this.parentNode };
+			postData( flagConf.URICount, p, confirmDelete.bind( p ), serverFailed );
+			e.stopPropagation();
+		};
+
+		var confirmDelete = function (obj)
+		{
+			new MessageBox(
+				"Delete Flag"
+				, [
+					Dand.wrapc("ae_blockswitch",
+						[
+							Dand.textNode( "Are you sure you want to delete " )
+							, Dand.wrap( "span", null, "flag_active", Dand.textNode( this.flag ) )
+							, 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(
+					flagConf.URISet
+					, { flag: this.flag, del: 1 }
+					, deleteSuccess.bind( this )
+					, serverFailed
+				);
+			}
+		};
+
+		var deleteSuccess = function(obj)
+		{
+			// Remove element
+			this.sflage.parentNode.removeChild(this.sflage);
+			// Delete reference
+			delete flags[this.flag];
+		};
+
+		var parseFlags = function ()
+		{
+			// Filter invalid flags
+			var nflags = this.value.trim().match(/[^\n]+/g), d, e;
+			for (var i in nflags)
+			{
+				if(!flags[(i = nflags[i]).toLowerCase()])
+				{
+					flags[i] = Dand.wrap("span", null, "flag_active",
+						[d = Dand.wrap("span", null, "ae_flag_delete", "\u00D7"), e = Dand.textNode(i)]
+					);
+					// Seperator
+					ae_flags.appendChild(Dand.textNode("	"));
+					ae_flags.appendChild(flags[i]);
+
+					flags[i].onclick = function() { toggleFlag(this) }.bind(flags[i]);
+					d.onclick = deleteFlag.bind(e);
+
+				}
+				else
+				{
+					debug.Info("Flag exist: " + i);
+					// Hightlight these flags
+					flags[i.toLowerCase()].className = "flag_active";
+				}
+			}
+
+		};
+
+		var toggleFlag = function (flag)
+		{
+			var isEnabled = flag.className == "flag_active" ? true : false;
+			flag.className = isEnabled ? "ae_disabled" : "flag_active";
+		};
+
+		var serverFailed = function (obj) { };
+
+		var cflag, ae_children = ae_flags.childNodes;
+		for (var i in ae_children)
+		{
+			if((cflag = ae_children[i]).nodeType == 1)
+			{
+				flags[cflag.lastChild.nodeValue.toLowerCase()] = cflag;
+				IDOMElement( cflag ).addEventListener( "Click", function() { toggleFlag( this ); }.bind( cflag ) );
+				// Bind the last child (x button) to firstChild (textNode: flagname)
+				IDOMElement( cflag.firstChild ).addEventListener( "Click", deleteFlag.bind( cflag.lastChild ) );
+			}
+		}
+
+		this.getSetData = function ( data )
+		{
+			// Compile flag list
+			var tlist = [];
+
+			// Return names
+			for (var i in flags)
+			{
+				if(flags[i].className == "flag_active")
+					tlist[tlist.length] = flags[i].lastChild.nodeValue;
+			}
+
+			data[ this.id ] = tlist.join("\n");
+		}
+
+		this.setForView = function ( flagList )
+		{
+			// Disable all flags first
+			for ( var i in flags ) flags[i].className = "ae_disabled";
+
+			// Set flags from flagList
+			for ( i in flagList )
+				if ( flagList[i] ) flags[flagList[i].toLowerCase()].className = "flag_active";
+		}
+	}
+
+	Flag.prototype.getSetData = function () {	};
+	Flag.prototype.setForView = function ( flagList ) {	};
+
+	ns[ NS_EXPORT ]( EX_CLASS, "Flag", Flag );
+
+})();
diff --git a/botanjs/src/Astro/Blog/AstroEdit/Tag.js b/botanjs/src/Astro/Blog/AstroEdit/Tag.js
deleted file mode 100644
index 028da5b..0000000
--- a/botanjs/src/Astro/Blog/AstroEdit/Tag.js
+++ /dev/null
@@ -1,197 +0,0 @@
-(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 );
-
-})();
diff --git a/botanjs/src/Astro/Blog/AstroEdit/_this.css b/botanjs/src/Astro/Blog/AstroEdit/_this.css
index e312862..a948732 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/_this.css
+++ b/botanjs/src/Astro/Blog/AstroEdit/_this.css
@@ -1,6 +1,8 @@
 .ae_panel_section {
 	padding: 0 1em;
 	color: white;
+    height: 0;
+    overflow: hidden;;
 }
 
 .ae_section_prop {
@@ -116,6 +118,10 @@
 	font-size: 2em;
 }
 
+.ae_stitle:hover {
+    background-color: rgba( 0, 0, 0, 0.2 );
+}
+
 .ae_stitle {
 	font-size: 1.5em;
 }
diff --git a/botanjs/src/Astro/Blog/AstroEdit/_this.js b/botanjs/src/Astro/Blog/AstroEdit/_this.js
index 9e173e9..e013993 100644
--- a/botanjs/src/Astro/Blog/AstroEdit/_this.js
+++ b/botanjs/src/Astro/Blog/AstroEdit/_this.js
@@ -13,8 +13,8 @@
 	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.Flag} */
+	var Flag                                        = __import( "Astro.Blog.AstroEdit.Flag" );
 	/** @type {Astro.Blog.AstroEdit.Visualizer} */
 	var Visualizer                                 = __import( "Astro.Blog.AstroEdit.Visualizer" );
 	/** @type {Astro.Blog.AstroEdit.Uploader} */
@@ -44,11 +44,16 @@
 			}
 		);
 
-		article = new Article( a_conf.paths.set_article );
+		article = new Article(
+			a_conf.paths.set_article
+			, [
+				new Flag( "tags", "ae_tags", a_conf.paths.tags )
+				, new Flag( "section", "ae_secs", a_conf.paths.sections )
+			]
+		);
 
 		// 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" )
diff --git a/botanjs/src/externs/Astro.Blog.AstroEdit.IPlugin.js b/botanjs/src/externs/Astro.Blog.AstroEdit.IPlugin.js
new file mode 100644
index 0000000..78a1000
--- /dev/null
+++ b/botanjs/src/externs/Astro.Blog.AstroEdit.IPlugin.js
@@ -0,0 +1,8 @@
+/** @constructor Plugin Interface */
+Astro.Blog.AstroEdit.IPlugin = function(){};
+/** @type {String} */
+Astro.Blog.AstroEdit.IPlugin.id;
+/** @type {Function} */
+Astro.Blog.AstroEdit.IPlugin.setFromData;
+/** @type {Function} */
+Astro.Blog.AstroEdit.IPlugin.getSetData;
diff --git a/botanjs/src/externs/Astro.Blog.AstroEdit.Tag.js b/botanjs/src/externs/Astro.Blog.AstroEdit.Tag.js
deleted file mode 100644
index a3c6b92..0000000
--- a/botanjs/src/externs/Astro.Blog.AstroEdit.Tag.js
+++ /dev/null
@@ -1,6 +0,0 @@
-/** @constructor */
-Astro.Blog.AstroEdit.Tag = function(){};
-/** @type {Function} */
-Astro.Blog.AstroEdit.Tag.getTags;
-/** @type {Function} */
-Astro.Blog.AstroEdit.Tag.setTags;
diff --git a/botanjs/src/externs/_AstConf_.AstroEdit.js b/botanjs/src/externs/_AstConf_.AstroEdit.js
index 0ef0cc9..ac4fddb 100644
--- a/botanjs/src/externs/_AstConf_.AstroEdit.js
+++ b/botanjs/src/externs/_AstConf_.AstroEdit.js
@@ -14,7 +14,15 @@ _AstConf_.AstroEdit.paths = {};
 	_AstConf_.AstroEdit.paths.get_files;
 	/** @type {string} */
 	_AstConf_.AstroEdit.paths.set_file;
-	/** @type {string} */
-	_AstConf_.AstroEdit.paths.tag_count;
-	/** @type {string} */
-	_AstConf_.AstroEdit.paths.set_tag;
+
+	/** @type {object} */
+	_AstConf_.AstroEdit.tags;
+	/** @type {object} */
+	_AstConf_.AstroEdit.sections;
+
+/** @type {object} */
+_AstConf_.AstroEdit.flags = {};
+/** @type {string} */
+_AstConf_.AstroEdit.flags.URICount;
+/** @type {string} */
+_AstConf_.AstroEdit.flags.URISet;
diff --git a/botanjs/src/externs/_AstJson_.AJaxGetArticle.js b/botanjs/src/externs/_AstJson_.AJaxGetArticle.js
index 71eebd7..9a528da 100644
--- a/botanjs/src/externs/_AstJson_.AJaxGetArticle.js
+++ b/botanjs/src/externs/_AstJson_.AJaxGetArticle.js
@@ -27,6 +27,8 @@ _AstJson_.AJaxGetArticle.entry;
 	_AstJson_.AJaxGetArticle.entry.date_published;
 	/** @type {Array} */
 	_AstJson_.AJaxGetArticle.entry.tags;
+	/** @type {Array} */
+	_AstJson_.AJaxGetArticle.entry.section;
 	/** @type {String} */
 	_AstJson_.AJaxGetArticle.entry.text;
 	/** @type {String} */