penguin/AstroJS

Javascript framework for my blog

botanjs/src/Astro/Blog/Components/Calendar.js

raw ยท 5879 bytes

(function(){
	var ns = __namespace( "Astro.Blog.Components" );

	/** @type {System.Cycle} */
	var Cycle                            = __import( "System.Cycle" );
	/** @type {System.Debug} */
	var debug                            = __import( "System.Debug" );
	/** @type {Dandelion} */
	var Dand                             = __import( "Dandelion" );
	/** @type {Dandelion.IDOMElement} */
	var IDOMElement                      = __import( "Dandelion.IDOMElement" );
	/** @type {Astro.utils.Date} */
	var XDate                            = __import( "Astro.utils.Date" );

	var Calendar = function ()
	{
		this.stage = null;
		this.calDate = null;
		this.show = false;
		this.caption = null;
		this.calDays = false;
		this.currentHandler = function( v ) {
			debug.Info( "[Astro.Blog.Components.Calendar] " + v );
		};
	};

	var bodyClick = function ( e )
	{
		var s = e.target.getAttribute("calObj")
		if(s)
		{
			this.stage.style.display = "none";
			this.stage.style.position = "";
			this.show = false;
		}

		if( this.show && !this.istg.contains( e.target ) )
		{
			this.stage.style.display = "none";
			this.stage.style.position = "";
			this.show = false;
		}
	};

	var addZero = function ( num )
	{
		return num < 10
			? "0" + String(num)
			: String(num)
		;
	};

	Calendar.prototype.init = function()
	{
		this.stage = Dand.wrapc( "astx calendar" );
		this.istg = IDOMElement( this.stage );
		this.calDate = new Date;

		IDOMElement( document.body ).addEventListener( "Click", bodyClick.bind( this ) );

		var tr = Dand.wrap(null, "navbar")
		, td = Dand.wrap("span")
		, btn = Dand.wrap("a", null, "navbtn")
		;
		tr.setAttribute("style", "position: relative");

		btn.onclick = function (e) { this.nextMon(); }.bind(this);

		td.style.textAlign = "right";
		td.style.width = "100%";
		td.style.position = "absolute";
		td.style.left = "0";

		btn.appendChild(Dand.textNode("\u25ba"));

		td.appendChild(btn);
		tr.appendChild(td);

		td = Dand.wrap("span");
		btn = Dand.wrap("a", null, "navbtn");

		btn.appendChild(Dand.textNode("\u25c4"));

		btn.onclick = function (e) { this.prevMon(); }.bind(this);

		td.style["float"] = "left";
		td.style.position = "absolute";

		td.appendChild(btn);
		tr.appendChild(td);

		caption = Dand.wrap("span", null, "calDate");
		caption.style.width = "100%";
		caption.appendChild(
			Dand.textNode(
				XDate.MONTH[this.calDate.getMonth()] + ", " + this.calDate.getFullYear()
			)
		);
		tr.appendChild(caption);

		this.stage.appendChild(tr);

		this.stage.onselectstart = function() { return false;};

		return this.stage;
	};


	Calendar.prototype.pop = function ( dateObj, handler )
	{
		if( typeof( dateObj ) == "string" )
		{
			var p = dateObj.split(",");
			if ( p.length == 3 )
				dateObj = new Date( p[2], p[1] - 1, p[0] );
		}

		this.draw( dateObj, handler );

		this.show = false;

		this.stage.style.display = "block";
		Cycle.next( function (){ this.show = true; }.bind(this) );
	};

	Calendar.prototype.draw = function (dateObj, handler)
	{
		if(!dateObj)
			dateObj = new Date;

		this.calDate = dateObj;

		var mon = dateObj.getMonth()
			, yr = dateObj.getFullYear()
			, j = dateObj.getDay()
			, dt = dateObj.getDate()
			, thisDate = new Date
			, thisYear = thisDate.getFullYear()
			, thisMonth = thisDate.getMonth()
			, thisDate = thisDate.getDate()
			, thisDate = Number(String(thisYear) + addZero(thisMonth) + addZero(thisDate))
			, currHead = String(yr) + addZero(mon)
			, currDate;

		( typeof handler == "function" ) && ( this.currentHandler = handler );

		caption.innerHTML = XDate.MONTH[this.calDate.getMonth()] + ", " + this.calDate.getFullYear();

		if(this.calDays)
			this.calDays.parentElement.removeChild(this.calDays);
		this.calDays = Dand.wrap(null, "calDays");

		var days = (mon == 1) ? (yr % 4 == 0 ? 29: 28) : XDate.CAP_MONTHS[mon] ? 30 : 31;
		for (var i = 0; i < days; i ++)
		{
			if(j < 0)
				j = 6;
			if(dt - i == 1)
			break;
			j --;
		}

		var tr = Dand.wrap(), td;
		for(i = 0; i < 7; i ++)
		{
			td = Dand.wrap("span");
			td.appendChild( Dand.textNode( XDate.DAY_ABBR[i] ) );
			tr.appendChild(td);
		}
		this.calDays.appendChild(tr);

		tr = Dand.wrap();
		for(i = 0; i < j; i ++)
		{
			td = Dand.wrap("span");
			td.style.background = "none";
			tr.appendChild(td);
		}

		i = 0;
		while( i ++ < days )
		{
			currDate = Number(currHead + addZero(i));
			if(j > 6)
			{
				j = 0;
				this.calDays.appendChild(tr);
				tr = Dand.wrap();
			}

			td = Dand.wrap( "span" );
			td.setAttribute( "value", i + "," + (mon + 1) + "," + yr );
			td.setAttribute( "onmouseover", "className=\"onhover\";" );
			td.setAttribute( "onmouseout", "className=\"toNorm\";" );
			// Unique identifier for body click
			// to test whether choice is chosen
			td.setAttribute("calObj", "1");

			td.onclick = function ( e )
			{
				this.currentHandler( e.target.getAttribute("value") );
			}.bind(this);

			if(thisDate < currDate)
			{
				td.setAttribute("id", "notyet");
			}
			else if(thisDate > currDate)
			{
				td.setAttribute("id", "norec");
				/*
					if(!( book[yr] && book[yr][mon + 1] && book[yr][mon + 1][i] )) {
						td.setAttribute("id", "norec");
					} else if(book[yr][mon + 1][i][1]) {
						td.setAttribute("id", "notfin");
					}
				*/
			}
			else if(currDate == thisDate)
			{
				td.setAttribute("id", "today");
				currlabel = td;
			}
			td.appendChild(Dand.textNode(i));
			tr.appendChild(td);
			j ++;
		}

		if(j) this.calDays.appendChild(tr);

		this.stage.appendChild(this.calDays);
	};

	Calendar.prototype.prevMon = function () {
		this.draw( this.calDate = new Date( this.calDate.getFullYear(), this.calDate.getMonth() - 1 ) );
	};

	Calendar.prototype.nextMon = function () {
		this.draw( this.calDate = new Date( this.calDate.getFullYear(), this.calDate.getMonth() + 1 ) );
	};


	ns[ NS_EXPORT ]( EX_CLASS, "Calendar", Calendar );
})();