r77292 MediaWiki - Code Review archive

Repository:MediaWiki
Revision:r77291‎ | r77292 | r77293 >
Date:15:18, 25 November 2010
Author:fde
Status:deferred
Tags:
Comment:
Added new extension Semantic Project Management. Semantic Project Management is an extension to MediaWiki that offers two new
result formats for Semantic MediaWiki's inline queries.
Modified paths:
  • /trunk/extensions/SemanticProjectManagement (added) (history)
  • /trunk/extensions/SemanticProjectManagement/INSTALL (added) (history)
  • /trunk/extensions/SemanticProjectManagement/README (added) (history)
  • /trunk/extensions/SemanticProjectManagement/RELEASE-NOTES (added) (history)
  • /trunk/extensions/SemanticProjectManagement/SemanticProjectManagement.php (added) (history)
  • /trunk/extensions/SemanticProjectManagement/includes (added) (history)
  • /trunk/extensions/SemanticProjectManagement/includes/SPM_Alias.php (added) (history)
  • /trunk/extensions/SemanticProjectManagement/includes/SPM_GanttChart.php (added) (history)
  • /trunk/extensions/SemanticProjectManagement/includes/SPM_Messages.php (added) (history)
  • /trunk/extensions/SemanticProjectManagement/includes/SPM_ProjectManagementClass.php (added) (history)
  • /trunk/extensions/SemanticProjectManagement/includes/SPM_SpecialPage.php (added) (history)
  • /trunk/extensions/SemanticProjectManagement/includes/SPM_WBS.php (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/calendar.css (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/calendar_db.js (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/calendar_eu.js (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/calendar_us.js (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/cal.gif (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/next_mon.gif (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/next_year.gif (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/no_cal.gif (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/pixel.gif (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/prev_mon.gif (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/prev_year.gif (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_bl.png (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_bm.png (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_br.png (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_mr.png (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_tr.png (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/license.txt (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/calendar/readme.txt (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/ganttchart (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/ganttchart/copyright.txt (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/ganttchart/discuss_icon.png (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/ganttchart/jsgantt.css (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/ganttchart/jsgantt.js (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/ganttchart/test.html (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/jscolor (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/jscolor/arrow.gif (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/jscolor/cross.gif (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/jscolor/hs.png (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/jscolor/hv.png (added) (history)
  • /trunk/extensions/SemanticProjectManagement/libs/jscolor/jscolor.js (added) (history)

Diff [purge]

Index: trunk/extensions/SemanticProjectManagement/INSTALL
@@ -0,0 +1,15 @@
 2+== Installation ==
 3+
 4+Installation instructions are available online in a more convenient form for
 5+reading at:
 6+
 7+ http://www.mediawiki.org/wiki/Extension:Semantic_Project_Management
 8+
 9+Copy all files into MediaWiki's extensions folder, either by using SVN or by
 10+extracting an installation package. You need to enter one line to your local
 11+settings (somewhere after the inclusion of Semantic MediaWiki):
 12+
 13+ require_once("$IP/extensions/SemanticProjectManagement/SemanticProjectManagement.php");
 14+
 15+Notes on specific formats:
 16+* ganttchart: requires Javascript to render.
\ No newline at end of file
Index: trunk/extensions/SemanticProjectManagement/RELEASE-NOTES
@@ -0,0 +1,9 @@
 2+For a documentation of all features, see
 3+http://www.mediawiki.org/wiki/Extension:Semantic_Project_Management
 4+
 5+== Semantic Project Management 1.5 beta ==
 6+
 7+Released on XXX.
 8+
 9+Initial release (the numbering is in order to be consistent with SMW core. Note
 10+that this does not state anything about the stability of the software).
\ No newline at end of file
Index: trunk/extensions/SemanticProjectManagement/includes/SPM_WBS.php
@@ -0,0 +1,209 @@
 2+<?php
 3+/*******************************************************************************
 4+ *
 5+ * Copyright (c) 2010 Frank Dengler, Jonas Bissinger
 6+ *
 7+ * Semantic Project Management is free software: you can redistribute it and/or modify
 8+ * it under the terms of the GNU General Public License as published by
 9+ * the Free Software Foundation, either version 3 of the License, or
 10+ * (at your option) any later version.
 11+ *
 12+ * Semantic Project Management is distributed in the hope that it will be useful,
 13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15+ * GNU General Public License for more details.
 16+ *
 17+ * You should have received a copy of the GNU General Public License
 18+ * along with Semantic Project Management. If not, see <http://www.gnu.org/licenses/>.
 19+ *******************************************************************************/
 20+
 21+if( !defined( 'MEDIAWIKI' ) ) {
 22+ die( 'Not an entry point.' );
 23+}
 24+
 25+/**
 26+ *
 27+ * @author Frank Dengler, Jonas Bissinger
 28+ *
 29+ * @ingroup SemanticProjectManagement
 30+ *
 31+ */
 32+
 33+
 34+class SPMWBS extends SMWResultPrinter {
 35+ protected $m_projectmanagementclass;
 36+
 37+
 38+ protected function readParameters($params,$outputmode) {
 39+
 40+ SMWResultPrinter::readParameters($params,$outputmode);
 41+
 42+ // init breakdown instance
 43+ $this->m_projectmanagementclass = new ProjectManagementClass();
 44+ $this->m_projectmanagementclass->setInternals();
 45+
 46+ }
 47+ public function getMimeType($res) {
 48+ return 'text/xml';
 49+ }
 50+
 51+ public function getFileName($res) {
 52+ if ($this->getSearchLabel(SMW_OUTPUT_WIKI) != '') {
 53+ return str_replace(' ', '_',$this->getSearchLabel(SMW_OUTPUT_WIKI)) . '.xml';
 54+ } else {
 55+ return 'MSProject.xml';
 56+ }
 57+ }
 58+
 59+ public function getQueryMode($context) {
 60+ return ($context==SMWQueryProcessor::SPECIAL_PAGE)?SMWQuery::MODE_INSTANCES:SMWQuery::MODE_NONE;
 61+ }
 62+
 63+ public function getName() {
 64+ wfLoadExtensionMessages('SemanticProjectManagement');
 65+ return wfMsg('spm_printername_wbs');
 66+ }
 67+
 68+
 69+
 70+ /**
 71+ * This method renders the result set provided by SMW according to the printer
 72+ *
 73+ * @param res SMWQueryResult, result set of the ask query provided by SMW
 74+ * @param outputmode ?
 75+ * @returns String, rendered HTML output of this printer for the ask-query
 76+ *
 77+ */
 78+ protected function getResultText($res, $outputmode) {
 79+ global $wgContLang; // content language object
 80+ $result = '';
 81+ $m_outlineLevel= 0;
 82+ $hasChildren=array();
 83+ $m_outlineLevel++;
 84+ $m_seedCategory = "";
 85+ $m_seedName = "";
 86+ $m_categories = $this->m_projectmanagementclass->getCategories();
 87+ $m_properties = $this->m_projectmanagementclass->getProperties();
 88+ if ($outputmode == SMW_OUTPUT_FILE) {
 89+
 90+ $queryparts = preg_split("/]]/", $res->getQueryString());
 91+ $taskname = str_replace("[[","",$queryparts[0]);
 92+
 93+ if ((strpos($taskname,"Category:") === false)){
 94+
 95+ //case: [[{{PAGENAME}}]]
 96+ if (($res->getCount() == 1)){
 97+
 98+ $m_seedName = trim(str_replace("[[","",str_replace("]]","",$res->getQueryString())));
 99+ $firstQuery = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[['.$m_seedName.']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 100+ //$firstQuery = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[[Part of::'.$m_seedName.']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 101+
 102+ }
 103+ else {
 104+ return "<html><body>ERROR: Query: ".$res->getQueryString()."is invalid! Valid formats: [[Category:SampleCategory]] or: [[{{PAGENAME}}]]</body></html>";
 105+ }
 106+ }
 107+
 108+ //case: [[Category:SampleCategory]]
 109+ else {
 110+ $m_seedCategory = trim(str_replace("Category:","",$taskname));
 111+
 112+ if (in_array($m_seedCategory,$m_categories)){
 113+
 114+ $firstQuery = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[[Category:'.$m_seedCategory.']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 115+
 116+ }
 117+ else {
 118+ return "<html><body>ERROR: Category: ".$m_seedCategory." has not been defined on Special:SemanticProjectManagement </body></html>";
 119+ }
 120+ }
 121+
 122+ $this->m_projectmanagementclass->setName("ProjectManagementClass");
 123+
 124+
 125+ // echo "First Query: ".$firstQuery->getQueryString()."<br/>";
 126+
 127+ //generate seed task
 128+
 129+ $task = $this->m_projectmanagementclass->makeTask("seed",0);
 130+ $task->addWBS(0,0);
 131+ $task->setUid(0);
 132+
 133+ $hasChildren = $this->m_projectmanagementclass->getTaskResults($firstQuery,$outputmode, $m_outlineLevel, $task);
 134+
 135+ $processedChildren = array();
 136+ $hasChild=true;
 137+ while ($hasChild){
 138+ $hasChild = false;
 139+ $allTempChildren = array();
 140+ $m_outlineLevel++;
 141+
 142+ foreach ($hasChildren as $child){
 143+
 144+ if (in_array($child,$processedChildren)){
 145+
 146+ } else {
 147+
 148+
 149+ if ((isset($m_properties[$child->getLevel()])) && isset($m_categories[$child->getLevel()])) {
 150+
 151+ //build new Query
 152+ if ($child->getLevel() != 0)
 153+ $res2 = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[[Category:'.$m_categories[$child->getLevel()].']] [['.$m_properties[$child->getLevel()].'::'.$child->getPage().']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 154+ else {
 155+ if (isset($m_properties[1])) $res2 = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[[Category:'.$m_categories[0].']] [['.$m_properties[1].'::'.$child->getPage().']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 156+ else $res2 = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[['.$child->getPage().']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 157+ }
 158+
 159+
 160+ // echo "Next Query: ".$res2->getQueryString()." Level: ".$m_outlineLevel."<br/>";
 161+
 162+ $queryresults = $this->m_projectmanagementclass->getTaskResults($res2, $outputmode, $m_outlineLevel,$child);
 163+ $processedChildren[] = $child;
 164+ foreach ($queryresults as $temp)
 165+ $allTempChildren[] = $temp;
 166+ }
 167+
 168+ }
 169+ }
 170+
 171+ $hasChildren = $allTempChildren;
 172+ if (count($hasChildren)>0)
 173+ $hasChild = true;
 174+ }
 175+
 176+ $task->addWBS(1,0);
 177+
 178+
 179+ $result .= $this->m_projectmanagementclass->getXML();
 180+
 181+ } else { // just make xml file
 182+ if ($this->getSearchLabel($outputmode)) {
 183+ $label = $this->getSearchLabel($outputmode);
 184+ } else {
 185+ wfLoadExtensionMessages('SemanticProjectManagement');
 186+ $label = wfMsgForContent('spm_wbs_link');
 187+ }
 188+ $link = $res->getQueryLink($label);
 189+ $link->setParameter('wbs','format');
 190+ if ($this->getSearchLabel(SMW_OUTPUT_WIKI) != '') {
 191+ $link->setParameter($this->getSearchLabel(SMW_OUTPUT_WIKI),'searchlabel');
 192+ }
 193+ if (array_key_exists('limit', $this->m_params)) {
 194+ $link->setParameter($this->m_params['limit'],'limit');
 195+ } else { // use a reasonable default limit
 196+ $link->setParameter(500,'limit');
 197+ }
 198+ $result .= $link->getText($outputmode,$this->mLinker);
 199+ $this->isHTML = ($outputmode == SMW_OUTPUT_HTML); // yes, our code can be viewed as HTML if requested, no more parsing needed
 200+
 201+ // make xml file
 202+
 203+
 204+
 205+ }
 206+ return $result;
 207+
 208+
 209+ }
 210+}
\ No newline at end of file
Index: trunk/extensions/SemanticProjectManagement/includes/SPM_SpecialPage.php
@@ -0,0 +1,440 @@
 2+<?php
 3+/*******************************************************************************
 4+ *
 5+ * Copyright (c) 2010 Jonas Bissinger
 6+ *
 7+ * Semantic Project Management is free software: you can redistribute it and/or modify
 8+ * it under the terms of the GNU General Public License as published by
 9+ * the Free Software Foundation, either version 3 of the License, or
 10+ * (at your option) any later version.
 11+ *
 12+ * Semantic Project Management is distributed in the hope that it will be useful,
 13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15+ * GNU General Public License for more details.
 16+ *
 17+ * You should have received a copy of the GNU General Public License
 18+ * along with Semantic Project Management. If not, see <http://www.gnu.org/licenses/>.
 19+ *******************************************************************************/
 20+
 21+/**
 22+ *
 23+ * @author Jonas Bissinger
 24+ *
 25+ * @ingroup SemanticProjectManagement
 26+ *
 27+ */
 28+
 29+class SemanticProjectManagement extends SpecialPage
 30+{
 31+
 32+
 33+ /**
 34+ * Constructor
 35+ */
 36+ function __construct() {
 37+ parent::__construct( 'SemanticProjectManagement' );
 38+ wfLoadExtensionMessages( 'SemanticProjectManagement' );
 39+ }
 40+ //main class
 41+ function execute( $par ){
 42+
 43+ global $wgRequest,$wgOut,$wgUser;
 44+
 45+ $page = 0;
 46+ $this->setHeaders();
 47+
 48+ //check if user is allowed to access special page
 49+ if ( ! $wgUser->isAllowed('SPMsetup') ) {
 50+ $wgOut->permissionRequired('SPMsetup');
 51+ return;
 52+ }
 53+
 54+ if ($wgRequest->getCheck('page2')) {
 55+ $page = 2;
 56+
 57+ $levels = $wgRequest->getVal('level');
 58+ if ($levels == "") $levels = 1;
 59+ $text = self::getPage1Text($levels);
 60+ }
 61+
 62+ if ($wgRequest->getCheck('page3')) {
 63+ $page = 3;
 64+ $levels = $wgRequest->getVal('level');
 65+ if ($wgRequest->getVal('allSame')=="on") $allSame = 1;
 66+ else $allSame = 0;
 67+ $text = self::getPage2Text($levels,$allSame);
 68+
 69+ }
 70+
 71+ if ($wgRequest->getCheck('calendar')) {
 72+ $page = 4;
 73+ $date = $wgRequest->getVal('startmonth');
 74+ $text = self::getCalendarText($date);
 75+
 76+ }
 77+
 78+
 79+ if (($page == 0)||($wgRequest->getCheck('page1')||($wgRequest->getCheck('page1refresh')) ||($wgRequest->getCheck('calendarRefresh')))) {
 80+ $page = 1;
 81+ $text = self::getPage0Text();
 82+ }
 83+
 84+ $wgOut->addHTML($text);
 85+
 86+ }
 87+
 88+
 89+ function writeSetupData($level,$m0,$allSame,$cat,$props,$colors){
 90+
 91+ //structure: levels{**}M0{**}$allSame{**}cat[0]{**}color[0]{**}property[0]{**}cat[1]...
 92+
 93+ $newtext = "This page is used to store the settings of the Semantic Project Management Extension.<br/><br/>Do not delete or edit this page. To change the settings, please go to: [[Special:SemanticProjectManagement]].<!--";
 94+ $newtext .= $level."{**}".$m0."{**}".$allSame."{**}";
 95+
 96+ for ($i = 0; $i<$level; $i++){
 97+ $newtext .= $cat[$i]."{**}".$colors[$i]."{**}".$props[$i]."{**}";
 98+ }
 99+
 100+ $newtext .= "-->";
 101+
 102+ $title = Title::newFromText("SPM_Setup");
 103+ $article = new Article($title);
 104+ $article->doEdit($newtext, "settings change", EDIT_UPDATE);
 105+
 106+ }
 107+
 108+ function getSetupData(){
 109+
 110+ //get values from SPM_setup
 111+ $title = Title::newFromText("SPM_Setup");
 112+ $article = new Article($title);
 113+ $wikitext = $article->getContent();
 114+
 115+ $pos1 = strpos($wikitext,"<!--");
 116+ $pos2 = strpos($wikitext,"-->");
 117+ $data = substr($wikitext,$pos1+4,$pos2-$pos1-4);
 118+
 119+ $textarr = explode("{**}",$data);
 120+ $levels = (int) $textarr[0];
 121+
 122+
 123+ //check if data on SPM_setup is valid
 124+ //todo: better check!
 125+ //echo "SIZE: ".(sizeof($textarr))."<br/>";
 126+ if ((3*$levels) != (sizeof($textarr)-4)) return false;
 127+ return $textarr;
 128+
 129+ }
 130+
 131+ //checks if all values in an array are different
 132+ function checkAllDifferent($arr){
 133+
 134+ $check = array();
 135+ for ($i = 0;$i<sizeof($arr);$i++){
 136+ if (isset($check[$arr[$i]])) return false;
 137+ else $check[$arr[$i]] = 1;
 138+ }
 139+ return true;
 140+ }
 141+
 142+ //checks if all values in an array are identical
 143+ function checkAllSame($arr){
 144+ for ($i = 1;$i<sizeof($arr);$i++){
 145+ if ($arr[0] != $arr[$i]) return false;
 146+ }
 147+ return true;
 148+ }
 149+
 150+
 151+ function getPage0Text(){
 152+
 153+ global $wgRequest;
 154+
 155+ $startmonth = "";
 156+ $setting = "";
 157+
 158+ if ($wgRequest->getCheck('calendarRefresh')){
 159+ $startmonth = $wgRequest->getVal('testinput');
 160+ }
 161+
 162+ //page is reached after changes have been made
 163+ if ($wgRequest->getCheck('page1refresh')){
 164+
 165+ $arr = self::getSetupData();
 166+ $m0 = $arr[1];
 167+ $allSame = $arr[2];
 168+
 169+ //echo "loaded m0: ".$m0;
 170+
 171+ $l = $wgRequest->getVal('level');
 172+
 173+ $cat = array();
 174+ $col = array();
 175+ $prop = array();
 176+
 177+ for ($i = 1; $i<=$l; $i++){
 178+
 179+ $cat[$i-1] = $wgRequest->getVal('category'.$i);
 180+ $col[$i-1] = $wgRequest->getVal('color'.$i);
 181+ $prop[$i-1] = $wgRequest->getVal('property'.$i);
 182+ }
 183+
 184+ $allSame = $wgRequest->getVal('allSame');
 185+
 186+ $valid = true;
 187+ $error = "";
 188+
 189+ if ($allSame == 1) {
 190+ $valid = (self::checkAllSame($cat))&&(self::checkAllSame(array_slice($prop,1)));
 191+ $error = "<br/> <b> <font color=\"#FF0000\"> Invalid setting! </font> </b> All categories/properties have to be identical <br/> <br/>";
 192+ }
 193+ if ($allSame == 0){
 194+ $valid = self::checkAllDifferent($cat);
 195+ $error = "<br/> <b> <font color=\"#FF0000\"> Invalid setting! </font> </b> All categories have to be different! <br/> <br/>";
 196+ }
 197+
 198+ if ($valid) self::writeSetupData($l,$m0,$allSame,$cat,$prop,$col);
 199+ else $setting .= $error;
 200+
 201+ }
 202+
 203+ //page is reached after m0 has been changed
 204+ if ($wgRequest->getCheck('calendarRefresh')){
 205+ $startmonth = $wgRequest->getVal('testinput');
 206+
 207+ $arr = self::getSetupData();
 208+
 209+ $arr[1] = $startmonth;
 210+ $result = implode("{**}",$arr);
 211+
 212+ $newtext = "This page is used to store the settings of the Semantic Project Management Extension.<br/><br/>Do not delete or edit this page. To change the settings, please go to: [[Special:SemanticProjectManagement]].<!--";
 213+ $newtext .= $result;
 214+ $newtext .= "-->";
 215+
 216+
 217+ //save SPM_Setup with new m0
 218+ $title = Title::newFromText("SPM_Setup");
 219+ $article = new Article($title);
 220+
 221+ $article->doEdit($newtext , "startmonth change");
 222+ }
 223+
 224+
 225+ //check if data is valid
 226+ if (self::getSetupData() == false) {
 227+
 228+ //fill SPM_Setup with default values
 229+ $title = Title::newFromText("SPM_Setup");
 230+ $article = new Article($title);
 231+ $defaultText = "This page is used to store the settings of the Semantic Project Management Extension.<br/><br/>Do not delete or edit this page. To change the settings, please go to: [[Special:SemanticProjectManagement]].<!--3{**}06/01/2009{**}false{**}Work Package{**}FF0000{**}{**}Task{**}FFEE05{**}Part of{**}Deliverable{**}09FF00{**}Part of{**}-->";
 232+ $article->doEdit($defaultText , "default restored");
 233+
 234+ //create error message
 235+ $setting .= " <br/> <b> <font color=\"#FF0000\"> Invalid setting! </font> </b> <br/> Default setting restored! <br/><br/>";
 236+ }
 237+
 238+
 239+ //data is valid
 240+ $textarr = self::getSetupData();
 241+ $levels = $textarr[0];
 242+ $m0 = $textarr[1];
 243+ $allSame = $textarr[2];
 244+ $setting .= " <b> Current Setting: </b> <br/> <br/> <table border = \"0\" cellpadding=\"3\" cellspacing=\"5\"><tr bgcolor = \"#A3D5E4\"><th>Level</th><th>Category</th><th>Color</th><th>Property</th><tr>";
 245+ for ($i = 0; $i < $levels; $i++){
 246+ $triple = array_splice($textarr,3,3);
 247+
 248+ if ($triple[2] == "") $triple[2] = "-";
 249+ $setting .= "<tr> <td align=\"center\">".($i+1)."</td> <td>".$triple[0]."</td> <td width=\"100\" bgcolor=\"#".$triple[1]."\" height=\"21\"></td> <td td align=\"center\">".$triple[2]." </td></tr>";
 250+
 251+ }
 252+
 253+ $setting .= "</table>";
 254+
 255+
 256+ $text =<<<END
 257+<html>
 258+<head>
 259+
 260+</head>
 261+<body>
 262+
 263+ $setting
 264+ <br/>
 265+ <br/>
 266+ <b> Project Start Month (M0): $m0 </b>
 267+ <br/>
 268+ <br/>
 269+ <form enctype="multipart/form-data" action="" method="post" name="page0">
 270+<input type="hidden" name="level" value="$levels">
 271+<input type="hidden" name="startmonth" value="$m0">
 272+ <p><input type="Submit" name="page2" value="Change Setting"><input type="Submit" name="calendar" value="Change Startmonth"></p>
 273+
 274+ </form>
 275+</body>
 276+END;
 277+
 278+ return $text;
 279+ }
 280+
 281+
 282+ function getCalendarText($date){
 283+
 284+ global $spmgScriptPath;
 285+
 286+ $text =<<<END
 287+
 288+<html>
 289+<head>
 290+ <link rel="stylesheet" type="text/css" href="$spmgScriptPath/libs/calendar/calendar.css" />
 291+ <script language="javascript" src="$spmgScriptPath/libs/calendar/calendar_us.js"></script>
 292+
 293+</head>
 294+<body>
 295+
 296+Please enter Project Startmonth (M0):
 297+
 298+<form name="testform" enctype="multipart/form-data" action="" method="post">
 299+
 300+ <input type="text" name="testinput" value="$date" />
 301+ <script language="javascript">
 302+ var A_CALTPL = {
 303+ 'months' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
 304+ 'weekdays' : ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
 305+ 'yearscroll': true, // show year scroller
 306+ 'weekstart': 0, // first day of week: 0-Su or 1-Mo
 307+ 'centyear' : 70, // 2 digit years less than 'centyear' are in 20xx, othewise in 19xx.
 308+ 'imgpath' : '$spmgScriptPath/libs/calendar/img/'
 309+ }
 310+ new tcal ({
 311+ 'formname': 'testform',
 312+ 'controlname': 'testinput'},
 313+
 314+ A_CALTPL);
 315+ </script>
 316+
 317+
 318+<p><input type="Submit" name="calendarRefresh" value="Save"><input type="Submit" name="page0" value="Cancel"></p>
 319+</form>
 320+
 321+
 322+</body>
 323+</html>
 324+END;
 325+
 326+ return $text;
 327+
 328+ }
 329+
 330+
 331+ function getPage1Text($levels){
 332+
 333+ $checkbox = "";
 334+
 335+ //$checkbox = "<p><input type=\"checkbox\" name=\"allSame\"> All Levels have same Category/Property </p>";
 336+ //uncomment last line to enable allSame checkbox
 337+
 338+ $s = array("","","","","","","","","","");
 339+ $s[$levels] = "selected";
 340+
 341+ $text =<<<END
 342+
 343+<form enctype="multipart/form-data" action="" method="post">
 344+<p>Please select number of levels:
 345+<select name="level">
 346+ <option value="1" $s[1]>1</option>
 347+ <option value="2" $s[2]>2</option>
 348+ <option value="3" $s[3]>3</option>
 349+ <option value="4" $s[4]>4</option>
 350+ <option value="5" $s[5]>5</option>
 351+ <option value="6" $s[6]>6</option>
 352+ <option value="7" $s[7]>7</option>
 353+ <option value="8" $s[8]>8</option>
 354+ <option value="9" $s[9]>9</option>
 355+ </select>
 356+$checkbox
 357+<p><input type="Submit" name="page3" value="Continue"><input type="Submit" name="page0" value="Cancel"></p>
 358+</form>
 359+
 360+END;
 361+
 362+ return $text;
 363+ }
 364+
 365+ function getPage2Text($levels,$allSame){
 366+
 367+ global $spmgScriptPath;
 368+
 369+ //echo " allSame:".$allSame."<br/>";
 370+
 371+ if (self::getSetupData() != false) $textarr = self::getSetupData();
 372+ else return "<br/> Internal error: Please reload Special:SemanticProjectManagement <br/>";
 373+
 374+
 375+ $l = $textarr[0];
 376+ $text =<<<END
 377+
 378+<html>
 379+<head>
 380+<script type="text/javascript" src="$spmgScriptPath/libs/jscolor/jscolor.js"></script>
 381+</head>
 382+<body>
 383+<form enctype="multipart/form-data" action="" method="post" name="page2">
 384+<table>
 385+<tr>
 386+END;
 387+
 388+
 389+ for ( $i = 0; $i < $levels; $i += 1) {
 390+
 391+ $triple = array_splice($textarr,3,3);
 392+
 393+ if ($i < $l) $text .= self::generateLevelBox($i+1, $triple[0], $triple[2], $triple[1]);
 394+ else $text .= self::generateLevelBox($i+1, "", "", "", "ffffff", 0);
 395+
 396+ if (($i+1)%4 == 0) {
 397+ $text.= "</tr> <tr>";
 398+ }
 399+ }
 400+
 401+ $text .=<<<END
 402+</tr>
 403+</table>
 404+<input type="hidden" name="allSame" value="$allSame">
 405+<input type="hidden" name="level" value="$levels">
 406+<p><input type="Submit" name="page1refresh" value="Save"><input type="Submit" name="page0" value="Cancel"></p>
 407+</form>
 408+</body>
 409+</html>
 410+END;
 411+
 412+ return $text;
 413+ }
 414+
 415+ function generateLevelBox($index, $category, $property, $color){
 416+
 417+ $low = $index-1;
 418+ $propbox = "";
 419+ if ($low != 0) $propbox ="<p> Connecting Property to Level $low: <input style=\"width: 100%;\" type=\"text\" name=\"property$index\" value=\"$property\"/></p>";
 420+
 421+ $text =<<<END
 422+<td>
 423+<fieldset style="width: 220px;">
 424+<legend>
 425+Level $index
 426+</legend>
 427+<p> Category: <input style="width: 100%;" type="text" name="category$index" value="$category"/> </p>
 428+
 429+<p> Color: <input style="width: 100%;" class="color" name="color$index" value="$color"/></p>
 430+
 431+$propbox
 432+</fieldset>
 433+<td>
 434+
 435+END;
 436+
 437+ return $text;
 438+
 439+ }
 440+
 441+}
\ No newline at end of file
Index: trunk/extensions/SemanticProjectManagement/includes/SPM_GanttChart.php
@@ -0,0 +1,193 @@
 2+<?php
 3+/*******************************************************************************
 4+ *
 5+ * Copyright (c) 2010 Frank Dengler, Jonas Bissinger
 6+ *
 7+ * Semantic Project Management is free software: you can redistribute it and/or modify
 8+ * it under the terms of the GNU General Public License as published by
 9+ * the Free Software Foundation, either version 3 of the License, or
 10+ * (at your option) any later version.
 11+ *
 12+ * Semantic Project Management is distributed in the hope that it will be useful,
 13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15+ * GNU General Public License for more details.
 16+ *
 17+ * You should have received a copy of the GNU General Public License
 18+ * along with Semantic Project Management. If not, see <http://www.gnu.org/licenses/>.
 19+ *******************************************************************************/
 20+
 21+if( !defined( 'MEDIAWIKI' ) ) {
 22+ die( 'Not an entry point.' );
 23+}
 24+
 25+/**
 26+ *
 27+ * @author Frank Dengler, Jonas Bissinger
 28+ *
 29+ * @ingroup SemanticProjectManagement
 30+ *
 31+ */
 32+
 33+
 34+class SPMGanttChart extends SMWResultPrinter {
 35+
 36+ protected $m_projectmanagementclass;
 37+
 38+
 39+ //constructor
 40+ protected function readParameters($params,$outputmode) {
 41+
 42+ SMWResultPrinter::readParameters($params,$outputmode);
 43+ $this->m_projectmanagementclass = new ProjectManagementClass();
 44+
 45+ //set display options for Gantt-chart
 46+ if (array_key_exists('showdiscussion', $params)) {
 47+ if (self::isTrue($params['showdiscussion'])) $this->m_projectmanagementclass->setShowDiscussion(true);
 48+ }
 49+
 50+ if (array_key_exists('showresponsible', $params)) {
 51+ if (self::isTrue($params['showresponsible'])) $this->m_projectmanagementclass->setShowResponsible(true);
 52+ }
 53+
 54+ if (array_key_exists('showduration', $params)) {
 55+ if (self::isTrue($params['showduration'])) $this->m_projectmanagementclass->setShowDuration(true);
 56+ }
 57+
 58+ if (array_key_exists('showcompleteness', $params)) {
 59+ if (self::isTrue($params['showcompleteness'])) $this->m_projectmanagementclass->setShowComplete(true);
 60+ }
 61+
 62+ if (array_key_exists('showstartdate', $params)) {
 63+ if (self::isTrue($params['showstartdate'])) $this->m_projectmanagementclass->setShowStartdate(true);
 64+ }
 65+
 66+ if (array_key_exists('showenddate', $params)) {
 67+ if (self::isTrue($params['showenddate'])) $this->m_projectmanagementclass->setShowEnddate(true);
 68+ }
 69+
 70+
 71+
 72+ $this->m_projectmanagementclass->setInternals();
 73+
 74+ }
 75+ public static function isTrue($value){
 76+ $res = false;
 77+ if ((strtolower(trim($value))=='yes') || (strtolower(trim($value)) == 'true')) $res = true;
 78+ return $res;
 79+ }
 80+
 81+ /**
 82+ * This method renders the result set provided by SMW according to the printer
 83+ *
 84+ * @param res SMWQueryResult, result set of the ask query provided by SMW
 85+ * @param outputmode ?
 86+ * @returns String, rendered HTML output of this printer for the ask-query
 87+ *
 88+ */
 89+ protected function getResultText($res, $outputmode) {
 90+ global $wgContLang; // content language object
 91+
 92+ $this->isHTML = true;
 93+
 94+ $result = '';
 95+ $m_outlineLevel= 0;
 96+ $hasChildren=array();
 97+ $m_outlineLevel++;
 98+ $m_seedCategory = "";
 99+ $m_seedName = "";
 100+ $m_categories = $this->m_projectmanagementclass->getCategories();
 101+ $m_properties = $this->m_projectmanagementclass->getProperties();
 102+ $queryparts = preg_split("/]]/", $res->getQueryString());
 103+ $taskname = str_replace("[[","",$queryparts[0]);
 104+
 105+ if ((strpos($taskname,"Category:") === false)){
 106+
 107+ //case: [[{{PAGENAME}}]]
 108+ if (($res->getCount() == 1)){
 109+
 110+ $m_seedName = trim(str_replace("[[","",str_replace("]]","",$res->getQueryString())));
 111+ $firstQuery = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[['.$m_seedName.']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 112+ //$firstQuery = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[[Part of::'.$m_seedName.']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 113+
 114+ }
 115+ else {
 116+ return "<html><body>ERROR: Query: ".$res->getQueryString()."is invalid! Valid formats: [[Category:SampleCategory]] or: [[{{PAGENAME}}]]</body></html>";
 117+ }
 118+ }
 119+
 120+ //case: [[Category:SampleCategory]]
 121+ else {
 122+ $m_seedCategory = trim(str_replace("Category:","",$taskname));
 123+
 124+ if (in_array($m_seedCategory,$m_categories)){
 125+
 126+ $firstQuery = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[[Category:'.$m_seedCategory.']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 127+
 128+ }
 129+ else {
 130+ return "<html><body>ERROR: Category: ".$m_seedCategory." has not been defined on Special:SemanticProjectManagement </body></html>";
 131+ }
 132+ }
 133+
 134+ $this->m_projectmanagementclass->setName("ProjectManagementClass");
 135+
 136+
 137+ // echo "First Query: ".$firstQuery->getQueryString()."<br/>";
 138+
 139+ //generate seed task
 140+
 141+ $task = $this->m_projectmanagementclass->makeTask("seed",0);
 142+ $task->addWBS(0,0);
 143+ $task->setUid(0);
 144+
 145+ $hasChildren = $this->m_projectmanagementclass->getTaskResults($firstQuery,$outputmode, $m_outlineLevel, $task);
 146+
 147+ $processedChildren = array();
 148+ $hasChild=true;
 149+ while ($hasChild){
 150+ $hasChild = false;
 151+ $allTempChildren = array();
 152+ $m_outlineLevel++;
 153+
 154+ foreach ($hasChildren as $child){
 155+
 156+ if (in_array($child,$processedChildren)){
 157+
 158+ } else {
 159+
 160+
 161+ if ((isset($m_properties[$child->getLevel()])) && isset($m_categories[$child->getLevel()])) {
 162+
 163+ //build new Query
 164+ if ($child->getLevel() != 0)
 165+ $res2 = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[[Category:'.$m_categories[$child->getLevel()].']] [['.$m_properties[$child->getLevel()].'::'.$child->getPage().']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 166+ else {
 167+ if (isset($m_properties[1])) $res2 = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[[Category:'.$m_categories[0].']] [['.$m_properties[1].'::'.$child->getPage().']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 168+ else $res2 = smwfGetStore()->getQueryResult(SMWQueryProcessor::createQuery('[['.$child->getPage().']]',array(),SMWQueryProcessor::INLINE_QUERY,'',$res->getPrintRequests()));
 169+ }
 170+
 171+
 172+ // echo "Next Query: ".$res2->getQueryString()." Level: ".$m_outlineLevel."<br/>";
 173+
 174+ $queryresults = $this->m_projectmanagementclass->getTaskResults($res2, $outputmode, $m_outlineLevel,$child);
 175+ $processedChildren[] = $child;
 176+ foreach ($queryresults as $temp)
 177+ $allTempChildren[] = $temp;
 178+ }
 179+
 180+ }
 181+ }
 182+
 183+ $hasChildren = $allTempChildren;
 184+ if (count($hasChildren)>0)
 185+ $hasChild = true;
 186+ }
 187+
 188+ $task->addWBS(1,0);
 189+ $result .= $this->m_projectmanagementclass->getGanttChart();
 190+ return $result;
 191+
 192+
 193+ }
 194+}
\ No newline at end of file
Index: trunk/extensions/SemanticProjectManagement/includes/SPM_Messages.php
@@ -0,0 +1,23 @@
 2+<?php
 3+/**
 4+ * Internationalization file for the Semantic Project Management extension
 5+ *
 6+ * @addtogroup Extensions
 7+*/
 8+
 9+// FIXME: Can be enabled when new style magic words are used (introduced in r52503)
 10+// require_once( dirname( __FILE__ ) . '/SRF_Magic.php' );
 11+
 12+$messages = array();
 13+
 14+/** English
 15+ */
 16+$messages['en'] = array(
 17+
 18+ 'spm_wbs_link' => 'MS Project XML export',
 19+ 'spm_printername_wbs' => 'MS Project export',
 20+ 'spm-name' => 'Semantic Project Management',
 21+ 'spm-desc' => 'Project Management Formats for Semantic MediaWiki inline queries',
 22+ 'semanticprojectmanagement-desc' => 'Project Management Formats for Semantic MediaWiki inline queries',
 23+ 'semanticprojectmanagement' => 'Semantic Project Management'
 24+);
Index: trunk/extensions/SemanticProjectManagement/includes/SPM_Alias.php
@@ -0,0 +1,12 @@
 2+<?php
 3+/**
 4+ * Alias file for the Semantic Project Management extension
 5+ *
 6+ * @addtogroup Extensions
 7+*/
 8+$aliases = array();
 9+
 10+/** English */
 11+$aliases['en'] = array(
 12+ 'SemanticProjectManagement' => array( 'SemanticProjectManagement' ),
 13+);
Index: trunk/extensions/SemanticProjectManagement/includes/SPM_ProjectManagementClass.php
@@ -0,0 +1,1825 @@
 2+<?php
 3+/*******************************************************************************
 4+ *
 5+ * Copyright (c) 2010 Frank Dengler, Jonas Bissinger
 6+ *
 7+ * Semantic Project Management is free software: you can redistribute it and/or modify
 8+ * it under the terms of the GNU General PIFublic License as published by
 9+ * the Free Software Foundation, either version 3 of the License, or
 10+ * (at your option) any later version.
 11+ *
 12+ * Semantic Project Management is distributed in the hope that it will be useful,
 13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15+ * GNU General Public License for more details.
 16+ *
 17+ * You should have received a copy of the GNU General Public License
 18+ * along with Semantic Project Management. If not, see <http://www.gnu.org/licenses/>.
 19+ *******************************************************************************/
 20+
 21+/**
 22+ *
 23+ * @author Frank Dengler, Jonas Bissinger
 24+ *
 25+ * @ingroup SemanticProjectManagement
 26+ *
 27+ */
 28+
 29+if( !defined( 'MEDIAWIKI' ) ) {
 30+ die( 'Not an entry point.' );
 31+}
 32+
 33+class ProjectManagementClass{
 34+
 35+ //general variables
 36+ protected $m_name = "";
 37+ private $m_title = "";
 38+ protected $m_tasks = array();
 39+ protected $m_resources = array();
 40+ protected $m_startDate = null;
 41+ protected $m_id = 1;
 42+ protected $m_errors = array();
 43+
 44+ //variables for Gantt-Chart
 45+ //display options
 46+ protected $m_showDiscussion = false;
 47+ protected $m_showResponsible = false;
 48+ protected $m_showDuration = false;
 49+ protected $m_showComplete = false;
 50+ protected $m_showStartdate = false;
 51+ protected $m_showEnddate = false;
 52+ //TODO: implement Caption, DateInputFormat, DateDisplayFormat, FormatArr
 53+
 54+ //settings from SpecialPage
 55+ protected $m_categories = array();
 56+ protected $m_colors = array();
 57+ protected $m_properties = array();
 58+ protected $m_m0 = ""; //startmonth (M0) for M-notation
 59+ protected $m_allSame = false; //true if all categories are identical
 60+
 61+ //getters and setters
 62+ public function setTitle($title){
 63+ $this->m_title = $title;
 64+ }
 65+
 66+ public function getTitle(){
 67+ return $this->m_title;
 68+ }
 69+
 70+ public function setName($name){
 71+ $this->m_name = $name;
 72+ }
 73+
 74+ public function getName(){
 75+ return $this->m_name;
 76+ }
 77+
 78+ public function getShowResponsible(){
 79+ return $this->m_showResponsible;
 80+ }
 81+
 82+ public function setShowResponsible($show){
 83+ $this->m_showResponsible = $show;
 84+ }
 85+
 86+ public function getShowDiscussion(){
 87+ return $this->m_showDiscussion;
 88+ }
 89+
 90+ public function setShowDiscussion($show){
 91+ $this->m_showDiscussion = $show;
 92+ }
 93+
 94+ public function getShowDuration(){
 95+ return $this->m_showDuration;
 96+ }
 97+
 98+ public function setShowDuration($show){
 99+ $this->m_showDuration = $show;
 100+ }
 101+
 102+ public function getShowComplete(){
 103+ return $this->m_showComplete;
 104+ }
 105+
 106+ public function setShowComplete($show){
 107+ $this->m_showComplete = $show;
 108+ }
 109+
 110+ public function getShowStartdate(){
 111+ return $this->m_showStartdate;
 112+ }
 113+
 114+ public function setShowStartdate($show){
 115+ $this->m_showStartdate = $show;
 116+ }
 117+
 118+ public function getShowEnddate(){
 119+ return $this->m_showEnddate;
 120+ }
 121+
 122+ public function setShowEnddate($show){
 123+ $this->m_showEnddate = $show;
 124+ }
 125+
 126+ public function getm0(){
 127+ return $this->m_m0;
 128+ }
 129+
 130+ public function getID(){
 131+ return $this->m_id;
 132+ }
 133+
 134+ public function getParents(){
 135+ return $this->m_parents;
 136+ }
 137+
 138+ private function makeID($val){
 139+ return substr($val,-18);
 140+ }
 141+
 142+ /**
 143+ * This method sets the internal values for Gantt-chart
 144+ *
 145+ */
 146+ public function setInternals(){
 147+ //get internal values from SPM_Setup page
 148+ $title = Title::newFromText("SPM_Setup");
 149+ $article = new Article($title);
 150+ $wikitext = $article->getContent();
 151+
 152+ $pos1 = strpos($wikitext,"<!--");
 153+ $pos2 = strpos($wikitext,"-->");
 154+
 155+ $data = substr($wikitext,$pos1+4,$pos2-$pos1-4);
 156+
 157+ $textarr = explode("{**}",$data);
 158+ $levels = (int) $textarr[0];
 159+ $this->m_m0 = $textarr[1];
 160+ $this->m_allSame = $textarr[2];
 161+
 162+ for ( $i = 0; $i < $levels; $i += 1) {
 163+
 164+ $vals = array_splice($textarr,3,3);
 165+ $this->m_categories[$i] = $vals[0];
 166+ $this->m_colors[$i] = $vals[1];
 167+ $this->m_properties[$i] = $vals[2];
 168+ }
 169+
 170+ }
 171+
 172+ public function getCategories(){
 173+ return $this->m_categories;
 174+ }
 175+ public function getColors(){
 176+ return $this->m_colors;
 177+ }
 178+ public function getProperties(){
 179+ return $this->m_properties;
 180+ }
 181+ /**
 182+ * This method creates UIds for every task and orders them to correctly display the Gantt-chart
 183+ */
 184+ private function orderTasks(){
 185+
 186+ $this->setTimeParameters();
 187+
 188+ usort($this->m_tasks,array( $this , "cmpLevel"));
 189+
 190+ $level1number = 10;
 191+ $number = array();
 192+ $tasknames = array();
 193+ $parent = array();
 194+
 195+
 196+ //create UId for each task with following logic:
 197+ //UId of first task: 10
 198+ //UId of 10's first child: 1010
 199+ //UId of 10's second child: 1011
 200+ //UId of 1011's first child: 101110 ...
 201+ foreach ($this->m_tasks as $temp){
 202+
 203+ $temp->setM0($this->m_m0);
 204+
 205+ if (!isset($number[$temp->getLevel()])) $number[$temp->getLevel()] = 10;
 206+
 207+ //check to which parent task belongs
 208+ $parts = $temp->getPartOf();
 209+
 210+ if (sizeof($parts) == 0){
 211+ //level 1
 212+ $temp->setUid($level1number);
 213+ $tasknames[$temp->getId()] = $temp->getUid();
 214+ $level1number++;
 215+ }
 216+ else {
 217+
 218+ foreach ($parts as $part){
 219+
 220+ if (isset($tasknames[$part])){
 221+ if (!isset($number[$tasknames[$part]])) $number[$tasknames[$part]] = 10;
 222+ $temp->setUid(100*$tasknames[$part]+$number[$tasknames[$part]]);
 223+ $temp->setParent($tasknames[$part]);
 224+ $tasknames[$temp->getId()] = $temp->getUid();
 225+ $number[$tasknames[$part]]++;
 226+ $parent[$tasknames[$part]] = 1;
 227+ }
 228+ //no part-of relation found -> level 1
 229+ else {
 230+ $temp->setUid($level1number);
 231+ $tasknames[$temp->getId()] = $temp->getUid();
 232+ $level1number++;
 233+ }
 234+ }
 235+ }
 236+ }
 237+
 238+ //set group property for all parents
 239+ foreach ($this->m_tasks as $temp){
 240+ if ((isset($parent[$temp->getUid()]))&&($parent[$temp->getUid()] == 1)){
 241+ $temp->setGroup(1);
 242+ $temp->setGanttEndDate('');
 243+ $temp->setGanttStartDate('');
 244+ }
 245+ else $temp->setGroup(0);
 246+ }
 247+
 248+ //all tasks have a UId -> sort tasks by UId (with string comparison)
 249+ usort($this->m_tasks,array( $this , "cmpUid"));
 250+
 251+ }
 252+
 253+ /**
 254+ * Comparison function, orders by: level, starttime (if level was identical), name (if level & starttime identical)
 255+ *
 256+ * @param $task1 task, first task to compare
 257+ * @param $task2 task, second task to compare
 258+ */
 259+ static function cmpLevel($task1,$task2){
 260+ $level1 = $task1->getLevel();
 261+ $level2 = $task2->getLevel();
 262+
 263+
 264+ if ($level1 == $level2) {
 265+
 266+ $sec1 = $task1->getStartSeconds();
 267+ $sec2 = $task2->getStartSeconds();
 268+
 269+ if ($sec1 == $sec2) {
 270+
 271+
 272+ $name1 = (String) $task1->getLabel();
 273+ $name2 = (String) $task1->getLabel();
 274+
 275+ return strnatcasecmp($name1,$name2);
 276+ }
 277+ return ($sec1 > $sec2);
 278+ }
 279+ return ($level1>$level2);
 280+ }
 281+
 282+ /**
 283+ * Comparison function, orders by: string comparison of UId
 284+ *
 285+ * @param $task1 task, first task to compare
 286+ * @param $task2 task, second task to compare
 287+ */
 288+ static function cmpUid($task1,$task2){
 289+ $id1 = (String) $task1->getUid();
 290+ $id2 = (String) $task2->getUid();
 291+ return strcmp($id1,$id2);
 292+ }
 293+
 294+ /**
 295+ * Comparison function, orders by: XMLSchemaDate
 296+ *
 297+ * @param $task1 task, first task to compare
 298+ * @param $task2 task, second task to compare
 299+ */
 300+ static function cmpDate($task1,$task2){
 301+ $date1 = $task1->getPlannedStartDate();
 302+ if ($date1!=null)
 303+ $res1 = strtotime($date1->getXMLSchemaDate());
 304+ $date2 = $task2->getPlannedStartDate();
 305+ if ($date2!=null)
 306+ $res2 = strtotime($date2->getXMLSchemaDate());
 307+ return ($res1<$res2);
 308+
 309+ }
 310+
 311+ /**
 312+ * This method should be used for getting new or existing nodes
 313+ * If a node does not exist yet, it will be created
 314+ *
 315+ * @param $id string, node id
 316+ * @param $label string, node label
 317+ * @return Object of type ProcessNode
 318+ */
 319+ public function makeTask($val, $level){
 320+
 321+ $this->id = $this->makeID($val);
 322+ $id = $this->makeID($val);
 323+
 324+ $task;
 325+
 326+ // check if node exists
 327+ if (isset($this->m_tasks[$id])){
 328+ // take existing node
 329+ $task = $this->m_tasks[$id];
 330+
 331+ //switch on for debugging
 332+// echo "Task: ".$task->getID()." already exists! <br/>";
 333+ } else {
 334+ // create new node
 335+
 336+ $task = new ProjectManagementTask();
 337+ $task->setOutlineLevel($level);
 338+ $task->setPage($val);
 339+ $task->setProjectManagementClass($this);
 340+ $task->setId($this->id);
 341+ //set default color
 342+ $task->setColor("ff0000");
 343+
 344+ // add new node to process
 345+ $this->m_tasks[$id] = $task;
 346+
 347+ //switch on for debugging
 348+// echo "Task: ".$task->getID()." created! <br/>";
 349+ }
 350+ return $task;
 351+
 352+ }
 353+
 354+ /**
 355+ * This method should be used for making a new Resource
 356+ *
 357+ * @param $val Value of resource that is to be created
 358+ * @return Object of type resource
 359+ */
 360+ public function makeResource($val){
 361+
 362+ $id = $this->makeID($val);
 363+ $resource;
 364+
 365+ // check if node exists
 366+ if (isset($this->m_resources[$id])){
 367+ // take existing node
 368+ $resource = $this->m_resources[$id];
 369+
 370+ } else {
 371+ // create new node
 372+ $this->m_uid++;
 373+ $uid = $this->m_uid;
 374+
 375+
 376+ $resource = new ProjectManagementResource();
 377+ $resource->setPage($val);
 378+ $resource->setUid($uid);
 379+ $resource->setId($uid);
 380+ $resource->setProjectManagementClass($this);
 381+
 382+ // add new node to process
 383+ $this->m_resources[$id] = $resource;
 384+ }
 385+
 386+ return $resource;
 387+
 388+ }
 389+
 390+
 391+ /**
 392+ * Processes a result set and saves all relevant values internally
 393+ *
 394+ * @param $res array, Result set that is to be processed
 395+ * @param $outputmode Outputmode
 396+ * @param $level int, Level of Result set
 397+ * @param $parent Parent of result set
 398+ * @return Array of all children
 399+ */
 400+ public function getTaskResults($res, $outputmode, $level, $parent) {
 401+ global $wgContLang, $spmgScriptPath; // content language object
 402+ $hasChild = array();
 403+ //
 404+ // Iterate all rows in result set
 405+ //
 406+ $number=1;
 407+ $row = $res->getNext(); // get initial row (i.e. array of SMWResultArray)
 408+
 409+
 410+ while ( $row !== false) {
 411+
 412+ $task;
 413+ $subject = $row[0]->getResultSubject(); // get Subject of the Result
 414+ // creates a new node if $val has type wikipage
 415+
 416+ $val = $subject->getLongWikiText();
 417+
 418+ $task = $this->makeTask($val, $level);
 419+
 420+ if ($this->m_allSame == true){
 421+ $task->setLevel($level);
 422+ $task->setColor($this->m_colors[$level-1]);
 423+ }
 424+ // echo "generating task: ".$val."<br/>";
 425+
 426+ $hasChild[] = $task;
 427+ $task->setWBS($parent->getWBS());
 428+ $task->addWBS($level,$number);
 429+ $number++;
 430+
 431+ if ($parent->getID() != "seed"){
 432+ $task->addPartOf($parent->getID());
 433+// echo $task->getID()."s parent is: ".$parent->getID()."<br/>";
 434+ }
 435+
 436+ $title = $subject->getTitle();
 437+ $fullURL = $title->getFullURL();
 438+ $task->setHyperlink($fullURL);
 439+ $discussionTitle = Title::newFromText('Talk:'.$val.'');
 440+ if ($discussionTitle->isKnown()) {
 441+
 442+ $task->setPictureURL($spmgScriptPath . 'libs/ganttchart/discuss_icon.png');
 443+ $task->setPictureLink($discussionTitle->getFullURL());
 444+ }
 445+ //
 446+ // Iterate all colums of the row (which describe properties of the proces node)
 447+ //
 448+
 449+ foreach ($row as $field) {
 450+
 451+ // check column title
 452+ $req = $field->getPrintRequest();
 453+ switch ((strtolower($req->getLabel()))) {
 454+
 455+ case "hassuccessor":
 456+
 457+ // Sequence
 458+ foreach ($field->getContent() as $value) {
 459+
 460+ $val = $value->getLongWikiText();
 461+ $suc = $this->makeTask($val, $level);
 462+ $task->addSuccessor($suc);
 463+ $suc->addPredecessor($task);
 464+
 465+ //echo "hasSuccessor: ".$suc->getUid();
 466+
 467+
 468+ if ( $value->getTypeID() == '_wpg' ){
 469+ $title = $value->getTitle();
 470+ $fullURL = $title->getFullURL();
 471+
 472+ $suc->setHyperlink($fullURL);
 473+ }
 474+
 475+ }
 476+ break;
 477+
 478+ case "category":
 479+
 480+ // sequence
 481+ foreach ($field->getContent() as $value) {
 482+
 483+ //only identify level by category if all categories are different
 484+ if ($this->m_allSame == false){
 485+ if (($value !== false)) {
 486+ $val = $value->getShortWikiText();
 487+
 488+ for ($i=0; $i<sizeof($this->m_categories);$i++){
 489+
 490+ if ($val == $this->m_categories[$i]) {
 491+
 492+ // if (($task->getLevel() == 0)||($task->getLevel() < $task->getCurrentLevel())){
 493+ $task->setColor($this->m_colors[$i]);
 494+ $task->setLevel($i+1);
 495+ // $task->setCurrentLevel($i+1);
 496+ // }
 497+ }
 498+ }
 499+
 500+ }
 501+ }
 502+ }
 503+ break;
 504+
 505+ case "progress":
 506+
 507+ $value = current($field->getContent()); // save only the first
 508+ if (($value !== false)) {
 509+ $val = $value->getShortWikiText();
 510+ $task->setProgress($val);
 511+ }
 512+ break;
 513+
 514+
 515+ case "startmonth":
 516+
 517+ $value = current($field->getContent()); // save only the first
 518+ if (($value !== false)) {
 519+ $val = $value->getShortWikiText();
 520+ $task->setStartmonth($val);
 521+ }
 522+ break;
 523+
 524+
 525+ case "endmonth":
 526+
 527+ $value = current($field->getContent()); // save only the first
 528+ if (($value !== false)) {
 529+ $val = $value->getShortWikiText();
 530+ $task->setEndmonth($val);
 531+ }
 532+ break;
 533+
 534+ case "deliverymonth":
 535+
 536+ $value = current($field->getContent()); // save only the first
 537+ if (($value !== false)) {
 538+ $val = $value->getShortWikiText();
 539+ $task->setDeliverymonth($val);
 540+ }
 541+ break;
 542+
 543+ case "haslabel":
 544+ $value = current($field->getContent()); // save only the first
 545+ if (($value !== false)) {
 546+ $val = $value->getShortWikiText();
 547+ $task->setLabel($val);
 548+ }
 549+ break;
 550+
 551+ case "hasrealstartdate":
 552+ $value = current($field->getContent()); // save only the first
 553+ if (($value !== false) && ($req->getTypeID() == "_dat")) {
 554+
 555+ $task->setStartDate($value);
 556+ }
 557+ break;
 558+ case "hasrealfinishdate":
 559+ $value = current($field->getContent()); // save only the first
 560+ if (($value !== false) && ($req->getTypeID() == "_dat")) {
 561+
 562+ $task->setFinishDate($value);
 563+ }
 564+ case "hasplannedstartdate":
 565+ $value = current($field->getContent()); // save only the first
 566+ if (($value !== false) && ($req->getTypeID() == "_dat")) {
 567+
 568+ $task->setPlannedStartDate($value);
 569+ }
 570+ break;
 571+ case "hasplannedfinishdate":
 572+ $value = current($field->getContent()); // save only the first
 573+ if (($value !== false) && ($req->getTypeID() == "_dat")) {
 574+
 575+ $task->setPlannedFinishDate($value);
 576+ }
 577+ break;
 578+ case "hasearlystartdate":
 579+ $value = current($field->getContent()); // save only the first
 580+ if (($value !== false) && ($req->getTypeID() == "_dat")) {
 581+
 582+ $task->setEarlyStartDate($value);
 583+ }
 584+ break;
 585+ case "hasearlyfinishdate":
 586+ $value = current($field->getContent()); // save only the first
 587+ if (($value !== false) && ($req->getTypeID() == "_dat")) {
 588+
 589+ $task->setEarlyFinishDate($value);
 590+ }
 591+ break;
 592+ case "haslatestartdate":
 593+ $value = current($field->getContent()); // save only the first
 594+ if (($value !== false) && ($req->getTypeID() == "_dat")) {
 595+
 596+ $task->setLateStartDate($value);
 597+ }
 598+ break;
 599+ case "haslatefinishdate":
 600+ $value = current($field->getContent()); // save only the first
 601+ if (($value !== false) && ($req->getTypeID() == "_dat")) {
 602+
 603+ $task->setLateFinishDate($value);
 604+ }
 605+ break;
 606+ case "hasactor":
 607+ $value = current($field->getContent()); // save only the first
 608+ if (($value !== false)) {
 609+ $val = $value->getShortWikiText();
 610+ $resource = $this->makeResource($val);
 611+ $task->setActor($val);
 612+ }
 613+ break;
 614+
 615+ case "resource":
 616+ $value = current($field->getContent()); // save only the first
 617+ if (($value !== false)) {
 618+ $val = $value->getShortWikiText();
 619+ $task->setResource($val);
 620+ }
 621+ break;
 622+
 623+ case "caption":
 624+ $value = current($field->getContent()); // save only the first
 625+ if (($value !== false)) {
 626+ $val = $value->getShortWikiText();
 627+ $task->setCaption($val);
 628+ }
 629+ break;
 630+ default:
 631+
 632+
 633+ // TODO - redundant column in result
 634+
 635+ }
 636+ }
 637+
 638+ // reset row variables
 639+ unset($task);
 640+
 641+ $row = $res->getNext(); // switch to next row
 642+ }
 643+
 644+ return $hasChild;
 645+
 646+ }
 647+
 648+ /**
 649+ * This method returns all tasks that neither have a successor nor a successor
 650+ *
 651+ * @param $tasks array, tasks that are to be checked
 652+ * @return array of all single tasks
 653+ */
 654+ public function returnSingleTasks($tasks){
 655+ $single = array() ;
 656+
 657+ foreach ($tasks as $task){
 658+ if ((count($task->getSuccessors())==0)&&(count($task->getPredecessors())==0)){
 659+
 660+ $single[] = $task;
 661+
 662+ }
 663+ }
 664+ return $single;
 665+ }
 666+
 667+ /**
 668+ * This method returns all tasks that neither have a successor nor a successor
 669+ *
 670+ * @param $tasks array, tasks that are to be checked
 671+ * @return array of all single tasks
 672+ */
 673+ public function returnStartTasks($tasks){
 674+ $single = array() ;
 675+
 676+ foreach ($tasks as $task){
 677+ if ((count($task->getSuccessors())>0)&&(count($task->getPredecessors())==0)){
 678+
 679+ $single[] = $task;
 680+
 681+ }
 682+ }
 683+ return $single;
 684+ }
 685+
 686+
 687+ /**
 688+ * This method sets the time Parameters to correctly display the Gantt-chart
 689+ * Priorities from low to high:
 690+ * plannedStart/FinishDate, Start/EndMonth (M notation), realStart/EndDate
 691+ * if a task has more than one value, the one with the highest priority is selected
 692+ *
 693+ */
 694+ public function setTimeParameters(){
 695+
 696+ foreach($this->m_tasks as $task){
 697+
 698+ $starttime = null;
 699+ $endtime = null;
 700+ $startdate = null;
 701+ $enddate = null;
 702+
 703+ //if planned start date exists
 704+ if ($task->getPlannedStartDate() != null) {
 705+
 706+ $startdate = $task->getGanttDate($task->getPlannedStartDate());
 707+
 708+ //get task starttime as int
 709+ $time1 = explode("T",$task->parsedate($task->getPlannedStartDate()));
 710+ $time2 = explode("-",$time1[0]);
 711+ $time3 = explode(":",$time1[1]);
 712+ $starttime = date("U",mktime($time3[0],$time3[1],$time3[2],$time2[1],$time2[2],$time2[0]));
 713+
 714+ }
 715+
 716+ //if planned finish date exists
 717+ if ($task->getPlannedFinishDate() != null){
 718+
 719+ $enddate = $task->getGanttDate($task->getPlannedFinishDate());
 720+ //get task endtime as int
 721+ $time1 = explode("T",$task->parsedate($task->getPlannedFinishDate()));
 722+ $time2 = explode("-",$time1[0]);
 723+ $time3 = explode(":",$time1[1]);
 724+ $endtime = date("U",mktime($time3[0],$time3[1],$time3[2],$time2[1],$time2[2],$time2[0]));
 725+ }
 726+
 727+
 728+ //convert M1-36 notation.
 729+ if ($task->getStartMonth() != null){
 730+ $starttime = $task->monthToTime($task->getStartmonth());
 731+ $startdate = $task->monthToGanttDate($task->getStartmonth());
 732+ }
 733+ if ($task->getEndMonth() != null){
 734+
 735+ $tempint = (int) str_replace("M","",$task->getEndmonth());
 736+ $tempint++;
 737+ $endmonth = (string) "M".$tempint;
 738+ $endtime = $task->monthToTime($endmonth);
 739+ $enddate = $task->monthToGanttDate($endmonth);
 740+ }
 741+
 742+ //convert for M1-36 notation. (for Deliverables)
 743+ //can be removed if all deliverables have start&enddate
 744+ if ($task->getDeliveryMonth() != null){
 745+
 746+ $endtime = $task->monthToTime($task->getDeliverymonth());
 747+ $starttime = $endtime - (30*24*60*60);
 748+
 749+ $enddate = $task->monthToGanttDate($task->getDeliverymonth());
 750+
 751+ //set startdate = 1 month before enddate
 752+ $date = explode("/",$enddate);
 753+ if ($date[0] != "01") {
 754+ $m = (int) $date[0];
 755+ $s = (string)($m-1);
 756+ if ($m < 11) $s = "0".$s;
 757+ $date[0] = $s;
 758+ }
 759+ else {
 760+ $date[0] = 12;
 761+ $rest = explode(" ",$date[2]);
 762+ $y = (int) $rest[0];
 763+ $s = (string)($y-1);
 764+ $rest[0] = $s;
 765+ $date[2] = implode(" ",$rest);
 766+ }
 767+ $startdate = implode("/",$date);
 768+
 769+ }
 770+
 771+ //if real start date exists
 772+ if (($task->getStartDate() != null)){
 773+ $startdate = $task->getGanttDate($task->getStartDate());
 774+
 775+ //get task starttime as int
 776+ $time1 = explode("T",$task->parsedate($task->getStartDate()));
 777+ $time2 = explode("-",$time1[0]);
 778+ $time3 = explode(":",$time1[1]);
 779+ $starttime = date("U",mktime($time3[0],$time3[1],$time3[2],$time2[1],$time2[2],$time2[0]));
 780+ }
 781+
 782+ //if real finish date exists
 783+ if (($task->getFinishDate() != null)){
 784+ $enddate = $task->getGanttDate($task->getFinishDate());
 785+
 786+ //get task endtime as int
 787+ $time1 = explode("T",$task->parsedate($task->getFinishDate()));
 788+ $time2 = explode("-",$time1[0]);
 789+ $time3 = explode(":",$time1[1]);
 790+ $endtime = date("U",mktime($time3[0],$time3[1],$time3[2],$time2[1],$time2[2],$time2[0]));
 791+ }
 792+
 793+ //calculate progress
 794+ $progress = 0;
 795+
 796+ //only calculate progress if real start date exists
 797+ if ($task->getStartDate() != null){
 798+ $time = getdate();
 799+ $todaytime = $time[0];
 800+ if ($todaytime >= $endtime) $progress = 100;
 801+
 802+ if (($todaytime > $starttime)&&($todaytime < $endtime)){
 803+
 804+ if ($endtime > $starttime)
 805+ $progress = (int)((($todaytime - $starttime)/($endtime-$starttime))*100);
 806+
 807+ }
 808+ }
 809+
 810+ //use progress property if existing
 811+ if ($task->getProgress() != null) $progress = $task->getProgress();
 812+
 813+ //TODO: error handling
 814+ if ((($task->getLevel() == sizeof($this->m_categories)))&&(($startdate == null)||($enddate == null))){
 815+
 816+ echo "ERROR: No valid time for ".$task->getLabel()."<br/>";
 817+ if ($startdate == null) echo "no startdate! <br/>";
 818+ if ($enddate == null) echo "no enddate! <br/>";
 819+ $task->setStartSeconds(0);
 820+ $task->setGanttStartDate($startdate);
 821+ $task->setGanttEndDate($enddate);
 822+ $task->setProgress(0);
 823+
 824+ }
 825+ else{
 826+ $task->setStartSeconds($starttime);
 827+ $task->setGanttStartDate($startdate);
 828+ $task->setGanttEndDate($enddate);
 829+ $task->setProgress($progress);
 830+ }
 831+
 832+ }
 833+ }
 834+
 835+ /**
 836+ * This method returns a Calendar
 837+ * @return string, CalendarXML
 838+ *
 839+ */
 840+ public function getCalendarXML(){
 841+ $res ='';
 842+ $res .="<Calendars>\r\n";
 843+ $res .="<Calendar>\r\n";
 844+ $res .="<UID>3</UID>\r\n";
 845+ $res .="<Name>24 Stunden</Name>\r\n";
 846+ $res .="<IsBaseCalendar>1</IsBaseCalendar>\r\n";
 847+ $res .="<BaseCalendarUID>-1</BaseCalendarUID>\r\n";
 848+ $res .="<WeekDays>\r\n";
 849+ $res .="<WeekDay>\r\n";
 850+ $res .="<DayType>1</DayType>\r\n";
 851+ $res .="<DayWorking>1</DayWorking>\r\n";
 852+ $res .="<WorkingTimes>\r\n";
 853+ $res .="<WorkingTime>\r\n";
 854+ $res .="<FromTime>00:00:00</FromTime>\r\n";
 855+ $res .="<ToTime>00:00:00</ToTime>\r\n";
 856+ $res .="</WorkingTime>\r\n";
 857+ $res .="</WorkingTimes>\r\n";
 858+ $res .="</WeekDay>\r\n";
 859+ $res .="<WeekDay>\r\n";
 860+ $res .="<DayType>2</DayType>\r\n";
 861+ $res .="<DayWorking>1</DayWorking>\r\n";
 862+ $res .="<WorkingTimes>\r\n";
 863+ $res .="<WorkingTime>\r\n";
 864+ $res .="<FromTime>00:00:00</FromTime>\r\n";
 865+ $res .="<ToTime>00:00:00</ToTime>\r\n";
 866+ $res .="</WorkingTime>\r\n";
 867+ $res .="</WorkingTimes>\r\n";
 868+ $res .="</WeekDay>\r\n";
 869+ $res .="<WeekDay>\r\n";
 870+ $res .="<DayType>3</DayType>\r\n";
 871+ $res .="<DayWorking>1</DayWorking>\r\n";
 872+ $res .="<WorkingTimes>\r\n";
 873+ $res .="<WorkingTime>\r\n";
 874+ $res .="<FromTime>00:00:00</FromTime>\r\n";
 875+ $res .="<ToTime>00:00:00</ToTime>\r\n";
 876+ $res .="</WorkingTime>\r\n";
 877+ $res .="</WorkingTimes>\r\n";
 878+ $res .="</WeekDay>\r\n";
 879+ $res .="<WeekDay>\r\n";
 880+ $res .="<DayType>4</DayType>\r\n";
 881+ $res .="<DayWorking>1</DayWorking>\r\n";
 882+ $res .="<WorkingTimes>\r\n";
 883+ $res .="<WorkingTime>\r\n";
 884+ $res .="<FromTime>00:00:00</FromTime>\r\n";
 885+ $res .="<ToTime>00:00:00</ToTime>\r\n";
 886+ $res .="</WorkingTime>\r\n";
 887+ $res .="</WorkingTimes>\r\n";
 888+ $res .="</WeekDay>\r\n";
 889+ $res .="<WeekDay>\r\n";
 890+ $res .="<DayType>5</DayType>\r\n";
 891+ $res .="<DayWorking>1</DayWorking>\r\n";
 892+ $res .="<WorkingTimes>\r\n";
 893+ $res .="<WorkingTime>\r\n";
 894+ $res .="<FromTime>00:00:00</FromTime>\r\n";
 895+ $res .="<ToTime>00:00:00</ToTime>\r\n";
 896+ $res .="</WorkingTime>\r\n";
 897+ $res .="</WorkingTimes>\r\n";
 898+ $res .="</WeekDay>\r\n";
 899+ $res .="<WeekDay>\r\n";
 900+ $res .="<DayType>6</DayType>\r\n";
 901+ $res .="<DayWorking>1</DayWorking>\r\n";
 902+ $res .="<WorkingTimes>\r\n";
 903+ $res .="<WorkingTime>\r\n";
 904+ $res .="<FromTime>00:00:00</FromTime>\r\n";
 905+ $res .="<ToTime>00:00:00</ToTime>\r\n";
 906+ $res .="</WorkingTime>\r\n";
 907+ $res .="</WorkingTimes>\r\n";
 908+ $res .="</WeekDay>\r\n";
 909+ $res .="<WeekDay>\r\n";
 910+ $res .="<DayType>7</DayType>\r\n";
 911+ $res .="<DayWorking>1</DayWorking>\r\n";
 912+ $res .="<WorkingTimes>\r\n";
 913+ $res .="<WorkingTime>\r\n";
 914+ $res .="<FromTime>00:00:00</FromTime>\r\n";
 915+ $res .="<ToTime>00:00:00</ToTime>\r\n";
 916+ $res .="</WorkingTime>\r\n";
 917+ $res .="</WorkingTimes>\r\n";
 918+ $res .="</WeekDay>\r\n";
 919+ $res .="</WeekDays>\r\n";
 920+ $res .="</Calendar>\r\n";
 921+ $res .="</Calendars>\r\n";
 922+ return $res;
 923+ }
 924+
 925+ /**
 926+ * This method returns the html that integrates the JSGantt on the wikipage
 927+ * @return string, GanttChart
 928+ *
 929+ */
 930+ public function getGanttChart(){
 931+ global $spmgScriptPath;
 932+
 933+ // $levelcheck = $this->getParents();
 934+
 935+ array_shift($this->m_tasks);
 936+
 937+ $this->orderTasks();
 938+
 939+ $res ='';
 940+ $res .='<link rel="stylesheet" type="text/css" href="' .$spmgScriptPath . '/libs/ganttchart/jsgantt.css" />';
 941+ $res .="\r\n";
 942+ $res .='<script language="javascript" src="' .$spmgScriptPath . '/libs/ganttchart/jsgantt.js"></script>';
 943+ $res .="\r\n";
 944+ $res .='<div style="position:relative" class="gantt" id="GanttChartDIV"></div>';
 945+ $res .="\r\n";
 946+ $res .='<script language="javascript">';
 947+ $res .="\r\n";
 948+ $res .='var g = new JSGantt.GanttChart(\'g\',document.getElementById(\'GanttChartDIV\'), \'day\');';
 949+ $res .="\r\n";
 950+
 951+
 952+ if ($this->getShowResponsible()){
 953+ $res .='g.setShowRes(1); // Show Responsible';
 954+ } else {
 955+ $res .='g.setShowRes(0); // Hide Responsible';
 956+ }
 957+ $res .="\r\n";
 958+
 959+ if ($this->getShowComplete()){
 960+ $res .='g.setShowComp(1); // Show Completeness';
 961+ } else {
 962+ $res .='g.setShowComp(0); // Hide Completeness';
 963+ }
 964+ $res .="\r\n";
 965+
 966+ if ($this->getShowDuration()){
 967+ $res .='g.setShowDur(1); // Show Duration';
 968+ } else {
 969+ $res .='g.setShowDur(0); // Hide Duration';
 970+ }
 971+ $res .="\r\n";
 972+
 973+ if ($this->getShowDiscussion()) {
 974+ $res .='g.setShowPicture(1); // Show Picture';
 975+ } else {
 976+ $res .='g.setShowPicture(0); // Hide Picture';
 977+ }
 978+ $res .="\r\n";
 979+
 980+ if ($this->getShowStartdate()) {
 981+ $res .='g.setShowStartDate(1); // Show Startdate';
 982+ } else {
 983+ $res .='g.setShowStartDate(0); // Hide Startdate';
 984+ }
 985+ $res .="\r\n";
 986+
 987+ if ($this->getShowEnddate()) {
 988+ $res .='g.setShowEndDate(1); // Show Enddate';
 989+ } else {
 990+ $res .='g.setShowEndDate(0); // Hide Enddate';
 991+ }
 992+ $res .="\r\n";
 993+
 994+ $res .='g.setCaptionType(\'Complete\'); // Set to Show Caption';
 995+ $res .="\r\n";
 996+ $res .='g.setFormatArr("hour","day","week","month");';
 997+ $res .="\r\n";
 998+
 999+ $id=1;
 1000+ foreach($this->m_tasks as $task){
 1001+ $tempres = $task->getGanttChart($this->id);
 1002+ $res .= $tempres[0];
 1003+ $id = $tempres[1];
 1004+ }
 1005+
 1006+ $res .='g.Draw();';
 1007+ $res .="\r\n";
 1008+ $res .='g.DrawDependencies();';
 1009+ $res .="\r\n";
 1010+ $res .='</script>';
 1011+ $res .="\r\n";
 1012+ return $res;
 1013+ }
 1014+
 1015+ /**
 1016+ * This method returns the XML representation of the project
 1017+ * @return string, XML representation
 1018+ *
 1019+ */
 1020+ public function getXML(){
 1021+ array_shift($this->m_tasks);
 1022+ $this->orderTasks();
 1023+
 1024+ $res ='';
 1025+ //
 1026+ // header
 1027+ //
 1028+ $res .='<?xml version="1.0" encoding="UTF-8" standalone="yes"?>'."\r\n";
 1029+ $res .='<Project xmlns="http://schemas.microsoft.com/project">'."\r\n";
 1030+ $res .="<SaveVersion>1</SaveVersion>\r\n";
 1031+ if ($this->m_name!='')
 1032+ $res .="<Name>" . $this->m_name . "</Name>\r\n";
 1033+ if ($this->m_title!='')
 1034+ $res .="<Title>" . $this->m_title . "</Title>\r\n";
 1035+ if ($this->m_startDate!=null){
 1036+ $res .= "<StartDate>" . $this->m_startDate . "</StartDate>\r\n";
 1037+ $res .= "<ScheduleFromStart>1</ScheduleFromStart>\r\n";
 1038+ }
 1039+ // $res .= $this->getCalendarXML();
 1040+ // add tasks
 1041+ $res .="<Tasks>\r\n";
 1042+ $id=1;
 1043+ foreach($this->m_tasks as $task){
 1044+
 1045+ $tempres = $task->getXML($id);
 1046+ $res .= $tempres[0];
 1047+ $id = $tempres[1];
 1048+
 1049+ }
 1050+ $res .="</Tasks>\r\n";
 1051+ $res .="<Resources>\r\n";
 1052+
 1053+ foreach($this->m_resources as $resource){
 1054+
 1055+ $res .= $resource->getXML();
 1056+
 1057+ }
 1058+
 1059+ $res .="</Resources>\r\n";
 1060+ if (count($this->m_resources)>0){
 1061+ $res .="<Assignments>\r\n";
 1062+ $id=1;
 1063+ foreach($this->m_tasks as $task){
 1064+ $tempres = $task->getAssignmentXML($id);
 1065+ $res .= $tempres[0];
 1066+ $id = $tempres[1];
 1067+ }
 1068+ $res .="</Assignments>\r\n";
 1069+ }
 1070+ //
 1071+ // add final stuff
 1072+ //
 1073+ $res .= "</Project>\r\n";
 1074+
 1075+ return $res;
 1076+
 1077+ }
 1078+
 1079+}
 1080+
 1081+
 1082+
 1083+abstract class ProjectManagementElement{
 1084+
 1085+ private $m_projectmanagementclass;
 1086+ // TODO I18N
 1087+ private $m_id = 'no_id';
 1088+ private $m_uid = 'no_uid';
 1089+ private $m_uri = '';
 1090+ private $m_label = 'unlabeled';
 1091+ private $m_page='';
 1092+
 1093+
 1094+ //setters and getters
 1095+ public function getId(){
 1096+ return $this->m_id;
 1097+ }
 1098+
 1099+ public function setId($id){
 1100+ $this->m_id = $id;
 1101+ }
 1102+
 1103+ public function getLabel(){
 1104+ return $this->m_label;
 1105+ }
 1106+
 1107+ public function setLabel($label){
 1108+ $this->m_label = $label;
 1109+ }
 1110+
 1111+ public function setProjectManagementClass($proc){
 1112+ $this->m_projectmanagementclass = $proc;
 1113+ }
 1114+
 1115+ public function getProjectManagementClass(){
 1116+ return $this->m_projectmanagementclass;
 1117+ }
 1118+
 1119+ public function getUid(){
 1120+ return $this->m_uid;
 1121+ }
 1122+ public function setUid($uid){
 1123+ $this->m_uid = $uid;
 1124+ }
 1125+ public function getUri(){
 1126+ return $this->m_uri;
 1127+ }
 1128+ public function setUri($uri){
 1129+ $this->m_uri = $uri;
 1130+ }
 1131+ public function setPage($page){
 1132+ $this->m_page = $page;
 1133+ }
 1134+ public function replaceLabelChars($label){
 1135+ return str_replace("&","and",$label);
 1136+ }
 1137+}
 1138+
 1139+
 1140+
 1141+class ProjectManagementTask extends ProjectManagementElement{
 1142+
 1143+ //task variables
 1144+ private $m_WBS= array();
 1145+ private $m_outlineLevel;
 1146+ // TODO I18N
 1147+ private $m_page ='';
 1148+ private $m_successors = array();
 1149+ private $m_predecessors = array();
 1150+ private $m_earlyStart =null;
 1151+ private $m_earlyFinish=null;
 1152+ private $m_lateStart=null;
 1153+ private $m_lateFinish=null;
 1154+ private $m_start=null;
 1155+ private $m_finish=null;
 1156+ private $m_plannedStart=null;
 1157+ private $m_plannedFinish=null;
 1158+ private $m_timestamp=null;
 1159+ private $m_actor=null;
 1160+ private $m_hyperlink='';
 1161+ private $m_picturelink='';
 1162+ private $m_pictureurl='';
 1163+ private $m_color ='';
 1164+ private $m_progress = null;
 1165+ private $m_resource='';
 1166+ private $m_milestone = false;
 1167+ private $m_group = 0;
 1168+ private $m_parent = 0;
 1169+ private $m_open = 1;
 1170+ private $m_depend = "";
 1171+ private $m_caption = "";
 1172+ private $m_level = 0;
 1173+ private $m_parentname = "";
 1174+ private $m_parentBool = false;
 1175+ private $m_pid = 0;
 1176+ private $m_idd;
 1177+ private $m_startmonth;
 1178+ private $m_endmonth;
 1179+ private $m_deliverymonth;
 1180+ private $m_partOf = array();
 1181+ private $m_m0 = "";
 1182+ private $m_startdate = null;
 1183+ private $m_enddate = null;
 1184+ private $m_startseconds = null;
 1185+ private $m_currentlevel = 0;
 1186+
 1187+ //getters and setters
 1188+ public function setCurrentLevel($l){
 1189+ $this->m_currentlevel = $l;
 1190+ }
 1191+
 1192+ public function getCurrentLevel(){
 1193+ return $this->m_currentlevel;
 1194+ }
 1195+
 1196+ public function setM0($m){
 1197+ $this->m_m0 = $m;
 1198+ }
 1199+
 1200+ public function getM0(){
 1201+ return $this->m_m0;
 1202+ }
 1203+
 1204+ public function setGanttStartDate($p){
 1205+ $this->m_startdate = $p;
 1206+ }
 1207+
 1208+ public function getGanttStartDate(){
 1209+ return $this->m_startdate;
 1210+ }
 1211+
 1212+ public function setGanttEndDate($p){
 1213+ $this->m_enddate = $p;
 1214+ }
 1215+
 1216+ public function getGanttEndDate(){
 1217+ return $this->m_enddate;
 1218+ }
 1219+
 1220+ public function setStartSeconds($p){
 1221+ $this->m_startseconds = $p;
 1222+ }
 1223+
 1224+ public function getStartseconds(){
 1225+ return $this->m_startseconds;
 1226+ }
 1227+
 1228+ public function addPartOf($p){
 1229+ $this->m_partOf[] = $p;
 1230+ }
 1231+
 1232+ public function getPartOf(){
 1233+ return $this->m_partOf;
 1234+ }
 1235+
 1236+ public function setStartmonth($s){
 1237+ $this->m_startmonth = $s;
 1238+ }
 1239+
 1240+ public function getStartmonth(){
 1241+ return $this->m_startmonth;
 1242+ }
 1243+
 1244+ public function setEndmonth($s){
 1245+ $this->m_endmonth = $s;
 1246+ }
 1247+
 1248+ public function getEndmonth(){
 1249+ return $this->m_endmonth;
 1250+ }
 1251+
 1252+ public function setDeliverymonth($s){
 1253+ $this->m_deliverymonth = $s;
 1254+ }
 1255+
 1256+ public function getDeliverymonth(){
 1257+ return $this->m_deliverymonth;
 1258+ }
 1259+
 1260+ public function setIsParent($b){
 1261+ $this->m_parentBool = $b;
 1262+ }
 1263+
 1264+ public function isParent(){
 1265+ return $this->m_parentBool;
 1266+ }
 1267+
 1268+ public function setLevel($l){
 1269+ $this->m_level=$l;
 1270+ }
 1271+
 1272+ public function getLevel(){
 1273+ return $this->m_level;
 1274+ }
 1275+
 1276+ public function setColor($c){
 1277+ $this->m_color=strtolower($c);
 1278+ }
 1279+
 1280+ public function getColor(){
 1281+ return $this->m_color;
 1282+ }
 1283+
 1284+ public function setParent($p){
 1285+ $this->m_parent = $p;
 1286+ }
 1287+
 1288+ public function getParent(){
 1289+ return $this->m_parent;
 1290+ }
 1291+
 1292+ public function setParentName($p){
 1293+ $this->m_parentname = $p;
 1294+ }
 1295+
 1296+ public function getParentName(){
 1297+ return $this->m_parentname;
 1298+ }
 1299+
 1300+ public function getPid(){
 1301+ return $this->m_pid;
 1302+ }
 1303+
 1304+ public function setPid($pid){
 1305+ $this->m_pid = $pid;
 1306+ }
 1307+
 1308+ public function setDepend($depend){
 1309+ $this->m_depend = $depend;
 1310+ }
 1311+ public function getDepend(){
 1312+ return $this->m_depend;
 1313+ }
 1314+
 1315+ public function setCaption($caption){
 1316+ $this->m_caption = $caption;
 1317+ }
 1318+ public function getCaption(){
 1319+ return $this->m_caption;
 1320+ }
 1321+
 1322+ public function setMilestone($mile){
 1323+ $this->m_milestone = $mile;
 1324+ }
 1325+
 1326+ public function setGroup($group){
 1327+ $this->m_group = $group;
 1328+ }
 1329+
 1330+ public function getGroup(){
 1331+ return $this->m_group;
 1332+ }
 1333+
 1334+ public function setOpen($open){
 1335+ $this->m_open = $open;
 1336+ }
 1337+
 1338+ public function getOpen(){
 1339+ return $this->m_open;
 1340+ }
 1341+
 1342+ public function setPage($page){
 1343+ $this->m_page = $page;
 1344+ }
 1345+
 1346+ public function getPage(){
 1347+ return $this->m_page;
 1348+ }
 1349+
 1350+ public function setHyperlink($link){
 1351+ $this->m_hyperlink = $link;
 1352+ }
 1353+
 1354+ public function getHyperlink(){
 1355+ return $this->m_hyperlink;
 1356+ }
 1357+
 1358+ public function setPictureLink($link){
 1359+ $this->m_picturelink = $link;
 1360+ }
 1361+
 1362+ public function getPictureLink(){
 1363+ return $this->m_picturelink;
 1364+ }
 1365+
 1366+ public function setPictureURL($url){
 1367+ $this->m_pictureurl = $url;
 1368+ }
 1369+
 1370+ public function getPictureURL(){
 1371+ return $this->m_pictureurl;
 1372+ }
 1373+
 1374+ public function setStartDate($date){
 1375+ $this->m_start = $date;
 1376+ }
 1377+
 1378+ public function getStartDate(){
 1379+ return $this->m_start;
 1380+ }
 1381+
 1382+ public function setFinishDate($date){
 1383+ $this->m_finish = $date;
 1384+ }
 1385+
 1386+ public function getFinishDate(){
 1387+ return $this->m_finish;
 1388+ }
 1389+
 1390+ public function setPlannedStartDate($date){
 1391+ $this->m_plannedStart = $date;
 1392+ }
 1393+
 1394+ public function getPlannedStartDate(){
 1395+ return $this->m_plannedStart;
 1396+ }
 1397+
 1398+ public function setPlannedFinishDate($date){
 1399+ $this->m_plannedFinish = $date;
 1400+ }
 1401+
 1402+ public function getPlannedFinishDate(){
 1403+ return $this->m_plannedFinish;
 1404+ }
 1405+
 1406+ public function setEarlyStartDate($date){
 1407+ $this->m_earlyStart = $date;
 1408+ }
 1409+
 1410+ public function setEarlyFinishDate($date){
 1411+ $this->m_earlyFinish = $date;
 1412+ }
 1413+
 1414+ public function setLateStartDate($date){
 1415+ $this->m_lateStart = $date;
 1416+ }
 1417+
 1418+ public function setLateFinishDate($date){
 1419+ $this->m_lateFinish = $date;
 1420+ }
 1421+
 1422+ public function setActor($resource){
 1423+ $this->m_actor = $resource;
 1424+ }
 1425+
 1426+ public function getActor(){
 1427+ return $this->m_actor;
 1428+ }
 1429+
 1430+ public function addWBS($id, $value){
 1431+ $this->m_WBS[$id] = $value;
 1432+ }
 1433+
 1434+ public function setWBS($wbs){
 1435+ $this->m_WBS = $wbs;
 1436+ }
 1437+
 1438+ public function getWBS(){
 1439+ return $this->m_WBS;
 1440+ }
 1441+
 1442+ public function setTimestamp($time){
 1443+ $this->m_timestamp = $time;
 1444+ }
 1445+
 1446+ public function setOutlineLevel($level){
 1447+ $this->m_outlineLevel = $level;
 1448+ }
 1449+
 1450+ public function getOutlineLevel(){
 1451+ return $this->m_outlineLevel;
 1452+ }
 1453+
 1454+ public function addSuccessor($suc){
 1455+ $this->m_successors[] = $suc;
 1456+ }
 1457+
 1458+ public function getSuccessors(){
 1459+ return $this->m_successors;
 1460+ }
 1461+
 1462+ public function addPredecessor($pred){
 1463+ $this->m_predecessors[] = $pred;
 1464+ }
 1465+
 1466+ public function getPredecessors(){
 1467+ return $this->m_predecessors;
 1468+ }
 1469+
 1470+ public function isMilestone(){
 1471+ return $this->m_milestone;
 1472+ }
 1473+
 1474+ public function getResource(){
 1475+ return $this->m_resource;
 1476+ }
 1477+
 1478+ public function setResource($resource){
 1479+ $this->m_resource = $resource;
 1480+ }
 1481+ public function getProgress(){
 1482+ return $this->m_progress;
 1483+ }
 1484+
 1485+ public function setProgress($progress){
 1486+ $this->m_progress = $progress;
 1487+ }
 1488+
 1489+ /**
 1490+ * This method returns the assignment XML
 1491+ * @param id
 1492+ * @return string, AssignmentXML
 1493+ *
 1494+ */
 1495+ public function getAssignmentXML($id){
 1496+ $res = '';
 1497+ $res = '';
 1498+ if (($this->m_plannedFinish!=null) && ($this->m_plannedStart!=null)){
 1499+ $res .="<Assignment>\r\n";
 1500+ $res .="<UID>" .$id. "</UID>\r\n";
 1501+ $res .="<TaskUID>".$this->m_uid ."</TaskUID>\r\n";
 1502+ $res .="<ResourceUID>". $this->m_actor->getUid() ."</ResourceUID>\r\n";
 1503+ if ($this->m_plannedStart!=null) {
 1504+ $res .= "<Start>" . $this->parsedate($this->m_plannedStart) . "</Start>\r\n";
 1505+
 1506+ }
 1507+ if ($this->m_plannedFinish!=null)
 1508+ $res .= "<Finish>" . $this->parsedate($this->m_plannedFinish) . "</Finish>\r\n";
 1509+ $res .="</Assignment>\r\n";
 1510+ $id++;
 1511+ }
 1512+ return array($res,$id);
 1513+ }
 1514+
 1515+
 1516+ /**
 1517+ * This method extracts a date string formatted for task from a SMWTimeValue object.
 1518+ *
 1519+ * @param $dv SMWTimeValue, date that is to be converted
 1520+ * @return string in form YYYY-MM-DDTHH:MM:SS
 1521+ */
 1522+ public function parsedate(SMWTimeValue $dv, $isend=false) {
 1523+ $year = $dv->getYear();
 1524+ if ( ($year > 9999) || ($year<-9998) ) return ''; // ISO range is limited to four digits
 1525+ $year = number_format($year, 0, '.', '');
 1526+ $time = $dv->getTimeString(false);
 1527+ if ( ($time == false) && ($isend) ) { // increment by one day, compute date to cover leap years etc.
 1528+ $dv = SMWDataValueFactory::newTypeIDValue('_dat',$dv->getWikiValue() . 'T00:00:00+24:00');
 1529+ }
 1530+ $month = $dv->getMonth();
 1531+ if (strlen($month) == 1) $month = '0' . $month;
 1532+ $day = $dv->getDay();
 1533+ if (strlen($day) == 1) $day = '0' . $day;
 1534+ $result = $year .'-'. $month .'-'. $day;
 1535+ if ($time != false) $result .= "T$time";
 1536+ return $result;
 1537+ }
 1538+
 1539+ /**
 1540+ * This method extract a date string formatted for ganttchart from a SMWTimeValue object.
 1541+ *
 1542+ * @param $dv SMWTimeValue, date that is to be converted
 1543+ * @return string in form MM/DD/YYYY HH:MM:SS
 1544+ */
 1545+ public function getGanttDate(SMWTimeValue $dv, $isend=false) {
 1546+ $year = $dv->getYear();
 1547+ if ( ($year > 9999) || ($year<-9998) ) return ''; // ISO range is limited to four digits
 1548+ $year = number_format($year, 0, '.', '');
 1549+ $time = $dv->getTimeString(false);
 1550+ if ( ($time == false) && ($isend) ) { // increment by one day, compute date to cover leap years etc.
 1551+ $dv = SMWDataValueFactory::newTypeIDValue('_dat',$dv->getWikiValue() . 'T00:00:00+24:00');
 1552+ }
 1553+ $month = $dv->getMonth();
 1554+ if (strlen($month) == 1) $month = '0' . $month;
 1555+ $day = $dv->getDay();
 1556+ if (strlen($day) == 1) $day = '0' . $day;
 1557+ $result = $month .'/'. $day.'/'.$year;
 1558+ if ($time != false) $result .= " $time";
 1559+ return $result;
 1560+ }
 1561+
 1562+ /**
 1563+ * This method converts M01-M36 to time
 1564+ *
 1565+ * @param $mo string, month (in m notation) that is to be converted
 1566+ * @return int (seconds since unix aera)
 1567+ */
 1568+ public function monthToTime($mo){
 1569+
 1570+ $p = $this->getProjectManagementClass();
 1571+ $m0 = $p->getm0();
 1572+
 1573+ $arr = explode("/",$m0);
 1574+
 1575+ $m = (int) $arr[0];
 1576+ $d = (int) $arr[1];
 1577+ $y = (int) $arr[2];
 1578+
 1579+ $addYears = $y;
 1580+ $addMonths = (int) substr($mo,1);;
 1581+ $plusMonths = (int) substr($mo,1);
 1582+
 1583+ if ($plusMonths > 12){
 1584+ $addMonths = ((($plusMonths-1) % 12)+1);
 1585+ $addYears += floor((($plusMonths-1)/12));
 1586+ }
 1587+
 1588+ $addMonths += $m;
 1589+ $plusMonths = $addMonths;
 1590+
 1591+ if ($plusMonths > 12){
 1592+ $addMonths = ((($plusMonths-1) % 12)+1);
 1593+ $addYears += floor((($plusMonths-1)/12));
 1594+ }
 1595+
 1596+
 1597+ $result = date("U",mktime(0,0,0,$addMonths,$d,$addYears));
 1598+ return $result;
 1599+
 1600+ }
 1601+
 1602+ /**
 1603+ * This method converts M01-M36 to date
 1604+ *
 1605+ * @param $mo string, month (in m notation) that is to be converted
 1606+ * @return string in form MM/DD/YYYY HH:MM:SS
 1607+ */
 1608+ public function monthToGanttDate($mo){
 1609+
 1610+ $p = $this->getProjectManagementClass();
 1611+
 1612+ $m0 = $p->getm0();
 1613+
 1614+ $arr = explode("/",$m0);
 1615+
 1616+ $m = (int) $arr[0];
 1617+ $d = (int) $arr[1];
 1618+ $y = (int) $arr[2];
 1619+
 1620+ $addYears = $y;
 1621+ $addMonths = (int) substr($mo,1);;
 1622+ $plusMonths = (int) substr($mo,1);
 1623+
 1624+ if ($plusMonths > 12){
 1625+ $addMonths = ((($plusMonths-1) % 12)+1);
 1626+ $addYears += floor((($plusMonths-1)/12));
 1627+ }
 1628+
 1629+ $addMonths += $m;
 1630+ $plusMonths = $addMonths;
 1631+
 1632+ if ($plusMonths > 12){
 1633+ $addMonths = ((($plusMonths-1) % 12)+1);
 1634+ $addYears += floor((($plusMonths-1)/12));
 1635+ }
 1636+
 1637+ $result = date("m/d/Y H:i:s",mktime(0,0,0,$addMonths,$d,$addYears));
 1638+
 1639+ return $result;
 1640+
 1641+ }
 1642+
 1643+ /**
 1644+ * This method returns a tasks Gantt representation
 1645+ *
 1646+ * @param $id string, id of task that has to be converted
 1647+ * @return string, for JSGAntt
 1648+ */
 1649+ public function getGanttChart($id){
 1650+
 1651+ $res = '';
 1652+ $this->setId($id);
 1653+ $predStr = '';
 1654+
 1655+ $levelCheck = array();
 1656+
 1657+ $label = $this->getLabel();
 1658+
 1659+
 1660+ if ($label != 'unlabeled'){
 1661+
 1662+ //cut label if > 35 digits
 1663+ if (strlen($label) > 35) {
 1664+ $label=substr($label,0,35);
 1665+ $label .="...";
 1666+ }
 1667+
 1668+ if ($this->getColor() == '') $color = 'ff00ff';
 1669+ else $color = $this->getColor();
 1670+
 1671+ if ($this->getHyperlink() == '') $help = '';
 1672+ else $help = $this->getHyperlink();
 1673+
 1674+ if ($this->getPictureLink() == '') $pictureLink = '';
 1675+ else $pictureLink = $this->getPictureLink();
 1676+
 1677+ if ($this->getPictureURL() == '') $pictureURL = '';
 1678+ else $pictureURL = $this->getPictureURL();
 1679+
 1680+
 1681+ if ($this->isMilestone() == true) $milestone = 1;
 1682+ else $milestone = 0;
 1683+
 1684+ if ($this->getResource() == null) $resource = '';
 1685+ else $resource = $this->getResource();
 1686+
 1687+ if ($this->getGroup() == null) $group = 0;
 1688+ else $group = $this->getGroup();
 1689+
 1690+ if ($this->getParent() == null) $parent = 0;
 1691+ else $parent = $this->getParent();
 1692+
 1693+ if ($this->getOpen() == null) $open = 1;
 1694+ else $open = $this->getOpen();
 1695+
 1696+ if ($this->getCaption() == null) $caption = "";
 1697+ else $caption = $this->getCaption();
 1698+
 1699+ if ($this->getProgress() == null) $progress = "0";
 1700+ else $progress = $this->getProgress();
 1701+
 1702+ $startdate = $this->getGanttStartDate();
 1703+ $enddate = $this->getGanttEndDate();
 1704+
 1705+ //set dependence (red arrow from predecessor)
 1706+ $depend = "";
 1707+ $allt = $this->getPredecessors();
 1708+ foreach ($allt as $t) {
 1709+ $depend .= $t->getUid() . ",";
 1710+ }
 1711+ if (strlen($depend)>0){
 1712+ $depend = substr($depend, 0, -1);
 1713+ }
 1714+ //set id
 1715+ $id = $this->getUid();
 1716+
 1717+ $res .='g.AddTaskItem(new JSGantt.TaskItem('.$id. ',\'' .$label.'\', \''.$startdate. '\',\'' .$enddate.'\',\''.$color.'\', \''.$help.'\', '.$milestone.', \''.$resource.'\','.$progress.', '.$group.', '.$parent.', '.$open.', "'.$depend.'","","'.$pictureURL.'","'.$pictureLink.'"));';
 1718+ $res .="\r\n";
 1719+
 1720+ }
 1721+
 1722+ return array($res,$id);
 1723+ }
 1724+
 1725+ /**
 1726+ * This method returns a tasks XML representation
 1727+ *
 1728+ * @param $id string, id of task that has to be converted
 1729+ * @return string, XML representation
 1730+ */
 1731+ public function getXML($id){
 1732+
 1733+ $res = '';
 1734+ //if (($this->m_plannedFinish!=null) && ($this->m_plannedStart!=null)){
 1735+ $this->m_id = $id;
 1736+ $id++;
 1737+ $res .= "<Task>\r\n";
 1738+ $res .= "<UID>" . $this->getUid() . "</UID>\r\n";
 1739+ $res .= "<ID>" . $this->m_id . "</ID>\r\n";
 1740+ if ($this->getLabel()=='unlabeled'){
 1741+ $res .= "<Name>" . $this->m_page . "</Name>\r\n";
 1742+ }else{
 1743+ $res .= "<Name>" . $this->replaceLabelChars($this->getLabel()) . "</Name>\r\n";
 1744+ }
 1745+ $res .= "<Type>2</Type>\r\n";
 1746+ $res .= "<IsNull>0</IsNull>\r\n";
 1747+ if($this->m_timestamp!=null)
 1748+ $res .= "<CreateDate>" . date("Y-m-d", $this->m_timestamp) . "T" . date("H:i:s", $this->m_timestamp) . "</CreateDate>\r\n";
 1749+ $res .= "<WBS>" . $this->WBStoSTring($this->m_WBS) . "</WBS>\r\n";
 1750+ $res .= "<OutlineNumber>" . $this->WBStoSTring($this->m_WBS) . "</OutlineNumber>\r\n";
 1751+ $res .= "<OutlineLevel>" . $this->m_outlineLevel . "</OutlineLevel>\r\n";
 1752+ $res .= "<CalendarUID>3</CalendarUID>\r\n";
 1753+ if ($this->m_plannedStart!=null) {
 1754+ $res .= "<Start>" . $this->parsedate($this->m_plannedStart) . "</Start>\r\n";
 1755+ $res .= "<ConstraintType>2</ConstraintType>\r\n";
 1756+ $res .= "<ConstraintDate>" . $this->parsedate($this->m_plannedStart) . "</ConstraintDate>\r\n";
 1757+ }
 1758+ if ($this->m_plannedFinish!=null)
 1759+ $res .= "<Finish>" . $this->parsedate($this->m_plannedFinish) . "</Finish>\r\n";
 1760+ if ($this->m_earlyStart!=null)
 1761+ $res .= "<EarlyStart>" . $this->parsedate($this->m_earlyStart) . "</EarlyStart>\r\n";
 1762+ if ($this->m_earlyFinish!=null)
 1763+ $res .= "<EarlyFinish>" . $this->parsedate($this->m_earlyFinish) . "</EarlyFinish>\r\n";
 1764+ if ($this->m_lateStart!=null)
 1765+ $res .= "<LateStart>" . $this->parsedate($this->m_lateStart) . "</LateStart>\r\n";
 1766+ if ($this->m_lateFinish!=null)
 1767+ $res .= "<LateFinish>" . $this->parsedate($this->m_lateFinish) . "</LateFinish>\r\n";
 1768+ $res .= "<Hyperlink>".$this->replaceLabelChars($this->getLabel())."</Hyperlink>\r\n";
 1769+ $res .= "<HyperlinkAddress>". $this->m_hyperlink ."</HyperlinkAddress>\r\n";
 1770+ foreach ($this->m_predecessors as $pred){
 1771+ $res .= "<PredecessorLink>\r\n";
 1772+ $res .= "<PredecessorUID>". $pred->getUid() ."</PredecessorUID>\r\n";
 1773+ $res .= "<Type>1</Type>\r\n";
 1774+ $res .= "<CrossProject>0</CrossProject>\r\n";
 1775+ $res .= "<LinkLag>0</LinkLag>\r\n";
 1776+ $res .= "<LagFormat>7</LagFormat>\r\n";
 1777+ $res .= "</PredecessorLink>\r\n";
 1778+ }
 1779+ $res .= "<FixedCostAccrual>3</FixedCostAccrual>\r\n";
 1780+ $res .= "</Task>\r\n";
 1781+ //}
 1782+ return array($res,$id);
 1783+ }
 1784+
 1785+ /**
 1786+ * This method returns a string represenation of the work breakdown structure
 1787+ *
 1788+ * @param $wbs array, work breakdown structure
 1789+ * @return string, string representation of wbs
 1790+ */
 1791+ public function WBStoString($wbs){
 1792+ $res = '';
 1793+ for ($i=1; $i<count($wbs);$i++){
 1794+
 1795+ $res .= $wbs[$i] .'.';
 1796+ }
 1797+ $res = substr($res, 0, -1);
 1798+ return $res;
 1799+ }
 1800+}
 1801+
 1802+class ProjectManagementResource extends ProjectManagementElement{
 1803+
 1804+ /**
 1805+ * This method returns an XML represenation of the Element
 1806+ *
 1807+ * @return string, XML representation of Element
 1808+ */
 1809+ public function getXML(){
 1810+
 1811+ $res = '';
 1812+ $res .= "<Resource>\r\n";
 1813+ $res .= "<UID>" . $this->getUid() . "</UID>\r\n";
 1814+ $res .= "<ID>" . $this->getId() . "</ID>\r\n";
 1815+ if ($this->m_label=='unlabeled'){
 1816+ $res .= "<Name>" . $this->m_page . "</Name>\r\n";
 1817+ }else{
 1818+ $res .= "<Name>" . $this->replaceLabelChars($this->m_label) . "</Name>\r\n";
 1819+ }
 1820+ $res .= "<Type>1</Type>\r\n";
 1821+ $res .= "<IsNull>0</IsNull>\r\n";
 1822+ $res .= "</Resource>\r\n";
 1823+ return $res;
 1824+ }
 1825+
 1826+}
\ No newline at end of file
Index: trunk/extensions/SemanticProjectManagement/libs/ganttchart/jsgantt.css
@@ -0,0 +1,53 @@
 2+
 3+// These are the class/styles used by various objects in GanttChart. However, Firefox has problems deciphering class style when DIVs are embedded in other DIVs.
 4+
 5+// GanttChart makes heavy use of embedded DIVS, thus the style are often embedded directly in the objects html. If this could be resolved with Firefox, it would
 6+
 7+// make alot of the code look simpleer/cleaner without all the embedded styles
 8+
 9+
 10+
 11+..gantt { font-family:tahoma, arial, verdana; font-size:10px;}
 12+
 13+..gdatehead { BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; HEIGHT: 18px }
 14+
 15+..ghead { BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 24px; HEIGHT: 20px }
 16+
 17+..gname { BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; WIDTH: 18px; HEIGHT: 18px }
 18+
 19+..ghead A { FONT-SIZE: 10px; COLOR: #000000; TEXT-DECORATION: none }
 20+
 21+..gheadwkend A { FONT-SIZE: 10px; COLOR: #000000; TEXT-DECORATION: none }
 22+
 23+..gheadwkend { BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 24px; HEIGHT: 20px; background-color: #cfcfcf }
 24+
 25+..gfiller { BORDER-TOP: #efefef 1px solid; BORDER-LEFT: #efefef 1px solid; WIDTH: 18px; HEIGHT: 18px }
 26+
 27+..gfillerwkend { BORDER-LEFT: #efefef 1px solid; WIDTH: 18px; HEIGHT: 18px; BACKGROUND-COLOR: #cfcfcf }
 28+
 29+..gitem { BORDER-TOP: #cccccc 1px solid; WIDTH: 18px; HEIGHT: 18px }
 30+
 31+..gitemwkend { BORDER-TOP: #cccccc 1px solid; BORDER-LEFT: #cccccc 1px solid; WIDTH: 18px; HEIGHT: 18px }
 32+
 33+..gmilestone { BORDER-TOP: #efefef 1px solid; FONT-SIZE: 14px; OVERFLOW: hidden; BORDER-LEFT: #efefef 1px solid; WIDTH: 18px; HEIGHT: 18px}
 34+
 35+..gmilestonewkend { BORDER-TOP: #efefef 1px solid; BORDER-LEFT: #cccccc 1px solid; WIDTH: 18px; HEIGHT: 18px}
 36+
 37+..btn { BORDER-RIGHT: #ffffff; BORDER-TOP: #ffffff; FONT-WEIGHT: bold; FONT-SIZE: 10px; BORDER-LEFT: #ffffff; WIDTH: 12px; COLOR: #cccccc; BORDER-BOTTOM: #ffffff; BACKGROUND-COLOR: #ffffff }
 38+
 39+..hrcomplete { BORDER-RIGHT: #000000 2px solid; PADDING-RIGHT: 0px; BORDER-TOP: #000000 2px solid; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; BORDER-LEFT: #000000 2px solid; WIDTH: 20px; COLOR: #000000; PADDING-TOP: 0px; BORDER-BOTTOM: #000000 2px solid; HEIGHT: 4px }
 40+
 41+..hrhalfcomplete { BORDER-RIGHT: #000000 2px solid; BORDER-TOP: #000000 2px solid; BORDER-LEFT: #000000 2px solid; WIDTH: 9px; COLOR: #000000; BORDER-BOTTOM: #000000 2px solid; HEIGHT: 4px }
 42+
 43+..gweekend { font-family:tahoma, arial, verdana; font-size:11px; background-color:#EEEEEE; text-align:center; }
 44+
 45+..gtask { font-family:tahoma, arial, verdana; font-size:11px; background-color:#00FF00; text-align:center; }
 46+
 47+..gday { font-family:tahoma, arial, verdana; font-size:11px; text-align:center; }
 48+
 49+..gcomplete { background-color:black; height:5px; overflow: auto; margin-top:4px; }
 50+
 51+DIV.scroll { BORDER-RIGHT: #efefef 1px solid; PADDING-RIGHT: 0px; BORDER-TOP: #efefef 1px solid; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; OVERFLOW: hidden; BORDER-LEFT: #efefef 1px solid; WIDTH: 420px; PADDING-TOP: 0px; BORDER-BOTTOM: #efefef 1px solid; BACKGROUND-COLOR: #ffffff }
 52+
 53+DIV.scroll2 { position:relative; PADDING-RIGHT: 0px; overflow:auto ;overflow-x:scroll;overflow-y:hidden; PADDING-LEFT: 0px; PADDING-BOTTOM: 0px; WIDTH: 482px; PADDING-TOP: 0px; BACKGROUND-COLOR: #ffffff }
 54+
Property changes on: trunk/extensions/SemanticProjectManagement/libs/ganttchart/jsgantt.css
___________________________________________________________________
Added: svn:executable
155 + *
Index: trunk/extensions/SemanticProjectManagement/libs/ganttchart/test.html
@@ -0,0 +1,30 @@
 2+<html>
 3+<head>
 4+</head>
 5+<body>
 6+<p>test</p>
 7+<link rel="stylesheet" type="text/css" href="https://www.mediawiki.org/Users/fde/SVN/development/SemanticProjectManagement/libs/ganttchart/jsgantt.css" />
 8+<script language="javascript" src="/Users/fde/SVN/development/SemanticProjectManagement/libs/ganttchart/jsgantt.js"></script>
 9+<div style="position:relative" class="gantt" id="GanttChartDIV"></div>
 10+<p><script language="javascript">
 11+var g = new JSGantt.GanttChart('g',document.getElementById('GanttChartDIV'), 'hour');
 12+g.setShowRes(0); // Show/Hide Responsible (0/1)
 13+g.setShowDur(0); // Show/Hide Duration (0/1)
 14+g.setShowComp(1); // Show/Hide&#160;% Complete(0/1)
 15+g.setCaptionType('Complete'); // Set to Show Caption
 16+g.setFormatArr("hour","day","week","month");
 17+g.AddTaskItem(new JSGantt.TaskItem(10,'MasterTask of tc1', '','','4a4aff', 'http://km.aifb.kit.edu/projects/active-process/index.php/Http://psi.vcad-vlab.net/inst/project/tc1%3FTask_1', 0, '',0, 1, 0, 1, "","",'discuss_icon.png'));
 18+g.AddTaskItem(new JSGantt.TaskItem(1010,'Analog Floorplanning of pll', '01/02/2006 10:00:00','01/02/2006 11:09:59','ffee05', 'http://km.aifb.kit.edu/projects/active-process/index.php/Http://psi.vcad-vlab.net/inst/project/tc1/simulation/1_per_20agents%3FTask_117CADB126758CE3FF', 0, '',100, 0, 10, 1,'',"",'discuss_icon.png','http://test.de'));
 19+g.AddTaskItem(new JSGantt.TaskItem(1011,'Analog Floorplanning of pll_cp', '01/02/2006 11:09:59','01/02/2006 13:44:58','ffee05', 'http://km.aifb.kit.edu/projects/active-process/index.php/Http://psi.vcad-vlab.net/inst/project/tc1/simulation/1_per_20agents%3FTask_1081203126758CE40E', 0, '',100, 0, 10, 1, 1010));
 20+g.AddTaskItem(new JSGantt.TaskItem(1012,'Analog Floorplanning of pll_iqdiv2', '01/02/2006 13:44:58','01/02/2006 15:54:57','ffee05', 'http://km.aifb.kit.edu/projects/active-process/index.php/Http://psi.vcad-vlab.net/inst/project/tc1/simulation/1_per_20agents%3FTask_9E5119126758CE3FF', 0, '',100, 0, 10, 1, 1010));
 21+g.AddTaskItem(new JSGantt.TaskItem(1013,'Analog Layout of pll_cp_dni', '01/02/2006 15:54:57','01/02/2006 18:11:52','ffee05', 'http://km.aifb.kit.edu/projects/active-process/index.php/Http://psi.vcad-vlab.net/inst/project/tc1/simulation/1_per_20agents%3FTask_D68BB1126758CE40E', 0, '',100, 0, 10, 1, 1011));
 22+g.AddTaskItem(new JSGantt.TaskItem(1014,'Analog Layout of pll_cp_igen', '01/02/2006 18:11:52','01/03/2006 04:32:57','ffee05', 'http://km.aifb.kit.edu/projects/active-process/index.php/Http://psi.vcad-vlab.net/inst/project/tc1/simulation/1_per_20agents%3FTask_44D90A126758CE40E', 0, '',100, 0, 10, 1, 1011));
 23+g.AddTaskItem(new JSGantt.TaskItem(1015,'Analog Layout of pll_cp', '01/03/2006 04:32:57','01/04/2006 08:10:03','ffee05', 'http://km.aifb.kit.edu/projects/active-process/index.php/Http://psi.vcad-vlab.net/inst/project/tc1/simulation/1_per_20agents%3FTask_1B9C1DA126758CE3FF', 0, '',100, 0, 10, 1, 1011,"",'discuss_icon.png'));
 24+g.AddTaskItem(new JSGantt.TaskItem(1016,'Analog Layout of pll_iqdiv2', '01/04/2006 08:10:03','01/04/2006 16:13:16','ffee05', 'http://km.aifb.kit.edu/projects/active-process/index.php/Http://psi.vcad-vlab.net/inst/project/tc1/simulation/1_per_20agents%3FTask_10723B6126758CE3FF', 0, '',100, 0, 10, 1, 1014));
 25+g.AddTaskItem(new JSGantt.TaskItem(1017,'Analog Layout of pll_lf', '01/04/2006 16:13:16','01/04/2006 19:47:13','ffee05', 'http://km.aifb.kit.edu/projects/active-process/index.php/Http://psi.vcad-vlab.net/inst/project/tc1/simulation/1_per_20agents%3FTask_66004F126758CE3FF', 0, '',100, 0, 10, 1, 1010));
 26+g.AddTaskItem(new JSGantt.TaskItem(1018,'Analog Layout of pll', '01/04/2006 19:47:13','01/05/2006 21:50:59','ffee05', 'http://km.aifb.kit.edu/projects/active-process/index.php/Http://psi.vcad-vlab.net/inst/project/tc1/simulation/1_per_20agents%3FTask_1E7CC54126758CE3FF', 0, '',100, 0, 10, 1, 1016));
 27+g.Draw();
 28+g.DrawDependencies();
 29+</script>
 30+</body>
 31+</html>
\ No newline at end of file
Index: trunk/extensions/SemanticProjectManagement/libs/ganttchart/jsgantt.js
@@ -0,0 +1,1693 @@
 2+/*
 3+ _ ___ _ _ _ ____
 4+ (_)___ / _ \__ _ _ __ | |_| |_ / | |___ \
 5+ | / __| / /_\/ _` | '_ \| __| __| | | __) |
 6+ | \__ \/ /_\\ (_| | | | | |_| |_ | |_ / __/
 7+ _/ |___/\____/\__,_|_| |_|\__|\__| |_(_)_____|
 8+|__/
 9+
 10+Copyright (c) 2009, Shlomy Gantz BlueBrick Inc. All rights reserved.
 11+
 12+*
 13+* Redistribution and use in source and binary forms, with or without
 14+* modification, are permitted provided that the following conditions are met:
 15+* * Redistributions of source code must retain the above copyright
 16+* notice, this list of conditions and the following disclaimer.
 17+* * Redistributions in binary form must reproduce the above copyright
 18+* notice, this list of conditions and the following disclaimer in the
 19+* documentation and/or other materials provided with the distribution.
 20+* * Neither the name of Shlomy Gantz or BlueBrick Inc. nor the
 21+* names of its contributors may be used to endorse or promote products
 22+* derived from this software without specific prior written permission.
 23+*
 24+* THIS SOFTWARE IS PROVIDED BY SHLOMY GANTZ/BLUEBRICK INC. ''AS IS'' AND ANY
 25+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 26+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 27+* DISCLAIMED. IN NO EVENT SHALL SHLOMY GANTZ/BLUEBRICK INC. BE LIABLE FOR ANY
 28+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 29+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 30+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 31+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 32+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 33+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
 34+*/
 35+
 36+var JSGantt; if (!JSGantt) JSGantt = {};
 37+
 38+var vTimeout = 0;
 39+var vBenchTime = new Date().getTime();
 40+
 41+JSGantt.isIE = function () {
 42+
 43+ if(typeof document.all != 'undefined')
 44+ return true;
 45+ else
 46+ return false;
 47+}
 48+
 49+
 50+JSGantt.TaskItem = function(pID, pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend, pCaption, pPicture, pPictureLink)
 51+{
 52+
 53+ var vID = pID;
 54+ var vName = pName;
 55+ var vStart = new Date();
 56+ var vEnd = new Date();
 57+ var vColor = pColor;
 58+ var vLink = pLink;
 59+ var vMile = pMile;
 60+ var vRes = pRes;
 61+ var vComp = pComp;
 62+ var vGroup = pGroup;
 63+ var vParent = pParent;
 64+ var vOpen = pOpen;
 65+ var vDepend = pDepend;
 66+ var vCaption = pCaption;
 67+ var vPicture = pPicture;
 68+ var vPictureLink = pPictureLink;
 69+ var vDuration = '';
 70+ var vLevel = 0;
 71+ var vNumKid = 0;
 72+ var vVisible = 1;
 73+ var x1, y1, x2, y2;
 74+
 75+ if (vGroup != 1)
 76+ {
 77+ vStart = JSGantt.parseDateStr(pStart,g.getDateInputFormat());
 78+ vEnd = JSGantt.parseDateStr(pEnd,g.getDateInputFormat());
 79+ }
 80+
 81+ this.getID = function(){ return vID };
 82+ this.getName = function(){ return vName };
 83+ this.getStart = function(){ return vStart};
 84+ this.getEnd = function(){ return vEnd };
 85+ this.getColor = function(){ return vColor};
 86+ this.getLink = function(){ return vLink };
 87+ this.getMile = function(){ return vMile };
 88+ this.getPictureLink = function(){ return vPictureLink };
 89+ this.getPicture = function(){ return vPicture };
 90+ this.getDepend = function(){ if(vDepend) return vDepend; else return null };
 91+ this.getCaption = function(){ if(vCaption) return vCaption; else return ''; };
 92+ this.getResource = function(){ if(vRes) return vRes; else return '&nbsp'; };
 93+ this.getCompVal = function(){ if(vComp) return vComp; else return 0; };
 94+ this.getCompStr = function(){ if(vComp) return vComp+'%'; else return ''; };
 95+
 96+ this.getDuration = function(vFormat){
 97+ if (vMile)
 98+ vDuration = '-';
 99+ else if (vFormat=='hour')
 100+ {
 101+ tmpPer = Math.ceil((this.getEnd() - this.getStart()) / ( 60 * 60 * 1000) );
 102+ if(tmpPer == 1)
 103+ vDuration = '1 Hour';
 104+ else
 105+ vDuration = tmpPer + ' Hours';
 106+ }
 107+
 108+ else if (vFormat=='minute')
 109+ {
 110+ tmpPer = Math.ceil((this.getEnd() - this.getStart()) / ( 60 * 1000) );
 111+ if(tmpPer == 1)
 112+ vDuration = '1 Minute';
 113+ else
 114+ vDuration = tmpPer + ' Minutes';
 115+ }
 116+
 117+ else { //if(vFormat == 'day') {
 118+ tmpPer = Math.ceil((this.getEnd() - this.getStart()) / (24 * 60 * 60 * 1000) + 1);
 119+ if(tmpPer == 1) vDuration = '1 Day';
 120+ else vDuration = tmpPer + ' Days';
 121+ }
 122+
 123+ //else if(vFormat == 'week') {
 124+ // tmpPer = ((this.getEnd() - this.getStart()) / (24 * 60 * 60 * 1000) + 1)/7;
 125+ // if(tmpPer == 1) vDuration = '1 Week';
 126+ // else vDuration = tmpPer + ' Weeks';
 127+ //}
 128+
 129+ //else if(vFormat == 'month') {
 130+ // tmpPer = ((this.getEnd() - this.getStart()) / (24 * 60 * 60 * 1000) + 1)/30;
 131+ // if(tmpPer == 1) vDuration = '1 Month';
 132+ // else vDuration = tmpPer + ' Months';
 133+ //}
 134+
 135+ //else if(vFormat == 'quater') {
 136+ // tmpPer = ((this.getEnd() - this.getStart()) / (24 * 60 * 60 * 1000) + 1)/120;
 137+ // if(tmpPer == 1) vDuration = '1 Qtr';
 138+ // else vDuration = tmpPer + ' Qtrs';
 139+ //}
 140+ return( vDuration )
 141+ };
 142+
 143+ this.getParent = function(){ return vParent };
 144+ this.getGroup = function(){ return vGroup };
 145+ this.getOpen = function(){ return vOpen };
 146+ this.getLevel = function(){ return vLevel };
 147+ this.getNumKids = function(){ return vNumKid };
 148+ this.getStartX = function(){ return x1 };
 149+ this.getStartY = function(){ return y1 };
 150+ this.getEndX = function(){ return x2 };
 151+ this.getEndY = function(){ return y2 };
 152+ this.getVisible = function(){ return vVisible };
 153+ this.setDepend = function(pDepend){ vDepend = pDepend;};
 154+ this.setStart = function(pStart){ vStart = pStart;};
 155+ this.setEnd = function(pEnd) { vEnd = pEnd; };
 156+ this.setLevel = function(pLevel){ vLevel = pLevel;};
 157+ this.setNumKid = function(pNumKid){ vNumKid = pNumKid;};
 158+ this.setCompVal = function(pCompVal){ vComp = pCompVal;};
 159+ this.setStartX = function(pX) {x1 = pX; };
 160+ this.setStartY = function(pY) {y1 = pY; };
 161+ this.setEndX = function(pX) {x2 = pX; };
 162+ this.setEndY = function(pY) {y2 = pY; };
 163+ this.setOpen = function(pOpen) {vOpen = pOpen; };
 164+ this.setVisible = function(pVisible) {vVisible = pVisible; };
 165+
 166+ }
 167+
 168+
 169+ // function that loads the main gantt chart properties and functions
 170+ // pDiv: (required) this is a DIV object created in HTML
 171+ // pStart: UNUSED - future use to force minimum chart date
 172+ // pEnd: UNUSED - future use to force maximum chart date
 173+ // pWidth: UNUSED - future use to force chart width and cause objects to scale to fit within that width
 174+ // pShowRes: UNUSED - future use to turn on/off display of resource names
 175+ // pShowDur: UNUSED - future use to turn on/off display of task durations
 176+ // pFormat: (required) - used to indicate whether chart should be drawn in "day", "week", "month", or "quarter" format
 177+ // pCationType - what type of Caption to show: Caption, Resource, Duration, Complete
 178+JSGantt.GanttChart = function(pGanttVar, pDiv, pFormat)
 179+{
 180+
 181+ var vGanttVar = pGanttVar;
 182+ var vDiv = pDiv;
 183+ var vFormat = pFormat;
 184+ var vShowRes = 1;
 185+ var vShowDur = 1;
 186+ var vShowComp = 1;
 187+ var vShowStartDate = 1;
 188+ var vShowEndDate = 1;
 189+ var vShowPicture = 1;
 190+ var vDateInputFormat = "mm/dd/yyyy";
 191+ var vDateDisplayFormat = "mm/dd/yy";
 192+ var vNumUnits = 0;
 193+ var vCaptionType;
 194+ var vDepId = 1;
 195+ var vTaskList = new Array();
 196+ var vFormatArr = new Array("day","week","month","quarter");
 197+ var vQuarterArr = new Array(1,1,1,2,2,2,3,3,3,4,4,4);
 198+ var vMonthDaysArr = new Array(31,28,31,30,31,30,31,31,30,31,30,31);
 199+ var vMonthArr = new Array("January","February","March","April","May","June","July","August","September","October","November","December");
 200+ this.setFormatArr = function() {
 201+ vFormatArr = new Array();
 202+ for(var i = 0; i < arguments.length; i++) {vFormatArr[i] = arguments[i];}
 203+ if(vFormatArr.length>4){vFormatArr.length=4;}
 204+ };
 205+ this.setShowRes = function(pShow) { vShowRes = pShow; };
 206+ this.setShowDur = function(pShow) { vShowDur = pShow; };
 207+ this.setShowComp = function(pShow) { vShowComp = pShow; };
 208+ this.setShowStartDate = function(pShow) { vShowStartDate = pShow; };
 209+ this.setShowEndDate = function(pShow) { vShowEndDate = pShow; };
 210+ this.setShowPicture = function(pShow) { vShowPicture = pShow; };
 211+ this.setDateInputFormat = function(pShow) { vDateInputFormat = pShow; };
 212+ this.setDateDisplayFormat = function(pShow) { vDateDisplayFormat = pShow; };
 213+ this.setCaptionType = function(pType) { vCaptionType = pType };
 214+ this.setFormat = function(pFormat){
 215+ vFormat = pFormat;
 216+ this.Draw();
 217+ };
 218+
 219+ this.getShowRes = function(){ return vShowRes };
 220+ this.getShowDur = function(){ return vShowDur };
 221+ this.getShowComp = function(){ return vShowComp };
 222+ this.getShowStartDate = function(){ return vShowStartDate };
 223+ this.getShowEndDate = function(){ return vShowEndDate };
 224+ this.getShowPicture = function(){ return vShowPicture };
 225+ this.getDateInputFormat = function() { return vDateInputFormat };
 226+ this.getDateDisplayFormat = function() { return vDateDisplayFormat };
 227+ this.getCaptionType = function() { return vCaptionType };
 228+ this.CalcTaskXY = function ()
 229+ {
 230+ var vList = this.getList();
 231+ var vTaskDiv;
 232+ var vParDiv;
 233+ var vLeft, vTop, vHeight, vWidth;
 234+
 235+ for(i = 0; i < vList.length; i++)
 236+ {
 237+ vID = vList[i].getID();
 238+ vTaskDiv = document.getElementById("taskbar_"+vID);
 239+ vBarDiv = document.getElementById("bardiv_"+vID);
 240+ vParDiv = document.getElementById("childgrid_"+vID);
 241+
 242+ if(vBarDiv) {
 243+ vList[i].setStartX( vBarDiv.offsetLeft );
 244+ vList[i].setStartY( vParDiv.offsetTop+vBarDiv.offsetTop+6 );
 245+ vList[i].setEndX( vBarDiv.offsetLeft + vBarDiv.offsetWidth );
 246+ vList[i].setEndY( vParDiv.offsetTop+vBarDiv.offsetTop+6 );
 247+ }
 248+ }
 249+ }
 250+
 251+ this.AddTaskItem = function(value)
 252+ {
 253+ vTaskList.push(value);
 254+ }
 255+
 256+ this.getList = function() { return vTaskList };
 257+
 258+ this.clearDependencies = function()
 259+ {
 260+ var parent = document.getElementById('rightside');
 261+ var depLine;
 262+ var vMaxId = vDepId;
 263+ for ( i=1; i<vMaxId; i++ ) {
 264+ depLine = document.getElementById("line"+i);
 265+ if (depLine) { parent.removeChild(depLine); }
 266+ }
 267+ vDepId = 1;
 268+ }
 269+
 270+
 271+ // sLine: Draw a straight line (colored one-pixel wide DIV), need to parameterize doc item
 272+ this.sLine = function(x1,y1,x2,y2) {
 273+
 274+ vLeft = Math.min(x1,x2);
 275+ vTop = Math.min(y1,y2);
 276+ vWid = Math.abs(x2-x1) + 1;
 277+ vHgt = Math.abs(y2-y1) + 1;
 278+
 279+ vDoc = document.getElementById('rightside');
 280+
 281+ // retrieve DIV
 282+ var oDiv = document.createElement('div');
 283+
 284+ oDiv.id = "line"+vDepId++;
 285+ oDiv.style.position = "absolute";
 286+ oDiv.style.margin = "0px";
 287+ oDiv.style.padding = "0px";
 288+ oDiv.style.overflow = "hidden";
 289+ oDiv.style.border = "0px";
 290+
 291+ // set attributes
 292+ oDiv.style.zIndex = 0;
 293+ oDiv.style.backgroundColor = "red";
 294+
 295+ oDiv.style.left = vLeft + "px";
 296+ oDiv.style.top = vTop + "px";
 297+ oDiv.style.width = vWid + "px";
 298+ oDiv.style.height = vHgt + "px";
 299+
 300+ oDiv.style.visibility = "visible";
 301+
 302+ vDoc.appendChild(oDiv);
 303+
 304+ }
 305+
 306+
 307+ // dLine: Draw a diaganol line (calc line x,y paisrs and draw multiple one-by-one sLines)
 308+ this.dLine = function(x1,y1,x2,y2) {
 309+
 310+ var dx = x2 - x1;
 311+ var dy = y2 - y1;
 312+ var x = x1;
 313+ var y = y1;
 314+
 315+ var n = Math.max(Math.abs(dx),Math.abs(dy));
 316+ dx = dx / n;
 317+ dy = dy / n;
 318+ for ( i = 0; i <= n; i++ )
 319+ {
 320+ vx = Math.round(x);
 321+ vy = Math.round(y);
 322+ this.sLine(vx,vy,vx,vy);
 323+ x += dx;
 324+ y += dy;
 325+ }
 326+
 327+ }
 328+
 329+ this.drawDependency =function(x1,y1,x2,y2)
 330+ {
 331+ if(x1 + 10 < x2)
 332+ {
 333+ this.sLine(x1,y1,x1+4,y1);
 334+ this.sLine(x1+4,y1,x1+4,y2);
 335+ this.sLine(x1+4,y2,x2,y2);
 336+ this.dLine(x2,y2,x2-3,y2-3);
 337+ this.dLine(x2,y2,x2-3,y2+3);
 338+ this.dLine(x2-1,y2,x2-3,y2-2);
 339+ this.dLine(x2-1,y2,x2-3,y2+2);
 340+ }
 341+ else
 342+ {
 343+ this.sLine(x1,y1,x1+4,y1);
 344+ this.sLine(x1+4,y1,x1+4,y2-10);
 345+ this.sLine(x1+4,y2-10,x2-8,y2-10);
 346+ this.sLine(x2-8,y2-10,x2-8,y2);
 347+ this.sLine(x2-8,y2,x2,y2);
 348+ this.dLine(x2,y2,x2-3,y2-3);
 349+ this.dLine(x2,y2,x2-3,y2+3);
 350+ this.dLine(x2-1,y2,x2-3,y2-2);
 351+ this.dLine(x2-1,y2,x2-3,y2+2);
 352+ }
 353+ }
 354+
 355+ this.DrawDependencies = function () {
 356+
 357+ //First recalculate the x,y
 358+ this.CalcTaskXY();
 359+
 360+ this.clearDependencies();
 361+
 362+ var vList = this.getList();
 363+ for(var i = 0; i < vList.length; i++)
 364+ {
 365+
 366+ vDepend = vList[i].getDepend();
 367+ if(vDepend) {
 368+
 369+ var vDependStr = vDepend + '';
 370+ var vDepList = vDependStr.split(',');
 371+ var n = vDepList.length;
 372+
 373+ for(var k=0;k<n;k++) {
 374+ var vTask = this.getArrayLocationByID(vDepList[k]);
 375+
 376+ if(vList[vTask].getVisible()==1)
 377+ this.drawDependency(vList[vTask].getEndX(),vList[vTask].getEndY(),vList[i].getStartX()-1,vList[i].getStartY())
 378+ }
 379+ }
 380+ }
 381+ }
 382+
 383+
 384+ this.getArrayLocationByID = function(pId) {
 385+
 386+ var vList = this.getList();
 387+ for(var i = 0; i < vList.length; i++)
 388+ {
 389+ if(vList[i].getID()==pId)
 390+ return i;
 391+ }
 392+ }
 393+
 394+
 395+ this.Draw = function()
 396+ {
 397+ var vMaxDate = new Date();
 398+ var vMinDate = new Date();
 399+ var vTmpDate = new Date();
 400+ var vNxtDate = new Date();
 401+ var vCurrDate = new Date();
 402+ var vTaskLeft = 0;
 403+ var vTaskRight = 0;
 404+ var vNumCols = 0;
 405+ var vID = 0;
 406+ var vMainTable = "";
 407+ var vLeftTable = "";
 408+ var vRightTable = "";
 409+ var vDateRowStr = "";
 410+ var vItemRowStr = "";
 411+ var vColWidth = 0;
 412+ var vColUnit = 0;
 413+ var vChartWidth = 0;
 414+ var vNumDays = 0;
 415+ var vDayWidth = 0;
 416+ var vStr = "";
 417+ var vNameWidth = 220;
 418+ var vStatusWidth = 70;
 419+ var vPictureWidth = 20;
 420+ var vLeftWidth = 15 + 220 + 70 + 70 + 70 + 70 + 70+ 20;
 421+
 422+ if(vTaskList.length > 0)
 423+ {
 424+
 425+ // Process all tasks preset parent date and completion %
 426+ JSGantt.processRows(vTaskList, 0, -1, 1, 1);
 427+
 428+ // get overall min/max dates plus padding
 429+ vMinDate = JSGantt.getMinDate(vTaskList, vFormat);
 430+ vMaxDate = JSGantt.getMaxDate(vTaskList, vFormat);
 431+
 432+ // Calculate chart width variables. vColWidth can be altered manually to change each column width
 433+ // May be smart to make this a parameter of GanttChart or set it based on existing pWidth parameter
 434+ if(vFormat == 'day') {
 435+ vColWidth = 18;
 436+ vColUnit = 1;
 437+ }
 438+ else if(vFormat == 'week') {
 439+ vColWidth = 37;
 440+ vColUnit = 7;
 441+ }
 442+ else if(vFormat == 'month') {
 443+ vColWidth = 37;
 444+ vColUnit = 30;
 445+ }
 446+ else if(vFormat == 'quarter') {
 447+ vColWidth = 60;
 448+ vColUnit = 90;
 449+ }
 450+
 451+ else if(vFormat=='hour')
 452+ {
 453+ vColWidth = 18;
 454+ vColUnit = 1;
 455+ }
 456+
 457+ else if(vFormat=='minute')
 458+ {
 459+ vColWidth = 18;
 460+ vColUnit = 1;
 461+ }
 462+
 463+ vNumDays = (Date.parse(vMaxDate) - Date.parse(vMinDate)) / ( 24 * 60 * 60 * 1000);
 464+ vNumUnits = vNumDays / vColUnit;
 465+
 466+
 467+ vChartWidth = vNumUnits * vColWidth + 1;
 468+ vDayWidth = (vColWidth / vColUnit) + (1/vColUnit);
 469+
 470+ vMainTable =
 471+ '<TABLE id=theTable cellSpacing=0 cellPadding=0 border=0><TBODY><TR>' +
 472+ '<TD vAlign=top bgColor=#ffffff>';
 473+
 474+ if(vShowRes !=1) vNameWidth+=vStatusWidth;
 475+ if(vShowDur !=1) vNameWidth+=vStatusWidth;
 476+ if(vShowComp!=1) vNameWidth+=vStatusWidth;
 477+ if(vShowStartDate!=1) vNameWidth+=vStatusWidth;
 478+ if(vShowEndDate!=1) vNameWidth+=vStatusWidth;
 479+ if(vShowPicture!=1) vNameWidth+=vPictureWidth;
 480+ // DRAW the Left-side of the chart (names, resources, comp%)
 481+ vLeftTable =
 482+ '<DIV class=scroll id=leftside style="width:' + vLeftWidth + 'px"><TABLE cellSpacing=0 cellPadding=0 border=0><TBODY>' +
 483+ '<TR style="HEIGHT: 17px">' +
 484+ ' <TD style="WIDTH: 15px; HEIGHT: 17px"></TD>' +
 485+ ' <TD style="WIDTH: ' + vNameWidth + 'px; HEIGHT: 17px"><NOBR></NOBR></TD>';
 486+
 487+ if(vShowRes ==1) vLeftTable += ' <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>' ;
 488+ if(vShowDur ==1) vLeftTable += ' <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>' ;
 489+ if(vShowComp==1) vLeftTable += ' <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>' ;
 490+ if(vShowStartDate==1) vLeftTable += ' <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>' ;
 491+ if(vShowEndDate==1) vLeftTable += ' <TD style="WIDTH: ' + vStatusWidth + 'px; HEIGHT: 17px"></TD>' ;
 492+ if(vShowPicture==1) vLeftTable += ' <TD style="WIDTH: ' + vPictureWidth + 'px; HEIGHT: 17px"></TD>' ;
 493+ vLeftTable +=
 494+ '<TR style="HEIGHT: 20px">' +
 495+ ' <TD style="BORDER-TOP: #efefef 1px solid; WIDTH: 15px; HEIGHT: 20px"></TD>' +
 496+ ' <TD style="BORDER-TOP: #efefef 1px solid; WIDTH: ' + vNameWidth + 'px; HEIGHT: 20px"><NOBR></NOBR></TD>' ;
 497+
 498+ if(vShowRes ==1) vLeftTable += ' <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=center nowrap>Resource</TD>' ;
 499+ if(vShowDur ==1) vLeftTable += ' <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=center nowrap>Duration</TD>' ;
 500+ if(vShowComp==1) vLeftTable += ' <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=center nowrap>% Comp.</TD>' ;
 501+ if(vShowStartDate==1) vLeftTable += ' <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=center nowrap>Start Date</TD>' ;
 502+ if(vShowEndDate==1) vLeftTable += ' <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 60px; HEIGHT: 20px" align=center nowrap>End Date</TD>' ;
 503+ if(vShowPicture==1) vLeftTable += ' <TD style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; WIDTH: 20px; HEIGHT: 20px" align=center nowrap></TD>' ;
 504+ vLeftTable += '</TR>';
 505+
 506+ for(i = 0; i < vTaskList.length; i++)
 507+ {
 508+ if( vTaskList[i].getGroup()) {
 509+ vBGColor = "f3f3f3";
 510+ vRowType = "group";
 511+ } else {
 512+ vBGColor = "ffffff";
 513+ vRowType = "row";
 514+ }
 515+
 516+ vID = vTaskList[i].getID();
 517+
 518+ if(vTaskList[i].getVisible() == 0)
 519+ vLeftTable += '<TR id=child_' + vID + ' bgcolor=#' + vBGColor + ' style="display:none" onMouseover=g.mouseOver(this,' + vID + ',"left","' + vRowType + '") onMouseout=g.mouseOut(this,' + vID + ',"left","' + vRowType + '")>' ;
 520+ else
 521+ vLeftTable += '<TR id=child_' + vID + ' bgcolor=#' + vBGColor + ' onMouseover=g.mouseOver(this,' + vID + ',"left","' + vRowType + '") onMouseout=g.mouseOut(this,' + vID + ',"left","' + vRowType + '")>' ;
 522+
 523+ vLeftTable +=
 524+ ' <TD class=gdatehead style="WIDTH: 15px; HEIGHT: 20px; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;">&nbsp;</TD>' +
 525+ ' <TD class=gname style="WIDTH: ' + vNameWidth + 'px; HEIGHT: 20px; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px;" nowrap><NOBR><span style="color: #aaaaaa">';
 526+
 527+ for(j=1; j<vTaskList[i].getLevel(); j++) {
 528+ vLeftTable += '&nbsp&nbsp&nbsp&nbsp';
 529+ }
 530+
 531+ vLeftTable += '</span>';
 532+
 533+ if( vTaskList[i].getGroup()) {
 534+ if( vTaskList[i].getOpen() == 1)
 535+ vLeftTable += '<SPAN id="group_' + vID + '" style="color:#000000; cursor:pointer; font-weight:bold; FONT-SIZE: 12px;" onclick="JSGantt.folder(' + vID + ','+vGanttVar+');'+vGanttVar+'.DrawDependencies();">&ndash;</span><span style="color:#000000">&nbsp</SPAN>' ;
 536+ else
 537+ vLeftTable += '<SPAN id="group_' + vID + '" style="color:#000000; cursor:pointer; font-weight:bold; FONT-SIZE: 12px;" onclick="JSGantt.folder(' + vID + ','+vGanttVar+');'+vGanttVar+'.DrawDependencies();">+</span><span style="color:#000000">&nbsp</SPAN>' ;
 538+
 539+ } else {
 540+
 541+ vLeftTable += '<span style="color: #000000; font-weight:bold; FONT-SIZE: 12px;">&nbsp&nbsp&nbsp</span>';
 542+ }
 543+
 544+ vLeftTable +=
 545+ '<span onclick=JSGantt.taskLink("' + vTaskList[i].getLink() + '",300,200); style="cursor:pointer"> ' + vTaskList[i].getName() + '</span></NOBR></TD>' ;
 546+
 547+ if(vShowRes ==1) vLeftTable += ' <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><NOBR>' + vTaskList[i].getResource() + '</NOBR></TD>' ;
 548+ if(vShowDur ==1) vLeftTable += ' <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><NOBR>' + vTaskList[i].getDuration(vFormat) + '</NOBR></TD>' ;
 549+ if(vShowComp==1) vLeftTable += ' <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><NOBR>' + vTaskList[i].getCompStr() + '</NOBR></TD>' ;
 550+ if(vShowStartDate==1) vLeftTable += ' <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><NOBR>' + JSGantt.formatDateStr( vTaskList[i].getStart(), vDateDisplayFormat) + '</NOBR></TD>' ;
 551+ if(vShowEndDate==1) vLeftTable += ' <TD class=gname style="WIDTH: 60px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><NOBR>' + JSGantt.formatDateStr( vTaskList[i].getEnd(), vDateDisplayFormat) + '</NOBR></TD>' ;
 552+ if(vShowPicture==1) vLeftTable += ' <TD class=gname ' ;
 553+ if(vShowPicture==1 && vTaskList[i].getPictureLink()!="" ) vLeftTable += 'onclick=JSGantt.taskLink("' + vTaskList[i].getPictureLink() + '",300,200); ' ;
 554+ if(vShowPicture==1) vLeftTable += 'style="WIDTH: 20px; HEIGHT: 20px; TEXT-ALIGN: center; BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; background-image: url('+vTaskList[i].getPicture()+');' ;
 555+ if(vShowPicture==1 && vTaskList[i].getPictureLink()!="" ) vLeftTable += 'cursor:pointer;';
 556+ if(vShowPicture==1) vLeftTable += '" align=center><NOBR></NOBR></TD>';
 557+ vLeftTable += '</TR>';
 558+
 559+ }
 560+
 561+ // DRAW the date format selector at bottom left. Another potential GanttChart parameter to hide/show this selector
 562+ vLeftTable += '</TD></TR>' +
 563+ '<TR><TD border=1 colspan=5 align=left style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 11px; BORDER-LEFT: #efefef 1px solid; height=18px">&nbsp;&nbsp;Powered by <a href=http://www.jsgantt.com>jsGantt</a>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Format:';
 564+
 565+ if (vFormatArr.join().indexOf("minute")!=-1) {
 566+ if (vFormat=='minute') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="minute" checked>Minute';
 567+ else vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("minute",'+vGanttVar+'); VALUE="minute">Minute';
 568+ }
 569+
 570+ if (vFormatArr.join().indexOf("hour")!=-1) {
 571+ if (vFormat=='hour') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="hour" checked>Hour';
 572+ else vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("hour",'+vGanttVar+'); VALUE="hour">Hour';
 573+ }
 574+
 575+ if (vFormatArr.join().indexOf("day")!=-1) {
 576+ if (vFormat=='day') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="day" checked>Day';
 577+ else vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("day",'+vGanttVar+'); VALUE="day">Day';
 578+ }
 579+
 580+ if (vFormatArr.join().indexOf("week")!=-1) {
 581+ if (vFormat=='week') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="week" checked>Week';
 582+ else vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("week",'+vGanttVar+') VALUE="week">Week';
 583+ }
 584+
 585+ if (vFormatArr.join().indexOf("month")!=-1) {
 586+ if (vFormat=='month') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="month" checked>Month';
 587+ else vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("month",'+vGanttVar+') VALUE="month">Month';
 588+ }
 589+
 590+ if (vFormatArr.join().indexOf("quarter")!=-1) {
 591+ if (vFormat=='quarter') vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" VALUE="quarter" checked>Quarter';
 592+ else vLeftTable += '<INPUT TYPE=RADIO NAME="radFormat" onclick=JSGantt.changeFormat("quarter",'+vGanttVar+') VALUE="quarter">Quarter';
 593+ }
 594+
 595+// vLeftTable += '<INPUT TYPE=RADIO NAME="other" VALUE="other" style="display:none"> .';
 596+
 597+ vLeftTable += '</TD></TR></TBODY></TABLE></TD>';
 598+
 599+ vMainTable += vLeftTable;
 600+
 601+ // Draw the Chart Rows
 602+ vRightTable =
 603+ '<TD style="width: ' + vChartWidth + 'px;" vAlign=top bgColor=#ffffff>' +
 604+ '<DIV class=scroll2 id=rightside>' +
 605+ '<TABLE style="width: ' + vChartWidth + 'px;" cellSpacing=0 cellPadding=0 border=0>' +
 606+ '<TBODY><TR style="HEIGHT: 18px">';
 607+
 608+ vTmpDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate());
 609+ vTmpDate.setHours(0);
 610+ vTmpDate.setMinutes(0);
 611+
 612+ // Major Date Header
 613+ while(Date.parse(vTmpDate) <= Date.parse(vMaxDate))
 614+ {
 615+ vStr = vTmpDate.getFullYear() + '';
 616+ vStr = vStr.substring(2,4);
 617+
 618+
 619+ if(vFormat == 'minute')
 620+ {
 621+ vRightTable += '<td class=gdatehead style="FONT-SIZE: 12px; HEIGHT: 19px;" align=center colspan=60>' ;
 622+ vRightTable += JSGantt.formatDateStr(vTmpDate, vDateDisplayFormat) + ' ' + vTmpDate.getHours() + ':00 -' + vTmpDate.getHours() + ':59 </td>';
 623+ vTmpDate.setHours(vTmpDate.getHours()+1);
 624+ }
 625+
 626+ if(vFormat == 'hour')
 627+ {
 628+ vRightTable += '<td class=gdatehead style="FONT-SIZE: 12px; HEIGHT: 19px;" align=center colspan=24>' ;
 629+ vRightTable += JSGantt.formatDateStr(vTmpDate, vDateDisplayFormat) + '</td>';
 630+ vTmpDate.setDate(vTmpDate.getDate()+1);
 631+ }
 632+
 633+ if(vFormat == 'day')
 634+ {
 635+ vRightTable += '<td class=gdatehead style="FONT-SIZE: 12px; HEIGHT: 19px;" align=center colspan=7>' +
 636+ JSGantt.formatDateStr(vTmpDate,vDateDisplayFormat.substring(0,5)) + ' - ';
 637+ vTmpDate.setDate(vTmpDate.getDate()+6);
 638+ vRightTable += JSGantt.formatDateStr(vTmpDate, vDateDisplayFormat) + '</td>';
 639+ vTmpDate.setDate(vTmpDate.getDate()+1);
 640+ }
 641+ else if(vFormat == 'week')
 642+ {
 643+ vRightTable += '<td class=gdatehead align=center style="FONT-SIZE: 12px; HEIGHT: 19px;" width='+vColWidth+'px>`'+ vStr + '</td>';
 644+ vTmpDate.setDate(vTmpDate.getDate()+7);
 645+ }
 646+ else if(vFormat == 'month')
 647+ {
 648+ vRightTable += '<td class=gdatehead align=center style="FONT-SIZE: 12px; HEIGHT: 19px;" width='+vColWidth+'px>`'+ vStr + '</td>';
 649+ vTmpDate.setDate(vTmpDate.getDate() + 1);
 650+ while(vTmpDate.getDate() > 1)
 651+ {
 652+ vTmpDate.setDate(vTmpDate.getDate() + 1);
 653+ }
 654+ }
 655+ else if(vFormat == 'quarter')
 656+ {
 657+ vRightTable += '<td class=gdatehead align=center style="FONT-SIZE: 12px; HEIGHT: 19px;" width='+vColWidth+'px>`'+ vStr + '</td>';
 658+ vTmpDate.setDate(vTmpDate.getDate() + 81);
 659+ while(vTmpDate.getDate() > 1)
 660+ {
 661+ vTmpDate.setDate(vTmpDate.getDate() + 1);
 662+ }
 663+ }
 664+
 665+ }
 666+
 667+ vRightTable += '</TR><TR>';
 668+
 669+ // Minor Date header and Cell Rows
 670+ vTmpDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate());
 671+ vNxtDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate());
 672+ vNumCols = 0;
 673+
 674+ while(Date.parse(vTmpDate) <= Date.parse(vMaxDate))
 675+ {
 676+ if (vFormat == 'minute')
 677+ {
 678+
 679+ if( vTmpDate.getMinutes() ==0 )
 680+ vWeekdayColor = "ccccff";
 681+ else
 682+ vWeekdayColor = "ffffff";
 683+
 684+
 685+ vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">' + vTmpDate.getMinutes() + '</div></td>';
 686+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 687+ vTmpDate.setMinutes(vTmpDate.getMinutes() + 1);
 688+ }
 689+
 690+ else if (vFormat == 'hour')
 691+ {
 692+
 693+ if( vTmpDate.getHours() ==0 )
 694+ vWeekdayColor = "ccccff";
 695+ else
 696+ vWeekdayColor = "ffffff";
 697+
 698+
 699+ vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">' + vTmpDate.getHours() + '</div></td>';
 700+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 701+ vTmpDate.setHours(vTmpDate.getHours() + 1);
 702+ }
 703+
 704+ else if(vFormat == 'day' )
 705+ {
 706+ if( JSGantt.formatDateStr(vCurrDate,'mm/dd/yyyy') == JSGantt.formatDateStr(vTmpDate,'mm/dd/yyyy')) {
 707+ vWeekdayColor = "ccccff";
 708+ vWeekendColor = "9999ff";
 709+ vWeekdayGColor = "bbbbff";
 710+ vWeekendGColor = "8888ff";
 711+ } else {
 712+ vWeekdayColor = "ffffff";
 713+ vWeekendColor = "cfcfcf";
 714+ vWeekdayGColor = "f3f3f3";
 715+ vWeekendGColor = "c3c3c3";
 716+ }
 717+
 718+ if(vTmpDate.getDay() % 6 == 0) {
 719+ vDateRowStr += '<td class="gheadwkend" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#' + vWeekendColor + ' align=center><div style="width: '+vColWidth+'px">' + vTmpDate.getDate() + '</div></td>';
 720+ vItemRowStr += '<td class="gheadwkend" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;" bgcolor=#' + vWeekendColor + ' align=center><div style="width: '+vColWidth+'px">&nbsp</div></td>';
 721+ }
 722+ else {
 723+ vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">' + vTmpDate.getDate() + '</div></td>';
 724+ if( JSGantt.formatDateStr(vCurrDate,'mm/dd/yyyy') == JSGantt.formatDateStr(vTmpDate,'mm/dd/yyyy'))
 725+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 726+ else
 727+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; cursor: default;" align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 728+ }
 729+
 730+ vTmpDate.setDate(vTmpDate.getDate() + 1);
 731+
 732+ }
 733+
 734+ else if(vFormat == 'week')
 735+ {
 736+
 737+ vNxtDate.setDate(vNxtDate.getDate() + 7);
 738+
 739+ if( vCurrDate >= vTmpDate && vCurrDate < vNxtDate )
 740+ vWeekdayColor = "ccccff";
 741+ else
 742+ vWeekdayColor = "ffffff";
 743+
 744+ if(vNxtDate <= vMaxDate) {
 745+ vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center width:'+vColWidth+'px><div style="width: '+vColWidth+'px">' + (vTmpDate.getMonth()+1) + '/' + vTmpDate.getDate() + '</div></td>';
 746+ if( vCurrDate >= vTmpDate && vCurrDate < vNxtDate )
 747+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 748+ else
 749+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 750+
 751+ } else {
 752+ vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid; bgcolor=#' + vWeekdayColor + ' BORDER-RIGHT: #efefef 1px solid;" align=center width:'+vColWidth+'px><div style="width: '+vColWidth+'px">' + (vTmpDate.getMonth()+1) + '/' + vTmpDate.getDate() + '</div></td>';
 753+ if( vCurrDate >= vTmpDate && vCurrDate < vNxtDate )
 754+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 755+ else
 756+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 757+
 758+ }
 759+
 760+ vTmpDate.setDate(vTmpDate.getDate() + 7);
 761+
 762+ }
 763+
 764+ else if(vFormat == 'month')
 765+ {
 766+
 767+ vNxtDate.setFullYear(vTmpDate.getFullYear(), vTmpDate.getMonth(), vMonthDaysArr[vTmpDate.getMonth()]);
 768+ if( vCurrDate >= vTmpDate && vCurrDate < vNxtDate )
 769+ vWeekdayColor = "ccccff";
 770+ else
 771+ vWeekdayColor = "ffffff";
 772+
 773+ if(vNxtDate <= vMaxDate) {
 774+ vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center width:'+vColWidth+'px><div style="width: '+vColWidth+'px">' + vMonthArr[vTmpDate.getMonth()].substr(0,3) + '</div></td>';
 775+ if( vCurrDate >= vTmpDate && vCurrDate < vNxtDate )
 776+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 777+ else
 778+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 779+ } else {
 780+ vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center width:'+vColWidth+'px><div style="width: '+vColWidth+'px">' + vMonthArr[vTmpDate.getMonth()].substr(0,3) + '</div></td>';
 781+ if( vCurrDate >= vTmpDate && vCurrDate < vNxtDate )
 782+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 783+ else
 784+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 785+ }
 786+
 787+ vTmpDate.setDate(vTmpDate.getDate() + 1);
 788+
 789+ while(vTmpDate.getDate() > 1)
 790+ {
 791+ vTmpDate.setDate(vTmpDate.getDate() + 1);
 792+ }
 793+
 794+ }
 795+
 796+ else if(vFormat == 'quarter')
 797+ {
 798+
 799+ vNxtDate.setDate(vNxtDate.getDate() + 122);
 800+ if( vTmpDate.getMonth()==0 || vTmpDate.getMonth()==1 || vTmpDate.getMonth()==2 )
 801+ vNxtDate.setFullYear(vTmpDate.getFullYear(), 2, 31);
 802+ else if( vTmpDate.getMonth()==3 || vTmpDate.getMonth()==4 || vTmpDate.getMonth()==5 )
 803+ vNxtDate.setFullYear(vTmpDate.getFullYear(), 5, 30);
 804+ else if( vTmpDate.getMonth()==6 || vTmpDate.getMonth()==7 || vTmpDate.getMonth()==8 )
 805+ vNxtDate.setFullYear(vTmpDate.getFullYear(), 8, 30);
 806+ else if( vTmpDate.getMonth()==9 || vTmpDate.getMonth()==10 || vTmpDate.getMonth()==11 )
 807+ vNxtDate.setFullYear(vTmpDate.getFullYear(), 11, 31);
 808+
 809+ if( vCurrDate >= vTmpDate && vCurrDate < vNxtDate )
 810+ vWeekdayColor = "ccccff";
 811+ else
 812+ vWeekdayColor = "ffffff";
 813+
 814+ if(vNxtDate <= vMaxDate) {
 815+ vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center width:'+vColWidth+'px><div style="width: '+vColWidth+'px">Qtr. ' + vQuarterArr[vTmpDate.getMonth()] + '</div></td>';
 816+ if( vCurrDate >= vTmpDate && vCurrDate < vNxtDate )
 817+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 818+ else
 819+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid;" align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 820+ } else {
 821+ vDateRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; HEIGHT: 19px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center width:'+vColWidth+'px><div style="width: '+vColWidth+'px">Qtr. ' + vQuarterArr[vTmpDate.getMonth()] + '</div></td>';
 822+ if( vCurrDate >= vTmpDate && vCurrDate < vNxtDate )
 823+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" bgcolor=#' + vWeekdayColor + ' align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 824+ else
 825+ vItemRowStr += '<td class="ghead" style="BORDER-TOP: #efefef 1px solid; FONT-SIZE: 12px; BORDER-LEFT: #efefef 1px solid; BORDER-RIGHT: #efefef 1px solid;" align=center><div style="width: '+vColWidth+'px">&nbsp&nbsp</div></td>';
 826+ }
 827+
 828+ vTmpDate.setDate(vTmpDate.getDate() + 81);
 829+
 830+ while(vTmpDate.getDate() > 1)
 831+ {
 832+ vTmpDate.setDate(vTmpDate.getDate() + 1);
 833+ }
 834+
 835+ }
 836+ }
 837+
 838+ vRightTable += vDateRowStr + '</TR>';
 839+ vRightTable += '</TBODY></TABLE>';
 840+
 841+ // Draw each row
 842+
 843+ for(i = 0; i < vTaskList.length; i++)
 844+
 845+ {
 846+
 847+ vTmpDate.setFullYear(vMinDate.getFullYear(), vMinDate.getMonth(), vMinDate.getDate());
 848+ vTaskStart = vTaskList[i].getStart();
 849+ vTaskEnd = vTaskList[i].getEnd();
 850+
 851+ vNumCols = 0;
 852+ vID = vTaskList[i].getID();
 853+
 854+ // vNumUnits = Math.ceil((vTaskList[i].getEnd() - vTaskList[i].getStart()) / (24 * 60 * 60 * 1000)) + 1;
 855+ vNumUnits = (vTaskList[i].getEnd() - vTaskList[i].getStart()) / (24 * 60 * 60 * 1000) + 1;
 856+ if (vFormat=='hour')
 857+ {
 858+ vNumUnits = (vTaskList[i].getEnd() - vTaskList[i].getStart()) / ( 60 * 1000) + 1;
 859+ }
 860+ else if (vFormat=='minute')
 861+ {
 862+ vNumUnits = (vTaskList[i].getEnd() - vTaskList[i].getStart()) / ( 60 * 1000) + 1;
 863+ }
 864+
 865+ if(vTaskList[i].getVisible() == 0)
 866+ vRightTable += '<DIV id=childgrid_' + vID + ' style="position:relative; display:none;">';
 867+ else
 868+ vRightTable += '<DIV id=childgrid_' + vID + ' style="position:relative">';
 869+
 870+ if( vTaskList[i].getMile()) {
 871+
 872+ vRightTable += '<DIV><TABLE style="position:relative; top:0px; width: ' + vChartWidth + 'px;" cellSpacing=0 cellPadding=0 border=0>' +
 873+ '<TR id=childrow_' + vID + ' class=yesdisplay style="HEIGHT: 20px" onMouseover=g.mouseOver(this,' + vID + ',"right","mile") onMouseout=g.mouseOut(this,' + vID + ',"right","mile")>' + vItemRowStr + '</TR></TABLE></DIV>';
 874+
 875+ // Build date string for Title
 876+ vDateRowStr = JSGantt.formatDateStr(vTaskStart,vDateDisplayFormat);
 877+
 878+ vTaskLeft = (Date.parse(vTaskList[i].getStart()) - Date.parse(vMinDate)) / (24 * 60 * 60 * 1000);
 879+ vTaskRight = 1
 880+
 881+ vRightTable +=
 882+ '<div id=bardiv_' + vID + ' style="position:absolute; top:0px; left:' + Math.ceil((vTaskLeft * (vDayWidth) + 1)) + 'px; height: 18px; width:160px; overflow:hidden;">' +
 883+ ' <div id=taskbar_' + vID + ' title="' + vTaskList[i].getName() + ': ' + vDateRowStr + '" style="height: 16px; width:12px; overflow:hidden; cursor: pointer;" onclick=JSGantt.taskLink("' + vTaskList[i].getLink() + '",300,200);>';
 884+
 885+ if(vTaskList[i].getCompVal() < 100)
 886+ vRightTable += '&loz;</div>' ;
 887+ else
 888+ vRightTable += '&diams;</div>' ;
 889+
 890+ if( g.getCaptionType() ) {
 891+ vCaptionStr = '';
 892+ switch( g.getCaptionType() ) {
 893+ case 'Caption': vCaptionStr = vTaskList[i].getCaption(); break;
 894+ case 'Resource': vCaptionStr = vTaskList[i].getResource(); break;
 895+ case 'Duration': vCaptionStr = vTaskList[i].getDuration(vFormat); break;
 896+ case 'Complete': vCaptionStr = vTaskList[i].getCompStr(); break;
 897+ }
 898+ //vRightTable += '<div style="FONT-SIZE:12px; position:absolute; left: 6px; top:1px;">' + vCaptionStr + '</div>';
 899+ vRightTable += '<div style="FONT-SIZE:12px; position:absolute; top:2px; width:120px; left:12px">' + vCaptionStr + '</div>';
 900+ }
 901+
 902+ vRightTable += '</div>';
 903+
 904+
 905+ } else {
 906+
 907+ // Build date string for Title
 908+ vDateRowStr = JSGantt.formatDateStr(vTaskStart,vDateDisplayFormat) + ' - ' + JSGantt.formatDateStr(vTaskEnd,vDateDisplayFormat)
 909+
 910+ if (vFormat=='minute')
 911+ {
 912+ vTaskRight = (Date.parse(vTaskList[i].getEnd()) - Date.parse(vTaskList[i].getStart())) / ( 60 * 1000) + 1/vColUnit;
 913+ vTaskLeft = Math.ceil((Date.parse(vTaskList[i].getStart()) - Date.parse(vMinDate)) / ( 60 * 1000));
 914+ }
 915+ else if (vFormat=='hour')
 916+ {
 917+ vTaskRight = (Date.parse(vTaskList[i].getEnd()) - Date.parse(vTaskList[i].getStart())) / ( 60 * 60 * 1000) + 1/vColUnit;
 918+ vTaskLeft = (Date.parse(vTaskList[i].getStart()) - Date.parse(vMinDate)) / ( 60 * 60 * 1000);
 919+ }
 920+ else
 921+ {
 922+ vTaskRight = (Date.parse(vTaskList[i].getEnd()) - Date.parse(vTaskList[i].getStart())) / (24 * 60 * 60 * 1000) + 1/vColUnit;
 923+ vTaskLeft = Math.ceil((Date.parse(vTaskList[i].getStart()) - Date.parse(vMinDate)) / (24 * 60 * 60 * 1000));
 924+ if (vFormat='day')
 925+ {
 926+ var tTime=new Date();
 927+ tTime.setTime(Date.parse(vTaskList[i].getStart()));
 928+ if (tTime.getMinutes() > 29)
 929+ vTaskLeft+=.5
 930+ }
 931+ }
 932+
 933+ // Draw Group Bar which has outer div with inner group div and several small divs to left and right to create angled-end indicators
 934+ if( vTaskList[i].getGroup()) {
 935+ vRightTable += '<DIV><TABLE style="position:relative; top:0px; width: ' + vChartWidth + 'px;" cellSpacing=0 cellPadding=0 border=0>' +
 936+ '<TR id=childrow_' + vID + ' class=yesdisplay style="HEIGHT: 20px" bgColor=#f3f3f3 onMouseover=g.mouseOver(this,' + vID + ',"right","group") onMouseout=g.mouseOut(this,' + vID + ',"right","group")>' + vItemRowStr + '</TR></TABLE></DIV>';
 937+ vRightTable +=
 938+ '<div id=bardiv_' + vID + ' style="position:absolute; top:5px; left:' + Math.ceil(vTaskLeft * (vDayWidth) + 1) + 'px; height: 7px; width:' + Math.ceil((vTaskRight) * (vDayWidth) - 1) + 'px">' +
 939+ '<div id=taskbar_' + vID + ' title="' + vTaskList[i].getName() + ': ' + vDateRowStr + '" class=gtask style="background-color:#000000; height: 7px; width:' + Math.ceil((vTaskRight) * (vDayWidth) -1) + 'px; cursor: pointer;opacity:0.9;">' +
 940+ '<div style="Z-INDEX: -4; float:left; background-color:#666666; height:3px; overflow: hidden; margin-top:1px; ' +
 941+ 'margin-left:1px; margin-right:1px; filter: alpha(opacity=80); opacity:0.8; width:' + vTaskList[i].getCompStr() + '; ' +
 942+ 'cursor: pointer;" onclick=JSGantt.taskLink("' + vTaskList[i].getLink() + '",300,200);>' +
 943+ '</div>' +
 944+ '</div>' +
 945+ '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:4px; overflow: hidden; width:1px;"></div>' +
 946+ '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:4px; overflow: hidden; width:1px;"></div>' +
 947+ '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:3px; overflow: hidden; width:1px;"></div>' +
 948+ '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:3px; overflow: hidden; width:1px;"></div>' +
 949+ '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:2px; overflow: hidden; width:1px;"></div>' +
 950+ '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:2px; overflow: hidden; width:1px;"></div>' +
 951+ '<div style="Z-INDEX: -4; float:left; background-color:#000000; height:1px; overflow: hidden; width:1px;"></div>' +
 952+ '<div style="Z-INDEX: -4; float:right; background-color:#000000; height:1px; overflow: hidden; width:1px;"></div>' ;
 953+
 954+ if( g.getCaptionType() ) {
 955+ vCaptionStr = '';
 956+ switch( g.getCaptionType() ) {
 957+ case 'Caption': vCaptionStr = vTaskList[i].getCaption(); break;
 958+ case 'Resource': vCaptionStr = vTaskList[i].getResource(); break;
 959+ case 'Duration': vCaptionStr = vTaskList[i].getDuration(vFormat); break;
 960+ case 'Complete': vCaptionStr = vTaskList[i].getCompStr(); break;
 961+ }
 962+ //vRightTable += '<div style="FONT-SIZE:12px; position:absolute; left: 6px; top:1px;">' + vCaptionStr + '</div>';
 963+ vRightTable += '<div style="FONT-SIZE:12px; position:absolute; top:-3px; width:120px; left:' + (Math.ceil((vTaskRight) * (vDayWidth) - 1) + 6) + 'px">' + vCaptionStr + '</div>';
 964+ }
 965+
 966+ vRightTable += '</div>' ;
 967+
 968+ } else {
 969+
 970+ vDivStr = '<DIV><TABLE style="position:relative; top:0px; width: ' + vChartWidth + 'px;" cellSpacing=0 cellPadding=0 border=0>' +
 971+ '<TR id=childrow_' + vID + ' class=yesdisplay style="HEIGHT: 20px" bgColor=#ffffff onMouseover=g.mouseOver(this,' + vID + ',"right","row") onMouseout=g.mouseOut(this,' + vID + ',"right","row")>' + vItemRowStr + '</TR></TABLE></DIV>';
 972+ vRightTable += vDivStr;
 973+
 974+ // Draw Task Bar which has outer DIV with enclosed colored bar div, and opaque completion div
 975+ vRightTable +=
 976+ '<div id=bardiv_' + vID + ' style="position:absolute; top:4px; left:' + Math.ceil(vTaskLeft * (vDayWidth) + 1) + 'px; height:18px; width:' + Math.ceil((vTaskRight) * (vDayWidth) - 1) + 'px">' +
 977+ '<div id=taskbar_' + vID + ' title="' + vTaskList[i].getName() + ': ' + vDateRowStr + '" class=gtask style="background-color:#' + vTaskList[i].getColor() +'; height: 13px; width:' + Math.ceil((vTaskRight) * (vDayWidth) - 1) + 'px; cursor: pointer;opacity:0.9;" ' +
 978+ 'onclick=JSGantt.taskLink("' + vTaskList[i].getLink() + '",300,200); >' +
 979+ '<div class=gcomplete style="Z-INDEX: -4; float:left; background-color:black; height:5px; overflow: auto; margin-top:4px; filter: alpha(opacity=40); opacity:0.4; width:' + vTaskList[i].getCompStr() + '; overflow:hidden">' +
 980+ '</div>' +
 981+ '</div>';
 982+
 983+ if( g.getCaptionType() ) {
 984+ vCaptionStr = '';
 985+ switch( g.getCaptionType() ) {
 986+ case 'Caption': vCaptionStr = vTaskList[i].getCaption(); break;
 987+ case 'Resource': vCaptionStr = vTaskList[i].getResource(); break;
 988+ case 'Duration': vCaptionStr = vTaskList[i].getDuration(vFormat); break;
 989+ case 'Complete': vCaptionStr = vTaskList[i].getCompStr(); break;
 990+ }
 991+ //vRightTable += '<div style="FONT-SIZE:12px; position:absolute; left: 6px; top:-3px;">' + vCaptionStr + '</div>';
 992+ vRightTable += '<div style="FONT-SIZE:12px; position:absolute; top:-3px; width:120px; left:' + (Math.ceil((vTaskRight) * (vDayWidth) - 1) + 6) + 'px">' + vCaptionStr + '</div>';
 993+ }
 994+ vRightTable += '</div>' ;
 995+
 996+
 997+
 998+ }
 999+ }
 1000+
 1001+ vRightTable += '</DIV>';
 1002+
 1003+ }
 1004+
 1005+ vMainTable += vRightTable + '</DIV></TD></TR></TBODY></TABLE></BODY></HTML>';
 1006+
 1007+ vDiv.innerHTML = vMainTable;
 1008+
 1009+ }
 1010+
 1011+ } //this.draw
 1012+
 1013+ this.mouseOver = function( pObj, pID, pPos, pType ) {
 1014+ if( pPos == 'right' ) vID = 'child_' + pID;
 1015+ else vID = 'childrow_' + pID;
 1016+
 1017+ pObj.bgColor = "#ffffaa";
 1018+ vRowObj = JSGantt.findObj(vID);
 1019+ if (vRowObj) vRowObj.bgColor = "#ffffaa";
 1020+ }
 1021+
 1022+ this.mouseOut = function( pObj, pID, pPos, pType ) {
 1023+ if( pPos == 'right' ) vID = 'child_' + pID;
 1024+ else vID = 'childrow_' + pID;
 1025+
 1026+ pObj.bgColor = "#ffffff";
 1027+ vRowObj = JSGantt.findObj(vID);
 1028+ if (vRowObj) {
 1029+ if( pType == "group") {
 1030+ pObj.bgColor = "#f3f3f3";
 1031+ vRowObj.bgColor = "#f3f3f3";
 1032+ } else {
 1033+ pObj.bgColor = "#ffffff";
 1034+ vRowObj.bgColor = "#ffffff";
 1035+ }
 1036+ }
 1037+ }
 1038+
 1039+} //GanttChart
 1040+
 1041+// Recursively process task tree ... set min, max dates of parent tasks and identfy task level.
 1042+JSGantt.processRows = function(pList, pID, pRow, pLevel, pOpen)
 1043+{
 1044+
 1045+ var vMinDate = new Date();
 1046+ var vMaxDate = new Date();
 1047+ var vMinSet = 0;
 1048+ var vMaxSet = 0;
 1049+ var vList = pList;
 1050+ var vLevel = pLevel;
 1051+ var i = 0;
 1052+ var vNumKid = 0;
 1053+ var vCompSum = 0;
 1054+ var vVisible = pOpen;
 1055+
 1056+ for(i = 0; i < pList.length; i++)
 1057+ {
 1058+ if(pList[i].getParent() == pID) {
 1059+ vVisible = pOpen;
 1060+ pList[i].setVisible(vVisible);
 1061+ if(vVisible==1 && pList[i].getOpen() == 0)
 1062+ vVisible = 0;
 1063+
 1064+ pList[i].setLevel(vLevel);
 1065+ vNumKid++;
 1066+
 1067+ if(pList[i].getGroup() == 1) {
 1068+ JSGantt.processRows(vList, pList[i].getID(), i, vLevel+1, vVisible);
 1069+ }
 1070+
 1071+ if( vMinSet==0 || pList[i].getStart() < vMinDate) {
 1072+ vMinDate = pList[i].getStart();
 1073+ vMinSet = 1;
 1074+ }
 1075+
 1076+ if( vMaxSet==0 || pList[i].getEnd() > vMaxDate) {
 1077+ vMaxDate = pList[i].getEnd();
 1078+ vMaxSet = 1;
 1079+ }
 1080+
 1081+ vCompSum += pList[i].getCompVal();
 1082+
 1083+ }
 1084+ }
 1085+
 1086+ if(pRow >= 0) {
 1087+ pList[pRow].setStart(vMinDate);
 1088+ pList[pRow].setEnd(vMaxDate);
 1089+ pList[pRow].setNumKid(vNumKid);
 1090+ pList[pRow].setCompVal(Math.ceil(vCompSum/vNumKid));
 1091+ }
 1092+
 1093+}
 1094+
 1095+
 1096+// Used to determine the minimum date of all tasks and set lower bound based on format
 1097+JSGantt.getMinDate = function getMinDate(pList, pFormat)
 1098+ {
 1099+
 1100+ var vDate = new Date();
 1101+
 1102+ vDate.setFullYear(pList[0].getStart().getFullYear(), pList[0].getStart().getMonth(), pList[0].getStart().getDate());
 1103+
 1104+ // Parse all Task End dates to find min
 1105+ for(i = 0; i < pList.length; i++)
 1106+ {
 1107+ if(Date.parse(pList[i].getStart()) < Date.parse(vDate))
 1108+ vDate.setFullYear(pList[i].getStart().getFullYear(), pList[i].getStart().getMonth(), pList[i].getStart().getDate());
 1109+ }
 1110+
 1111+ if ( pFormat== 'minute')
 1112+ {
 1113+ vDate.setHours(0);
 1114+ vDate.setMinutes(0);
 1115+ }
 1116+ else if (pFormat == 'hour' )
 1117+ {
 1118+ vDate.setHours(0);
 1119+ vDate.setMinutes(0);
 1120+ }
 1121+ // Adjust min date to specific format boundaries (first of week or first of month)
 1122+ else if (pFormat=='day')
 1123+ {
 1124+ vDate.setDate(vDate.getDate() - 1);
 1125+ while(vDate.getDay() % 7 > 0)
 1126+ {
 1127+ vDate.setDate(vDate.getDate() - 1);
 1128+ }
 1129+
 1130+ }
 1131+
 1132+ else if (pFormat=='week')
 1133+ {
 1134+ vDate.setDate(vDate.getDate() - 7);
 1135+ while(vDate.getDay() % 7 > 0)
 1136+ {
 1137+ vDate.setDate(vDate.getDate() - 1);
 1138+ }
 1139+
 1140+ }
 1141+
 1142+ else if (pFormat=='month')
 1143+ {
 1144+ while(vDate.getDate() > 1)
 1145+ {
 1146+ vDate.setDate(vDate.getDate() - 1);
 1147+ }
 1148+ }
 1149+
 1150+ else if (pFormat=='quarter')
 1151+ {
 1152+ if( vDate.getMonth()==0 || vDate.getMonth()==1 || vDate.getMonth()==2 )
 1153+ vDate.setFullYear(vDate.getFullYear(), 0, 1);
 1154+ else if( vDate.getMonth()==3 || vDate.getMonth()==4 || vDate.getMonth()==5 )
 1155+ vDate.setFullYear(vDate.getFullYear(), 3, 1);
 1156+ else if( vDate.getMonth()==6 || vDate.getMonth()==7 || vDate.getMonth()==8 )
 1157+ vDate.setFullYear(vDate.getFullYear(), 6, 1);
 1158+ else if( vDate.getMonth()==9 || vDate.getMonth()==10 || vDate.getMonth()==11 )
 1159+ vDate.setFullYear(vDate.getFullYear(), 9, 1);
 1160+
 1161+ }
 1162+
 1163+ return(vDate);
 1164+
 1165+ }
 1166+
 1167+
 1168+
 1169+
 1170+
 1171+
 1172+
 1173+ // Used to determine the minimum date of all tasks and set lower bound based on format
 1174+
 1175+JSGantt.getMaxDate = function (pList, pFormat)
 1176+{
 1177+ var vDate = new Date();
 1178+
 1179+ vDate.setFullYear(pList[0].getEnd().getFullYear(), pList[0].getEnd().getMonth(), pList[0].getEnd().getDate());
 1180+
 1181+
 1182+ // Parse all Task End dates to find max
 1183+ for(i = 0; i < pList.length; i++)
 1184+ {
 1185+ if(Date.parse(pList[i].getEnd()) > Date.parse(vDate))
 1186+ {
 1187+ //vDate.setFullYear(pList[0].getEnd().getFullYear(), pList[0].getEnd().getMonth(), pList[0].getEnd().getDate());
 1188+ vDate.setTime(Date.parse(pList[i].getEnd()));
 1189+ }
 1190+ }
 1191+
 1192+ if (pFormat == 'minute')
 1193+ {
 1194+ vDate.setHours(vDate.getHours() + 1);
 1195+ vDate.setMinutes(59);
 1196+ }
 1197+
 1198+ if (pFormat == 'hour')
 1199+ {
 1200+ vDate.setHours(vDate.getHours() + 2);
 1201+ }
 1202+
 1203+ // Adjust max date to specific format boundaries (end of week or end of month)
 1204+ if (pFormat=='day')
 1205+ {
 1206+ vDate.setDate(vDate.getDate() + 1);
 1207+
 1208+ while(vDate.getDay() % 6 > 0)
 1209+ {
 1210+ vDate.setDate(vDate.getDate() + 1);
 1211+ }
 1212+
 1213+ }
 1214+
 1215+ if (pFormat=='week')
 1216+ {
 1217+ //For weeks, what is the last logical boundary?
 1218+ vDate.setDate(vDate.getDate() + 11);
 1219+
 1220+ while(vDate.getDay() % 6 > 0)
 1221+ {
 1222+ vDate.setDate(vDate.getDate() + 1);
 1223+ }
 1224+
 1225+ }
 1226+
 1227+ // Set to last day of current Month
 1228+ if (pFormat=='month')
 1229+ {
 1230+ while(vDate.getDay() > 1)
 1231+ {
 1232+ vDate.setDate(vDate.getDate() + 1);
 1233+ }
 1234+
 1235+ vDate.setDate(vDate.getDate() - 1);
 1236+ }
 1237+
 1238+ // Set to last day of current Quarter
 1239+ if (pFormat=='quarter')
 1240+ {
 1241+ if( vDate.getMonth()==0 || vDate.getMonth()==1 || vDate.getMonth()==2 )
 1242+ vDate.setFullYear(vDate.getFullYear(), 2, 31);
 1243+ else if( vDate.getMonth()==3 || vDate.getMonth()==4 || vDate.getMonth()==5 )
 1244+ vDate.setFullYear(vDate.getFullYear(), 5, 30);
 1245+ else if( vDate.getMonth()==6 || vDate.getMonth()==7 || vDate.getMonth()==8 )
 1246+ vDate.setFullYear(vDate.getFullYear(), 8, 30);
 1247+ else if( vDate.getMonth()==9 || vDate.getMonth()==10 || vDate.getMonth()==11 )
 1248+ vDate.setFullYear(vDate.getFullYear(), 11, 31);
 1249+
 1250+ }
 1251+
 1252+ return(vDate);
 1253+
 1254+ }
 1255+
 1256+
 1257+
 1258+
 1259+
 1260+
 1261+
 1262+ // This function finds the document id of the specified object
 1263+
 1264+JSGantt.findObj = function (theObj, theDoc)
 1265+
 1266+ {
 1267+
 1268+ var p, i, foundObj;
 1269+
 1270+ if(!theDoc) theDoc = document;
 1271+
 1272+ if( (p = theObj.indexOf("?")) > 0 && parent.frames.length){
 1273+
 1274+ theDoc = parent.frames[theObj.substring(p+1)].document;
 1275+
 1276+ theObj = theObj.substring(0,p);
 1277+
 1278+ }
 1279+
 1280+ if(!(foundObj = theDoc[theObj]) && theDoc.all)
 1281+
 1282+ foundObj = theDoc.all[theObj];
 1283+
 1284+
 1285+
 1286+ for (i=0; !foundObj && i < theDoc.forms.length; i++)
 1287+
 1288+ foundObj = theDoc.forms[i][theObj];
 1289+
 1290+
 1291+
 1292+ for(i=0; !foundObj && theDoc.layers && i < theDoc.layers.length; i++)
 1293+
 1294+ foundObj = JSGantt.findObj(theObj,theDoc.layers[i].document);
 1295+
 1296+
 1297+
 1298+ if(!foundObj && document.getElementById)
 1299+
 1300+ foundObj = document.getElementById(theObj);
 1301+
 1302+
 1303+
 1304+ return foundObj;
 1305+
 1306+ }
 1307+
 1308+
 1309+
 1310+
 1311+
 1312+JSGantt.changeFormat = function(pFormat,ganttObj) {
 1313+
 1314+
 1315+
 1316+ if(ganttObj)
 1317+
 1318+ {
 1319+
 1320+ ganttObj.setFormat(pFormat);
 1321+
 1322+ ganttObj.DrawDependencies();
 1323+
 1324+ }
 1325+
 1326+ else
 1327+
 1328+ alert('Chart undefined');
 1329+
 1330+
 1331+
 1332+ }
 1333+
 1334+
 1335+
 1336+
 1337+
 1338+ // Function to open/close and hide/show children of specified task
 1339+
 1340+JSGantt.folder= function (pID,ganttObj) {
 1341+
 1342+ var vList = ganttObj.getList();
 1343+
 1344+ for(i = 0; i < vList.length; i++)
 1345+ {
 1346+ if(vList[i].getID() == pID) {
 1347+
 1348+ if( vList[i].getOpen() == 1 ) {
 1349+ vList[i].setOpen(0);
 1350+ JSGantt.hide(pID,ganttObj);
 1351+
 1352+ if (JSGantt.isIE())
 1353+ JSGantt.findObj('group_'+pID).innerText = '+';
 1354+ else
 1355+ JSGantt.findObj('group_'+pID).textContent = '+';
 1356+
 1357+ } else {
 1358+
 1359+ vList[i].setOpen(1);
 1360+
 1361+ JSGantt.show(pID, 1, ganttObj);
 1362+
 1363+ if (JSGantt.isIE())
 1364+ JSGantt.findObj('group_'+pID).innerText = '�';
 1365+ else
 1366+ JSGantt.findObj('group_'+pID).textContent = '�';
 1367+
 1368+ }
 1369+
 1370+ }
 1371+ }
 1372+}
 1373+
 1374+JSGantt.hide= function (pID,ganttObj) {
 1375+ var vList = ganttObj.getList();
 1376+ var vID = 0;
 1377+
 1378+ for(var i = 0; i < vList.length; i++)
 1379+ {
 1380+ if(vList[i].getParent() == pID) {
 1381+ vID = vList[i].getID();
 1382+ JSGantt.findObj('child_' + vID).style.display = "none";
 1383+ JSGantt.findObj('childgrid_' + vID).style.display = "none";
 1384+ vList[i].setVisible(0);
 1385+ if(vList[i].getGroup() == 1)
 1386+ JSGantt.hide(vID,ganttObj);
 1387+ }
 1388+
 1389+ }
 1390+}
 1391+
 1392+// Function to show children of specified task
 1393+JSGantt.show = function (pID, pTop, ganttObj) {
 1394+ var vList = ganttObj.getList();
 1395+ var vID = 0;
 1396+
 1397+ for(var i = 0; i < vList.length; i++)
 1398+ {
 1399+ if(vList[i].getParent() == pID) {
 1400+ vID = vList[i].getID();
 1401+ if(pTop == 1) {
 1402+ if (JSGantt.isIE()) { // IE;
 1403+
 1404+ if( JSGantt.findObj('group_'+pID).innerText == '+') {
 1405+ JSGantt.findObj('child_'+vID).style.display = "";
 1406+ JSGantt.findObj('childgrid_'+vID).style.display = "";
 1407+ vList[i].setVisible(1);
 1408+ }
 1409+
 1410+ } else {
 1411+
 1412+ if( JSGantt.findObj('group_'+pID).textContent == '+') {
 1413+ JSGantt.findObj('child_'+vID).style.display = "";
 1414+ JSGantt.findObj('childgrid_'+vID).style.display = "";
 1415+ vList[i].setVisible(1);
 1416+ }
 1417+
 1418+ }
 1419+
 1420+ } else {
 1421+
 1422+ if (JSGantt.isIE()) { // IE;
 1423+ if( JSGantt.findObj('group_'+pID).innerText == '�') {
 1424+ JSGantt.findObj('child_'+vID).style.display = "";
 1425+ JSGantt.findObj('childgrid_'+vID).style.display = "";
 1426+ vList[i].setVisible(1);
 1427+ }
 1428+
 1429+ } else {
 1430+
 1431+ if( JSGantt.findObj('group_'+pID).textContent == '�') {
 1432+ JSGantt.findObj('child_'+vID).style.display = "";
 1433+ JSGantt.findObj('childgrid_'+vID).style.display = "";
 1434+ vList[i].setVisible(1);
 1435+ }
 1436+ }
 1437+ }
 1438+
 1439+ if(vList[i].getGroup() == 1)
 1440+ JSGantt.show(vID, 0,ganttObj);
 1441+
 1442+ }
 1443+ }
 1444+}
 1445+
 1446+
 1447+
 1448+
 1449+
 1450+ // function to open window to display task link
 1451+
 1452+JSGantt.taskLink = function(pRef,pWidth,pHeight)
 1453+
 1454+ {
 1455+
 1456+ if(pWidth) vWidth =pWidth; else vWidth =400;
 1457+ if(pHeight) vHeight=pHeight; else vHeight=400;
 1458+
 1459+ var OpenWindow=window.open(pRef, "newwin", "height="+vHeight+",width="+vWidth);
 1460+
 1461+ }
 1462+
 1463+JSGantt.parseDateStr = function(pDateStr,pFormatStr) {
 1464+ var vDate =new Date();
 1465+ vDate.setTime( Date.parse(pDateStr));
 1466+
 1467+ switch(pFormatStr)
 1468+ {
 1469+ case 'mm/dd/yyyy':
 1470+ var vDateParts = pDateStr.split('/');
 1471+ vDate.setFullYear(parseInt(vDateParts[2], 10), parseInt(vDateParts[0], 10) - 1, parseInt(vDateParts[1], 10));
 1472+ break;
 1473+ case 'dd/mm/yyyy':
 1474+ var vDateParts = pDateStr.split('/');
 1475+ vDate.setFullYear(parseInt(vDateParts[2], 10), parseInt(vDateParts[1], 10) - 1, parseInt(vDateParts[0], 10));
 1476+ break;
 1477+ case 'yyyy-mm-dd':
 1478+ var vDateParts = pDateStr.split('-');
 1479+ vDate.setFullYear(parseInt(vDateParts[0], 10), parseInt(vDateParts[1], 10) - 1, parseInt(vDateParts[1], 10));
 1480+ break;
 1481+ }
 1482+
 1483+ return(vDate);
 1484+
 1485+}
 1486+
 1487+JSGantt.formatDateStr = function(pDate,pFormatStr) {
 1488+ vYear4Str = pDate.getFullYear() + '';
 1489+ vYear2Str = vYear4Str.substring(2,4);
 1490+ vMonthStr = (pDate.getMonth()+1) + '';
 1491+ vDayStr = pDate.getDate() + '';
 1492+
 1493+ var vDateStr = "";
 1494+
 1495+ switch(pFormatStr) {
 1496+ case 'mm/dd/yyyy':
 1497+ return( vMonthStr + '/' + vDayStr + '/' + vYear4Str );
 1498+ case 'dd/mm/yyyy':
 1499+ return( vDayStr + '/' + vMonthStr + '/' + vYear4Str );
 1500+ case 'yyyy-mm-dd':
 1501+ return( vYear4Str + '-' + vMonthStr + '-' + vDayStr );
 1502+ case 'mm/dd/yy':
 1503+ return( vMonthStr + '/' + vDayStr + '/' + vYear2Str );
 1504+ case 'dd/mm/yy':
 1505+ return( vDayStr + '/' + vMonthStr + '/' + vYear2Str );
 1506+ case 'yy-mm-dd':
 1507+ return( vYear2Str + '-' + vMonthStr + '-' + vDayStr );
 1508+ case 'mm/dd':
 1509+ return( vMonthStr + '/' + vDayStr );
 1510+ case 'dd/mm':
 1511+ return( vDayStr + '/' + vMonthStr );
 1512+ }
 1513+
 1514+}
 1515+
 1516+JSGantt.parseXML = function(ThisFile,pGanttVar){
 1517+ var is_chrome = navigator.userAgent.toLowerCase().indexOf('chrome') > -1; // Is this Chrome
 1518+
 1519+ try { //Internet Explorer
 1520+ xmlDoc=new ActiveXObject("Microsoft.XMLDOM");
 1521+ }
 1522+ catch(e) {
 1523+ try { //Firefox, Mozilla, Opera, Chrome etc.
 1524+ if (is_chrome==false) { xmlDoc=document.implementation.createDocument("","",null); }
 1525+ }
 1526+ catch(e) {
 1527+ alert(e.message);
 1528+ return;
 1529+ }
 1530+ }
 1531+
 1532+ if (is_chrome==false) { // can't use xmlDoc.load in chrome at the moment
 1533+ xmlDoc.async=false;
 1534+ xmlDoc.load(ThisFile); // we can use loadxml
 1535+ JSGantt.AddXMLTask(pGanttVar)
 1536+ xmlDoc=null; // a little tidying
 1537+ Task = null;
 1538+ }
 1539+ else {
 1540+ JSGantt.ChromeLoadXML(ThisFile,pGanttVar);
 1541+ ta=null; // a little tidying
 1542+ }
 1543+}
 1544+
 1545+JSGantt.AddXMLTask = function(pGanttVar){
 1546+
 1547+ Task=xmlDoc.getElementsByTagName("task");
 1548+
 1549+ var n = xmlDoc.documentElement.childNodes.length; // the number of tasks. IE gets this right, but mozilla add extra ones (Whitespace)
 1550+
 1551+ for(var i=0;i<n;i++) {
 1552+
 1553+ // optional parameters may not have an entry (Whitespace from mozilla also returns an error )
 1554+ // Task ID must NOT be zero other wise it will be skipped
 1555+ try { pID = Task[i].getElementsByTagName("pID")[0].childNodes[0].nodeValue;
 1556+ } catch (error) {pID =0;}
 1557+ pID *= 1; // make sure that these are numbers rather than strings in order to make jsgantt.js behave as expected.
 1558+
 1559+ if(pID!=0){
 1560+ try { pName = Task[i].getElementsByTagName("pName")[0].childNodes[0].nodeValue;
 1561+ } catch (error) {pName ="No Task Name";} // If there is no corresponding entry in the XML file the set a default.
 1562+
 1563+ try { pColor = Task[i].getElementsByTagName("pColor")[0].childNodes[0].nodeValue;
 1564+ } catch (error) {pColor ="0000ff";}
 1565+
 1566+ try { pParent = Task[i].getElementsByTagName("pParent")[0].childNodes[0].nodeValue;
 1567+ } catch (error) {pParent =0;}
 1568+ pParent *= 1;
 1569+
 1570+ try { pStart = Task[i].getElementsByTagName("pStart")[0].childNodes[0].nodeValue;
 1571+ } catch (error) {pStart ="";}
 1572+
 1573+ try { pEnd = Task[i].getElementsByTagName("pEnd")[0].childNodes[0].nodeValue;
 1574+ } catch (error) { pEnd ="";}
 1575+
 1576+ try { pLink = Task[i].getElementsByTagName("pLink")[0].childNodes[0].nodeValue;
 1577+ } catch (error) { pLink ="";}
 1578+
 1579+ try { pMile = Task[i].getElementsByTagName("pMile")[0].childNodes[0].nodeValue;
 1580+ } catch (error) { pMile=0;}
 1581+ pMile *= 1;
 1582+
 1583+ try { pRes = Task[i].getElementsByTagName("pRes")[0].childNodes[0].nodeValue;
 1584+ } catch (error) { pRes ="";}
 1585+
 1586+ try { pComp = Task[i].getElementsByTagName("pComp")[0].childNodes[0].nodeValue;
 1587+ } catch (error) {pComp =0;}
 1588+ pComp *= 1;
 1589+
 1590+ try { pGroup = Task[i].getElementsByTagName("pGroup")[0].childNodes[0].nodeValue;
 1591+ } catch (error) {pGroup =0;}
 1592+ pGroup *= 1;
 1593+
 1594+ try { pOpen = Task[i].getElementsByTagName("pOpen")[0].childNodes[0].nodeValue;
 1595+ } catch (error) { pOpen =1;}
 1596+ pOpen *= 1;
 1597+
 1598+ try { pDepend = Task[i].getElementsByTagName("pDepend")[0].childNodes[0].nodeValue;
 1599+ } catch (error) { pDepend =0;}
 1600+ //pDepend *= 1;
 1601+ if (pDepend.length==0){pDepend=''} // need this to draw the dependency lines
 1602+
 1603+ try { pCaption = Task[i].getElementsByTagName("pCaption")[0].childNodes[0].nodeValue;
 1604+ } catch (error) { pCaption ="";}
 1605+
 1606+
 1607+ // Finally add the task
 1608+ pGanttVar.AddTaskItem(new JSGantt.TaskItem(pID , pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend,pCaption));
 1609+ }
 1610+ }
 1611+}
 1612+
 1613+JSGantt.ChromeLoadXML = function(ThisFile,pGanttVar){
 1614+// Thanks to vodobas at mindlence,com for the initial pointers here.
 1615+ XMLLoader = new XMLHttpRequest();
 1616+ XMLLoader.onreadystatechange= function(){
 1617+ JSGantt.ChromeXMLParse(pGanttVar);
 1618+ };
 1619+ XMLLoader.open("GET", ThisFile, false);
 1620+ XMLLoader.send(null);
 1621+}
 1622+
 1623+JSGantt.ChromeXMLParse = function (pGanttVar){
 1624+// Manually parse the file as it is loads quicker
 1625+ if (XMLLoader.readyState == 4) {
 1626+ var ta=XMLLoader.responseText.split(/<task>/gi);
 1627+
 1628+ var n = ta.length; // the number of tasks.
 1629+ for(var i=1;i<n;i++) {
 1630+ Task = ta[i].replace(/<[/]p/g, '<p');
 1631+ var te = Task.split(/<pid>/i)
 1632+
 1633+ if(te.length> 2){var pID=te[1];} else {var pID = 0;}
 1634+ pID *= 1;
 1635+
 1636+ var te = Task.split(/<pName>/i)
 1637+ if(te.length> 2){var pName=te[1];} else {var pName = "No Task Name";}
 1638+
 1639+ var te = Task.split(/<pstart>/i)
 1640+ if(te.length> 2){var pStart=te[1];} else {var pStart = "";}
 1641+
 1642+ var te = Task.split(/<pEnd>/i)
 1643+ if(te.length> 2){var pEnd=te[1];} else {var pEnd = "";}
 1644+
 1645+ var te = Task.split(/<pColor>/i)
 1646+ if(te.length> 2){var pColor=te[1];} else {var pColor = '0000ff';}
 1647+
 1648+ var te = Task.split(/<pLink>/i)
 1649+ if(te.length> 2){var pLink=te[1];} else {var pLink = "";}
 1650+
 1651+ var te = Task.split(/<pMile>/i)
 1652+ if(te.length> 2){var pMile=te[1];} else {var pMile = 0;}
 1653+ pMile *= 1;
 1654+
 1655+ var te = Task.split(/<pRes>/i)
 1656+ if(te.length> 2){var pRes=te[1];} else {var pRes = "";}
 1657+
 1658+ var te = Task.split(/<pComp>/i)
 1659+ if(te.length> 2){var pComp=te[1];} else {var pComp = 0;}
 1660+ pComp *= 1;
 1661+
 1662+ var te = Task.split(/<pGroup>/i)
 1663+ if(te.length> 2){var pGroup=te[1];} else {var pGroup = 0;}
 1664+ pGroup *= 1;
 1665+
 1666+ var te = Task.split(/<pParent>/i)
 1667+ if(te.length> 2){var pParent=te[1];} else {var pParent = 0;}
 1668+ pParent *= 1;
 1669+
 1670+ var te = Task.split(/<pOpen>/i)
 1671+ if(te.length> 2){var pOpen=te[1];} else {var pOpen = 1;}
 1672+ pOpen *= 1;
 1673+
 1674+ var te = Task.split(/<pDepend>/i)
 1675+ if(te.length> 2){var pDepend=te[1];} else {var pDepend = "";}
 1676+ //pDepend *= 1;
 1677+ if (pDepend.length==0){pDepend=''} // need this to draw the dependency lines
 1678+
 1679+ var te = Task.split(/<pCaption>/i)
 1680+ if(te.length> 2){var pCaption=te[1];} else {var pCaption = "";}
 1681+
 1682+ // Finally add the task
 1683+ pGanttVar.AddTaskItem(new JSGantt.TaskItem(pID , pName, pStart, pEnd, pColor, pLink, pMile, pRes, pComp, pGroup, pParent, pOpen, pDepend,pCaption ));
 1684+ }
 1685+ }
 1686+}
 1687+
 1688+JSGantt.benchMark = function(pItem){
 1689+ var vEndTime=new Date().getTime();
 1690+ alert(pItem + ': Elapsed time: '+((vEndTime-vBenchTime)/1000)+' seconds.');
 1691+ vBenchTime=new Date().getTime();
 1692+}
 1693+
 1694+
Property changes on: trunk/extensions/SemanticProjectManagement/libs/ganttchart/jsgantt.js
___________________________________________________________________
Added: svn:executable
11695 + *
Index: trunk/extensions/SemanticProjectManagement/libs/ganttchart/copyright.txt
@@ -0,0 +1,24 @@
 2+* Copyright (c) 2008, Shlomy Gantz/BlueBrick Inc.
 3+* All rights reserved.
 4+*
 5+* Redistribution and use in source and binary forms, with or without
 6+* modification, are permitted provided that the following conditions are met:
 7+* * Redistributions of source code must retain the above copyright
 8+* notice, this list of conditions and the following disclaimer.
 9+* * Redistributions in binary form must reproduce the above copyright
 10+* notice, this list of conditions and the following disclaimer in the
 11+* documentation and/or other materials provided with the distribution.
 12+* * Neither the name of Shlomy Gantz or BlueBrick Inc. nor the
 13+* names of its contributors may be used to endorse or promote products
 14+* derived from this software without specific prior written permission.
 15+*
 16+* THIS SOFTWARE IS PROVIDED BY SHLOMY GANTZ/BLUEBRICK INC. ''AS IS'' AND ANY
 17+* EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
 18+* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
 19+* DISCLAIMED. IN NO EVENT SHALL SHLOMY GANTZ/BLUEBRICK INC. BE LIABLE FOR ANY
 20+* DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
 21+* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
 22+* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
 23+* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
 24+* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
 25+* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
Index: trunk/extensions/SemanticProjectManagement/libs/ganttchart/discuss_icon.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/ganttchart/discuss_icon.png
___________________________________________________________________
Added: svn:mime-type
126 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/calendar.css
@@ -0,0 +1,95 @@
 2+/* calendar icon */
 3+img.tcalIcon {
 4+ cursor: pointer;
 5+ margin-left: 1px;
 6+ vertical-align: middle;
 7+}
 8+/* calendar container element */
 9+div#tcal {
 10+ position: absolute;
 11+ visibility: hidden;
 12+ z-index: 100;
 13+ width: 158px;
 14+ padding: 2px 0 0 0;
 15+}
 16+/* all tables in calendar */
 17+div#tcal table {
 18+ width: 100%;
 19+ border: 1px solid silver;
 20+ border-collapse: collapse;
 21+ background-color: white;
 22+}
 23+/* navigation table */
 24+div#tcal table.ctrl {
 25+ border-bottom: 0;
 26+}
 27+/* navigation buttons */
 28+div#tcal table.ctrl td {
 29+ width: 15px;
 30+ height: 20px;
 31+}
 32+/* month year header */
 33+div#tcal table.ctrl th {
 34+ background-color: white;
 35+ color: black;
 36+ border: 0;
 37+}
 38+/* week days header */
 39+div#tcal th {
 40+ border: 1px solid silver;
 41+ border-collapse: collapse;
 42+ text-align: center;
 43+ padding: 3px 0;
 44+ font-family: tahoma, verdana, arial;
 45+ font-size: 10px;
 46+ background-color: gray;
 47+ color: white;
 48+}
 49+/* date cells */
 50+div#tcal td {
 51+ border: 0;
 52+ border-collapse: collapse;
 53+ text-align: center;
 54+ padding: 2px 0;
 55+ font-family: tahoma, verdana, arial;
 56+ font-size: 11px;
 57+ width: 22px;
 58+ cursor: pointer;
 59+}
 60+/* date highlight
 61+ in case of conflicting settings order here determines the priority from least to most important */
 62+div#tcal td.othermonth {
 63+ color: silver;
 64+}
 65+div#tcal td.weekend {
 66+ background-color: #ACD6F5;
 67+}
 68+div#tcal td.today {
 69+ border: 1px solid red;
 70+}
 71+div#tcal td.selected {
 72+ background-color: #FFB3BE;
 73+}
 74+/* iframe element used to suppress windowed controls in IE5/6 */
 75+iframe#tcalIF {
 76+ position: absolute;
 77+ visibility: hidden;
 78+ z-index: 98;
 79+ border: 0;
 80+}
 81+/* transparent shadow */
 82+div#tcalShade {
 83+ position: absolute;
 84+ visibility: hidden;
 85+ z-index: 99;
 86+}
 87+div#tcalShade table {
 88+ border: 0;
 89+ border-collapse: collapse;
 90+ width: 100%;
 91+}
 92+div#tcalShade table td {
 93+ border: 0;
 94+ border-collapse: collapse;
 95+ padding: 0;
 96+}
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/license.txt
@@ -0,0 +1,16 @@
 2+Tigra Calendar v4.0 LICENSE:
 3+
 4+Permission is hereby granted, free of charge, to any person obtaining a copy
 5+of this software and associated documentation files (the "Software"), to deal
 6+in the Software without restriction, including without limitation the rights
 7+to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 8+copies of the Software, and to permit persons to whom the Software is
 9+furnished to do so
 10+
 11+THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 12+IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 13+FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 14+AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 15+LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 16+OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
 17+THE SOFTWARE.
\ No newline at end of file
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/calendar_db.js
@@ -0,0 +1,335 @@
 2+// Tigra Calendar v4.0.2 (2009-01-12) Database (yyyy-mm-dd)
 3+// http://www.softcomplex.com/products/tigra_calendar/
 4+// Public Domain Software... You're welcome.
 5+
 6+// default settins
 7+var A_TCALDEF = {
 8+ 'months' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
 9+ 'weekdays' : ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
 10+ 'yearscroll': true, // show year scroller
 11+ 'weekstart': 0, // first day of week: 0-Su or 1-Mo
 12+ 'centyear' : 70, // 2 digit years less than 'centyear' are in 20xx, othewise in 19xx.
 13+ 'imgpath' : 'img/' // directory with calendar images
 14+}
 15+// date parsing function
 16+function f_tcalParseDate (s_date) {
 17+
 18+ var re_date = /^\s*(\d{2,4})\-(\d{1,2})\-(\d{1,2})\s*$/;
 19+ if (!re_date.exec(s_date))
 20+ return alert ("Invalid date: '" + s_date + "'.\nAccepted format is yyyy-mm-dd.")
 21+ var n_day = Number(RegExp.$3),
 22+ n_month = Number(RegExp.$2),
 23+ n_year = Number(RegExp.$1);
 24+
 25+ if (n_year < 100)
 26+ n_year += (n_year < this.a_tpl.centyear ? 2000 : 1900);
 27+ if (n_month < 1 || n_month > 12)
 28+ return alert ("Invalid month value: '" + n_month + "'.\nAllowed range is 01-12.");
 29+ var d_numdays = new Date(n_year, n_month, 0);
 30+ if (n_day > d_numdays.getDate())
 31+ return alert("Invalid day of month value: '" + n_day + "'.\nAllowed range for selected month is 01 - " + d_numdays.getDate() + ".");
 32+
 33+ return new Date (n_year, n_month - 1, n_day);
 34+}
 35+// date generating function
 36+function f_tcalGenerDate (d_date) {
 37+ return (
 38+ d_date.getFullYear() + "-"
 39+ + (d_date.getMonth() < 9 ? '0' : '') + (d_date.getMonth() + 1) + "-"
 40+ + (d_date.getDate() < 10 ? '0' : '') + d_date.getDate()
 41+ );
 42+}
 43+
 44+// implementation
 45+function tcal (a_cfg, a_tpl) {
 46+
 47+ // apply default template if not specified
 48+ if (!a_tpl)
 49+ a_tpl = A_TCALDEF;
 50+
 51+ // register in global collections
 52+ if (!window.A_TCALS)
 53+ window.A_TCALS = [];
 54+ if (!window.A_TCALSIDX)
 55+ window.A_TCALSIDX = [];
 56+
 57+ this.s_id = a_cfg.id ? a_cfg.id : A_TCALS.length;
 58+ window.A_TCALS[this.s_id] = this;
 59+ window.A_TCALSIDX[window.A_TCALSIDX.length] = this;
 60+
 61+ // assign methods
 62+ this.f_show = f_tcalShow;
 63+ this.f_hide = f_tcalHide;
 64+ this.f_toggle = f_tcalToggle;
 65+ this.f_update = f_tcalUpdate;
 66+ this.f_relDate = f_tcalRelDate;
 67+ this.f_parseDate = f_tcalParseDate;
 68+ this.f_generDate = f_tcalGenerDate;
 69+
 70+ // create calendar icon
 71+ this.s_iconId = 'tcalico_' + this.s_id;
 72+ this.e_icon = f_getElement(this.s_iconId);
 73+ if (!this.e_icon) {
 74+ document.write('<img src="' + a_tpl.imgpath + 'cal.gif" id="' + this.s_iconId + '" onclick="A_TCALS[\'' + this.s_id + '\'].f_toggle()" class="tcalIcon" alt="Open Calendar" />');
 75+ this.e_icon = f_getElement(this.s_iconId);
 76+ }
 77+ // save received parameters
 78+ this.a_cfg = a_cfg;
 79+ this.a_tpl = a_tpl;
 80+}
 81+
 82+function f_tcalShow (d_date) {
 83+
 84+ // find input field
 85+ if (!this.a_cfg.controlname)
 86+ throw("TC: control name is not specified");
 87+ if (this.a_cfg.formname) {
 88+ var e_form = document.forms[this.a_cfg.formname];
 89+ if (!e_form)
 90+ throw("TC: form '" + this.a_cfg.formname + "' can not be found");
 91+ this.e_input = e_form.elements[this.a_cfg.controlname];
 92+ }
 93+ else
 94+ this.e_input = f_getElement(this.a_cfg.controlname);
 95+
 96+ if (!this.e_input || !this.e_input.tagName || this.e_input.tagName != 'INPUT')
 97+ throw("TC: element '" + this.a_cfg.controlname + "' does not exist in "
 98+ + (this.a_cfg.formname ? "form '" + this.a_cfg.controlname + "'" : 'this document'));
 99+
 100+ // dynamically create HTML elements if needed
 101+ this.e_div = f_getElement('tcal');
 102+ if (!this.e_div) {
 103+ this.e_div = document.createElement("DIV");
 104+ this.e_div.id = 'tcal';
 105+ document.body.appendChild(this.e_div);
 106+ }
 107+ this.e_shade = f_getElement('tcalShade');
 108+ if (!this.e_shade) {
 109+ this.e_shade = document.createElement("DIV");
 110+ this.e_shade.id = 'tcalShade';
 111+ document.body.appendChild(this.e_shade);
 112+ }
 113+ this.e_iframe = f_getElement('tcalIF')
 114+ if (b_ieFix && !this.e_iframe) {
 115+ this.e_iframe = document.createElement("IFRAME");
 116+ this.e_iframe.style.filter = 'alpha(opacity=0)';
 117+ this.e_iframe.id = 'tcalIF';
 118+ this.e_iframe.src = this.a_tpl.imgpath + 'pixel.gif';
 119+ document.body.appendChild(this.e_iframe);
 120+ }
 121+
 122+ // hide all calendars
 123+ f_tcalHideAll();
 124+
 125+ // generate HTML and show calendar
 126+ this.e_icon = f_getElement(this.s_iconId);
 127+ if (!this.f_update())
 128+ return;
 129+
 130+ this.e_div.style.visibility = 'visible';
 131+ this.e_shade.style.visibility = 'visible';
 132+ if (this.e_iframe)
 133+ this.e_iframe.style.visibility = 'visible';
 134+
 135+ // change icon and status
 136+ this.e_icon.src = this.a_tpl.imgpath + 'no_cal.gif';
 137+ this.e_icon.title = 'Close Calendar';
 138+ this.b_visible = true;
 139+}
 140+
 141+function f_tcalHide (n_date) {
 142+ if (n_date)
 143+ this.e_input.value = this.f_generDate(new Date(n_date));
 144+
 145+ // no action if not visible
 146+ if (!this.b_visible)
 147+ return;
 148+
 149+ // hide elements
 150+ if (this.e_iframe)
 151+ this.e_iframe.style.visibility = 'hidden';
 152+ if (this.e_shade)
 153+ this.e_shade.style.visibility = 'hidden';
 154+ this.e_div.style.visibility = 'hidden';
 155+
 156+ // change icon and status
 157+ this.e_icon = f_getElement(this.s_iconId);
 158+ this.e_icon.src = this.a_tpl.imgpath + 'cal.gif';
 159+ this.e_icon.title = 'Open Calendar';
 160+ this.b_visible = false;
 161+}
 162+
 163+function f_tcalToggle () {
 164+ return this.b_visible ? this.f_hide() : this.f_show();
 165+}
 166+
 167+function f_tcalUpdate (d_date) {
 168+
 169+ var d_today = this.a_cfg.today ? this.f_parseDate(this.a_cfg.today) : f_tcalResetTime(new Date());
 170+ var d_selected = this.e_input.value == ''
 171+ ? (this.a_cfg.selected ? this.f_parseDate(this.a_cfg.selected) : d_today)
 172+ : this.f_parseDate(this.e_input.value);
 173+
 174+ // figure out date to display
 175+ if (!d_date)
 176+ // selected by default
 177+ d_date = d_selected;
 178+ else if (typeof(d_date) == 'number')
 179+ // get from number
 180+ d_date = f_tcalResetTime(new Date(d_date));
 181+ else if (typeof(d_date) == 'string')
 182+ // parse from string
 183+ this.f_parseDate(d_date);
 184+
 185+ if (!d_date) return false;
 186+
 187+ // first date to display
 188+ var d_firstday = new Date(d_date);
 189+ d_firstday.setDate(1);
 190+ d_firstday.setDate(1 - (7 + d_firstday.getDay() - this.a_tpl.weekstart) % 7);
 191+
 192+ var a_class, s_html = '<table class="ctrl"><tbody><tr>'
 193+ + (this.a_tpl.yearscroll ? '<td' + this.f_relDate(d_date, -1, 'y') + ' title="Previous Year"><img src="' + this.a_tpl.imgpath + 'prev_year.gif" /></td>' : '')
 194+ + '<td' + this.f_relDate(d_date, -1) + ' title="Previous Month"><img src="' + this.a_tpl.imgpath + 'prev_mon.gif" /></td><th>'
 195+ + this.a_tpl.months[d_date.getMonth()] + ' ' + d_date.getFullYear()
 196+ + '</th><td' + this.f_relDate(d_date, 1) + ' title="Next Month"><img src="' + this.a_tpl.imgpath + 'next_mon.gif" /></td>'
 197+ + (this.a_tpl.yearscroll ? '<td' + this.f_relDate(d_date, 1, 'y') + ' title="Next Year"><img src="' + this.a_tpl.imgpath + 'next_year.gif" /></td></td>' : '')
 198+ + '</tr></tbody></table><table><tbody><tr class="wd">';
 199+
 200+ // print weekdays titles
 201+ for (var i = 0; i < 7; i++)
 202+ s_html += '<th>' + this.a_tpl.weekdays[(this.a_tpl.weekstart + i) % 7] + '</th>';
 203+ s_html += '</tr>' ;
 204+
 205+ // print calendar table
 206+ var n_date, n_month, d_current = new Date(d_firstday);
 207+ while (d_current.getMonth() == d_date.getMonth() ||
 208+ d_current.getMonth() == d_firstday.getMonth()) {
 209+
 210+ // print row heder
 211+ s_html +='<tr>';
 212+ for (var n_wday = 0; n_wday < 7; n_wday++) {
 213+
 214+ a_class = [];
 215+ n_date = d_current.getDate();
 216+ n_month = d_current.getMonth();
 217+
 218+ // other month
 219+ if (d_current.getMonth() != d_date.getMonth())
 220+ a_class[a_class.length] = 'othermonth';
 221+ // weekend
 222+ if (d_current.getDay() == 0 || d_current.getDay() == 6)
 223+ a_class[a_class.length] = 'weekend';
 224+ // today
 225+ if (d_current.valueOf() == d_today.valueOf())
 226+ a_class[a_class.length] = 'today';
 227+ // selected
 228+ if (d_current.valueOf() == d_selected.valueOf())
 229+ a_class[a_class.length] = 'selected';
 230+
 231+ s_html += '<td onclick="A_TCALS[\'' + this.s_id + '\'].f_hide(' + d_current.valueOf() + ')"' + (a_class.length ? ' class="' + a_class.join(' ') + '">' : '>') + n_date + '</td>'
 232+
 233+ d_current.setDate(++n_date);
 234+ while (d_current.getDate() != n_date && d_current.getMonth() == n_month) {
 235+ d_current.setHours(d_current.getHours + 1);
 236+ d_current = f_tcalResetTime(d_current);
 237+ }
 238+ }
 239+ // print row footer
 240+ s_html +='</tr>';
 241+ }
 242+ s_html +='</tbody></table>';
 243+
 244+ // update HTML, positions and sizes
 245+ this.e_div.innerHTML = s_html;
 246+
 247+ var n_width = this.e_div.offsetWidth;
 248+ var n_height = this.e_div.offsetHeight;
 249+ var n_top = f_getPosition (this.e_icon, 'Top') + this.e_icon.offsetHeight;
 250+ var n_left = f_getPosition (this.e_icon, 'Left') - n_width + this.e_icon.offsetWidth;
 251+ if (n_left < 0) n_left = 0;
 252+
 253+ this.e_div.style.left = n_left + 'px';
 254+ this.e_div.style.top = n_top + 'px';
 255+
 256+ this.e_shade.style.width = (n_width + 8) + 'px';
 257+ this.e_shade.style.left = (n_left - 1) + 'px';
 258+ this.e_shade.style.top = (n_top - 1) + 'px';
 259+ this.e_shade.innerHTML = b_ieFix
 260+ ? '<table><tbody><tr><td rowspan="2" colspan="2" width="6"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td width="7" height="7" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_tr.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td height="' + (n_height - 7) + '" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_mr.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td width="7" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_bl.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_bm.png\', sizingMethod=\'scale\');" height="7" align="left"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_br.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tbody></table>'
 261+ : '<table><tbody><tr><td rowspan="2" width="6"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td rowspan="2"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td width="7" height="7"><img src="' + this.a_tpl.imgpath + 'shade_tr.png"></td></tr><tr><td background="' + this.a_tpl.imgpath + 'shade_mr.png" height="' + (n_height - 7) + '"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td><img src="' + this.a_tpl.imgpath + 'shade_bl.png"></td><td background="' + this.a_tpl.imgpath + 'shade_bm.png" height="7" align="left"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td><img src="' + this.a_tpl.imgpath + 'shade_br.png"></td></tr><tbody></table>';
 262+
 263+ if (this.e_iframe) {
 264+ this.e_iframe.style.left = n_left + 'px';
 265+ this.e_iframe.style.top = n_top + 'px';
 266+ this.e_iframe.style.width = (n_width + 6) + 'px';
 267+ this.e_iframe.style.height = (n_height + 6) +'px';
 268+ }
 269+ return true;
 270+}
 271+
 272+function f_getPosition (e_elemRef, s_coord) {
 273+ var n_pos = 0, n_offset,
 274+ e_elem = e_elemRef;
 275+
 276+ while (e_elem) {
 277+ n_offset = e_elem["offset" + s_coord];
 278+ n_pos += n_offset;
 279+ e_elem = e_elem.offsetParent;
 280+ }
 281+ // margin correction in some browsers
 282+ if (b_ieMac)
 283+ n_pos += parseInt(document.body[s_coord.toLowerCase() + 'Margin']);
 284+ else if (b_safari)
 285+ n_pos -= n_offset;
 286+
 287+ e_elem = e_elemRef;
 288+ while (e_elem != document.body) {
 289+ n_offset = e_elem["scroll" + s_coord];
 290+ if (n_offset && e_elem.style.overflow == 'scroll')
 291+ n_pos -= n_offset;
 292+ e_elem = e_elem.parentNode;
 293+ }
 294+ return n_pos;
 295+}
 296+
 297+function f_tcalRelDate (d_date, d_diff, s_units) {
 298+ var s_units = (s_units == 'y' ? 'FullYear' : 'Month');
 299+ var d_result = new Date(d_date);
 300+ d_result['set' + s_units](d_date['get' + s_units]() + d_diff);
 301+ if (d_result.getDate() != d_date.getDate())
 302+ d_result.setDate(0);
 303+ return ' onclick="A_TCALS[\'' + this.s_id + '\'].f_update(' + d_result.valueOf() + ')"';
 304+}
 305+
 306+function f_tcalHideAll () {
 307+ for (var i = 0; i < window.A_TCALSIDX.length; i++)
 308+ window.A_TCALSIDX[i].f_hide();
 309+}
 310+
 311+function f_tcalResetTime (d_date) {
 312+ d_date.setHours(0);
 313+ d_date.setMinutes(0);
 314+ d_date.setSeconds(0);
 315+ d_date.setMilliseconds(0);
 316+ return d_date;
 317+}
 318+
 319+f_getElement = document.all ?
 320+ function (s_id) { return document.all[s_id] } :
 321+ function (s_id) { return document.getElementById(s_id) };
 322+
 323+if (document.addEventListener)
 324+ window.addEventListener('scroll', f_tcalHideAll, false);
 325+if (window.attachEvent)
 326+ window.attachEvent('onscroll', f_tcalHideAll);
 327+
 328+// global variables
 329+var s_userAgent = navigator.userAgent.toLowerCase(),
 330+ re_webkit = /WebKit\/(\d+)/i;
 331+var b_mac = s_userAgent.indexOf('mac') != -1,
 332+ b_ie5 = s_userAgent.indexOf('msie 5') != -1,
 333+ b_ie6 = s_userAgent.indexOf('msie 6') != -1 && s_userAgent.indexOf('opera') == -1;
 334+var b_ieFix = b_ie5 || b_ie6,
 335+ b_ieMac = b_mac && b_ie5,
 336+ b_safari = b_mac && re_webkit.exec(s_userAgent) && Number(RegExp.$1) < 500;
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/calendar_us.js
@@ -0,0 +1,335 @@
 2+// Tigra Calendar v4.0.3 (01/12/2009) American (mm/dd/yyyy)
 3+// http://www.softcomplex.com/products/tigra_calendar/
 4+// Public Domain Software... You're welcome.
 5+
 6+// default settins
 7+var A_TCALDEF = {
 8+ 'months' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
 9+ 'weekdays' : ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
 10+ 'yearscroll': true, // show year scroller
 11+ 'weekstart': 0, // first day of week: 0-Su or 1-Mo
 12+ 'centyear' : 70, // 2 digit years less than 'centyear' are in 20xx, othewise in 19xx.
 13+ 'imgpath' : 'img/' // directory with calendar images
 14+}
 15+// date parsing function
 16+function f_tcalParseDate (s_date) {
 17+
 18+ var re_date = /^\s*(\d{1,2})\/(\d{1,2})\/(\d{2,4})\s*$/;
 19+ if (!re_date.exec(s_date))
 20+ return alert ("Invalid date: '" + s_date + "'.\nAccepted format is mm/dd/yyyy.")
 21+ var n_day = Number(RegExp.$2),
 22+ n_month = Number(RegExp.$1),
 23+ n_year = Number(RegExp.$3);
 24+
 25+ if (n_year < 100)
 26+ n_year += (n_year < this.a_tpl.centyear ? 2000 : 1900);
 27+ if (n_month < 1 || n_month > 12)
 28+ return alert ("Invalid month value: '" + n_month + "'.\nAllowed range is 01-12.");
 29+ var d_numdays = new Date(n_year, n_month, 0);
 30+ if (n_day > d_numdays.getDate())
 31+ return alert("Invalid day of month value: '" + n_day + "'.\nAllowed range for selected month is 01 - " + d_numdays.getDate() + ".");
 32+
 33+ return new Date (n_year, n_month - 1, n_day);
 34+}
 35+// date generating function
 36+function f_tcalGenerDate (d_date) {
 37+ return (
 38+ (d_date.getMonth() < 9 ? '0' : '') + (d_date.getMonth() + 1) + "/"
 39+ + (d_date.getDate() < 10 ? '0' : '') + d_date.getDate() + "/"
 40+ + d_date.getFullYear()
 41+ );
 42+}
 43+
 44+// implementation
 45+function tcal (a_cfg, a_tpl) {
 46+
 47+ // apply default template if not specified
 48+ if (!a_tpl)
 49+ a_tpl = A_TCALDEF;
 50+
 51+ // register in global collections
 52+ if (!window.A_TCALS)
 53+ window.A_TCALS = [];
 54+ if (!window.A_TCALSIDX)
 55+ window.A_TCALSIDX = [];
 56+
 57+ this.s_id = a_cfg.id ? a_cfg.id : A_TCALS.length;
 58+ window.A_TCALS[this.s_id] = this;
 59+ window.A_TCALSIDX[window.A_TCALSIDX.length] = this;
 60+
 61+ // assign methods
 62+ this.f_show = f_tcalShow;
 63+ this.f_hide = f_tcalHide;
 64+ this.f_toggle = f_tcalToggle;
 65+ this.f_update = f_tcalUpdate;
 66+ this.f_relDate = f_tcalRelDate;
 67+ this.f_parseDate = f_tcalParseDate;
 68+ this.f_generDate = f_tcalGenerDate;
 69+
 70+ // create calendar icon
 71+ this.s_iconId = 'tcalico_' + this.s_id;
 72+ this.e_icon = f_getElement(this.s_iconId);
 73+ if (!this.e_icon) {
 74+ document.write('<img src="' + a_tpl.imgpath + 'cal.gif" id="' + this.s_iconId + '" onclick="A_TCALS[\'' + this.s_id + '\'].f_toggle()" class="tcalIcon" alt="Open Calendar" />');
 75+ this.e_icon = f_getElement(this.s_iconId);
 76+ }
 77+ // save received parameters
 78+ this.a_cfg = a_cfg;
 79+ this.a_tpl = a_tpl;
 80+}
 81+
 82+function f_tcalShow (d_date) {
 83+
 84+ // find input field
 85+ if (!this.a_cfg.controlname)
 86+ throw("TC: control name is not specified");
 87+ if (this.a_cfg.formname) {
 88+ var e_form = document.forms[this.a_cfg.formname];
 89+ if (!e_form)
 90+ throw("TC: form '" + this.a_cfg.formname + "' can not be found");
 91+ this.e_input = e_form.elements[this.a_cfg.controlname];
 92+ }
 93+ else
 94+ this.e_input = f_getElement(this.a_cfg.controlname);
 95+
 96+ if (!this.e_input || !this.e_input.tagName || this.e_input.tagName != 'INPUT')
 97+ throw("TC: element '" + this.a_cfg.controlname + "' does not exist in "
 98+ + (this.a_cfg.formname ? "form '" + this.a_cfg.controlname + "'" : 'this document'));
 99+
 100+ // dynamically create HTML elements if needed
 101+ this.e_div = f_getElement('tcal');
 102+ if (!this.e_div) {
 103+ this.e_div = document.createElement("DIV");
 104+ this.e_div.id = 'tcal';
 105+ document.body.appendChild(this.e_div);
 106+ }
 107+ this.e_shade = f_getElement('tcalShade');
 108+ if (!this.e_shade) {
 109+ this.e_shade = document.createElement("DIV");
 110+ this.e_shade.id = 'tcalShade';
 111+ document.body.appendChild(this.e_shade);
 112+ }
 113+ this.e_iframe = f_getElement('tcalIF')
 114+ if (b_ieFix && !this.e_iframe) {
 115+ this.e_iframe = document.createElement("IFRAME");
 116+ this.e_iframe.style.filter = 'alpha(opacity=0)';
 117+ this.e_iframe.id = 'tcalIF';
 118+ this.e_iframe.src = this.a_tpl.imgpath + 'pixel.gif';
 119+ document.body.appendChild(this.e_iframe);
 120+ }
 121+
 122+ // hide all calendars
 123+ f_tcalHideAll();
 124+
 125+ // generate HTML and show calendar
 126+ this.e_icon = f_getElement(this.s_iconId);
 127+ if (!this.f_update())
 128+ return;
 129+
 130+ this.e_div.style.visibility = 'visible';
 131+ this.e_shade.style.visibility = 'visible';
 132+ if (this.e_iframe)
 133+ this.e_iframe.style.visibility = 'visible';
 134+
 135+ // change icon and status
 136+ this.e_icon.src = this.a_tpl.imgpath + 'no_cal.gif';
 137+ this.e_icon.title = 'Close Calendar';
 138+ this.b_visible = true;
 139+}
 140+
 141+function f_tcalHide (n_date) {
 142+ if (n_date)
 143+ this.e_input.value = this.f_generDate(new Date(n_date));
 144+
 145+ // no action if not visible
 146+ if (!this.b_visible)
 147+ return;
 148+
 149+ // hide elements
 150+ if (this.e_iframe)
 151+ this.e_iframe.style.visibility = 'hidden';
 152+ if (this.e_shade)
 153+ this.e_shade.style.visibility = 'hidden';
 154+ this.e_div.style.visibility = 'hidden';
 155+
 156+ // change icon and status
 157+ this.e_icon = f_getElement(this.s_iconId);
 158+ this.e_icon.src = this.a_tpl.imgpath + 'cal.gif';
 159+ this.e_icon.title = 'Open Calendar';
 160+ this.b_visible = false;
 161+}
 162+
 163+function f_tcalToggle () {
 164+ return this.b_visible ? this.f_hide() : this.f_show();
 165+}
 166+
 167+function f_tcalUpdate (d_date) {
 168+
 169+ var d_today = this.a_cfg.today ? this.f_parseDate(this.a_cfg.today) : f_tcalResetTime(new Date());
 170+ var d_selected = this.e_input.value == ''
 171+ ? (this.a_cfg.selected ? this.f_parseDate(this.a_cfg.selected) : d_today)
 172+ : this.f_parseDate(this.e_input.value);
 173+
 174+ // figure out date to display
 175+ if (!d_date)
 176+ // selected by default
 177+ d_date = d_selected;
 178+ else if (typeof(d_date) == 'number')
 179+ // get from number
 180+ d_date = f_tcalResetTime(new Date(d_date));
 181+ else if (typeof(d_date) == 'string')
 182+ // parse from string
 183+ this.f_parseDate(d_date);
 184+
 185+ if (!d_date) return false;
 186+
 187+ // first date to display
 188+ var d_firstday = new Date(d_date);
 189+ d_firstday.setDate(1);
 190+ d_firstday.setDate(1 - (7 + d_firstday.getDay() - this.a_tpl.weekstart) % 7);
 191+
 192+ var a_class, s_html = '<table class="ctrl"><tbody><tr>'
 193+ + (this.a_tpl.yearscroll ? '<td' + this.f_relDate(d_date, -1, 'y') + ' title="Previous Year"><img src="' + this.a_tpl.imgpath + 'prev_year.gif" /></td>' : '')
 194+ + '<td' + this.f_relDate(d_date, -1) + ' title="Previous Month"><img src="' + this.a_tpl.imgpath + 'prev_mon.gif" /></td><th>'
 195+ + this.a_tpl.months[d_date.getMonth()] + ' ' + d_date.getFullYear()
 196+ + '</th><td' + this.f_relDate(d_date, 1) + ' title="Next Month"><img src="' + this.a_tpl.imgpath + 'next_mon.gif" /></td>'
 197+ + (this.a_tpl.yearscroll ? '<td' + this.f_relDate(d_date, 1, 'y') + ' title="Next Year"><img src="' + this.a_tpl.imgpath + 'next_year.gif" /></td></td>' : '')
 198+ + '</tr></tbody></table><table><tbody><tr class="wd">';
 199+
 200+ // print weekdays titles
 201+ for (var i = 0; i < 7; i++)
 202+ s_html += '<th>' + this.a_tpl.weekdays[(this.a_tpl.weekstart + i) % 7] + '</th>';
 203+ s_html += '</tr>' ;
 204+
 205+ // print calendar table
 206+ var n_date, n_month, d_current = new Date(d_firstday);
 207+ while (d_current.getMonth() == d_date.getMonth() ||
 208+ d_current.getMonth() == d_firstday.getMonth()) {
 209+
 210+ // print row heder
 211+ s_html +='<tr>';
 212+ for (var n_wday = 0; n_wday < 7; n_wday++) {
 213+
 214+ a_class = [];
 215+ n_date = d_current.getDate();
 216+ n_month = d_current.getMonth();
 217+
 218+ // other month
 219+ if (d_current.getMonth() != d_date.getMonth())
 220+ a_class[a_class.length] = 'othermonth';
 221+ // weekend
 222+ if (d_current.getDay() == 0 || d_current.getDay() == 6)
 223+ a_class[a_class.length] = 'weekend';
 224+ // today
 225+ if (d_current.valueOf() == d_today.valueOf())
 226+ a_class[a_class.length] = 'today';
 227+ // selected
 228+ if (d_current.valueOf() == d_selected.valueOf())
 229+ a_class[a_class.length] = 'selected';
 230+
 231+ s_html += '<td onclick="A_TCALS[\'' + this.s_id + '\'].f_hide(' + d_current.valueOf() + ')"' + (a_class.length ? ' class="' + a_class.join(' ') + '">' : '>') + n_date + '</td>'
 232+
 233+ d_current.setDate(++n_date);
 234+ while (d_current.getDate() != n_date && d_current.getMonth() == n_month) {
 235+ d_current.setHours(d_current.getHours + 1);
 236+ d_current = f_tcalResetTime(d_current);
 237+ }
 238+ }
 239+ // print row footer
 240+ s_html +='</tr>';
 241+ }
 242+ s_html +='</tbody></table>';
 243+
 244+ // update HTML, positions and sizes
 245+ this.e_div.innerHTML = s_html;
 246+
 247+ var n_width = this.e_div.offsetWidth;
 248+ var n_height = this.e_div.offsetHeight;
 249+ var n_top = f_getPosition (this.e_icon, 'Top') + this.e_icon.offsetHeight;
 250+ var n_left = f_getPosition (this.e_icon, 'Left') - n_width + this.e_icon.offsetWidth;
 251+ if (n_left < 0) n_left = 0;
 252+
 253+ this.e_div.style.left = n_left + 'px';
 254+ this.e_div.style.top = n_top + 'px';
 255+
 256+ this.e_shade.style.width = (n_width + 8) + 'px';
 257+ this.e_shade.style.left = (n_left - 1) + 'px';
 258+ this.e_shade.style.top = (n_top - 1) + 'px';
 259+ this.e_shade.innerHTML = b_ieFix
 260+ ? '<table><tbody><tr><td rowspan="2" colspan="2" width="6"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td width="7" height="7" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_tr.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td height="' + (n_height - 7) + '" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_mr.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td width="7" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_bl.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_bm.png\', sizingMethod=\'scale\');" height="7" align="left"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_br.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tbody></table>'
 261+ : '<table><tbody><tr><td rowspan="2" width="6"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td rowspan="2"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td width="7" height="7"><img src="' + this.a_tpl.imgpath + 'shade_tr.png"></td></tr><tr><td background="' + this.a_tpl.imgpath + 'shade_mr.png" height="' + (n_height - 7) + '"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td><img src="' + this.a_tpl.imgpath + 'shade_bl.png"></td><td background="' + this.a_tpl.imgpath + 'shade_bm.png" height="7" align="left"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td><img src="' + this.a_tpl.imgpath + 'shade_br.png"></td></tr><tbody></table>';
 262+
 263+ if (this.e_iframe) {
 264+ this.e_iframe.style.left = n_left + 'px';
 265+ this.e_iframe.style.top = n_top + 'px';
 266+ this.e_iframe.style.width = (n_width + 6) + 'px';
 267+ this.e_iframe.style.height = (n_height + 6) +'px';
 268+ }
 269+ return true;
 270+}
 271+
 272+function f_getPosition (e_elemRef, s_coord) {
 273+ var n_pos = 0, n_offset,
 274+ e_elem = e_elemRef;
 275+
 276+ while (e_elem) {
 277+ n_offset = e_elem["offset" + s_coord];
 278+ n_pos += n_offset;
 279+ e_elem = e_elem.offsetParent;
 280+ }
 281+ // margin correction in some browsers
 282+ if (b_ieMac)
 283+ n_pos += parseInt(document.body[s_coord.toLowerCase() + 'Margin']);
 284+ else if (b_safari)
 285+ n_pos -= n_offset;
 286+
 287+ e_elem = e_elemRef;
 288+ while (e_elem != document.body) {
 289+ n_offset = e_elem["scroll" + s_coord];
 290+ if (n_offset && e_elem.style.overflow == 'scroll')
 291+ n_pos -= n_offset;
 292+ e_elem = e_elem.parentNode;
 293+ }
 294+ return n_pos;
 295+}
 296+
 297+function f_tcalRelDate (d_date, d_diff, s_units) {
 298+ var s_units = (s_units == 'y' ? 'FullYear' : 'Month');
 299+ var d_result = new Date(d_date);
 300+ d_result['set' + s_units](d_date['get' + s_units]() + d_diff);
 301+ if (d_result.getDate() != d_date.getDate())
 302+ d_result.setDate(0);
 303+ return ' onclick="A_TCALS[\'' + this.s_id + '\'].f_update(' + d_result.valueOf() + ')"';
 304+}
 305+
 306+function f_tcalHideAll () {
 307+ for (var i = 0; i < window.A_TCALSIDX.length; i++)
 308+ window.A_TCALSIDX[i].f_hide();
 309+}
 310+
 311+function f_tcalResetTime (d_date) {
 312+ d_date.setHours(0);
 313+ d_date.setMinutes(0);
 314+ d_date.setSeconds(0);
 315+ d_date.setMilliseconds(0);
 316+ return d_date;
 317+}
 318+
 319+f_getElement = document.all ?
 320+ function (s_id) { return document.all[s_id] } :
 321+ function (s_id) { return document.getElementById(s_id) };
 322+
 323+if (document.addEventListener)
 324+ window.addEventListener('scroll', f_tcalHideAll, false);
 325+if (window.attachEvent)
 326+ window.attachEvent('onscroll', f_tcalHideAll);
 327+
 328+// global variables
 329+var s_userAgent = navigator.userAgent.toLowerCase(),
 330+ re_webkit = /WebKit\/(\d+)/i;
 331+var b_mac = s_userAgent.indexOf('mac') != -1,
 332+ b_ie5 = s_userAgent.indexOf('msie 5') != -1,
 333+ b_ie6 = s_userAgent.indexOf('msie 6') != -1 && s_userAgent.indexOf('opera') == -1;
 334+var b_ieFix = b_ie5 || b_ie6,
 335+ b_ieMac = b_mac && b_ie5,
 336+ b_safari = b_mac && re_webkit.exec(s_userAgent) && Number(RegExp.$1) < 500;
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/readme.txt
@@ -0,0 +1,45 @@
 2+
 3+Tigra Calendar readme
 4+----------------------------------------------
 5+
 6+Thank you for downloading Tigra Calendar! We appreciate your interest
 7+and we hope that you'll enjoy working with the component.
 8+
 9+
 10+GETTING STARTED
 11+----------------------------------------------
 12+
 13+Tigra Calendar is a JavaScript software component, it is not intended
 14+for stand-alone use. We included several working samples demonstrating
 15+component's features and possible use scenarios, but eventually the
 16+calendar must be configured inside your own web pages. Follow the
 17+steps below to implement the calendar in your application:
 18+
 19+1. Test the samples, make sure calendar works in all the required browsers
 20+2. Make a copy of one of the samples and customize the calendar's
 21+ configuration for your needs. Check the page after every modification.
 22+3. Copy calendar related code from the test page into the destination
 23+ page. Adjust paths if needed.
 24+
 25+DOCUMENTATION
 26+----------------------------------------------
 27+
 28+The documentation for the latest version of the component is available at:
 29+http://www.softcomplex.com/products/tigra_calendar/docs/
 30+
 31+TECHNICAL SUPPORT
 32+----------------------------------------------
 33+
 34+For general questions please use our forum at:
 35+http://www.softcomplex.com/forum/forumdisplay_42/
 36+
 37+For full list of the available support options visit:
 38+http://www.softcomplex.com/support.html
 39+
 40+Subscribe to our RSS feed to be notified about new releases of the component:
 41+http://www.softcomplex.com/news.xml
 42+
 43+--
 44+Thank you and good luck!
 45+Softcomplex Team
 46+
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/no_cal.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/no_cal.gif
___________________________________________________________________
Added: svn:mime-type
147 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/prev_year.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/prev_year.gif
___________________________________________________________________
Added: svn:mime-type
248 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/next_year.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/next_year.gif
___________________________________________________________________
Added: svn:mime-type
349 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/cal.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/cal.gif
___________________________________________________________________
Added: svn:mime-type
450 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_bl.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_bl.png
___________________________________________________________________
Added: svn:mime-type
551 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/pixel.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/pixel.gif
___________________________________________________________________
Added: svn:mime-type
652 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_bm.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_bm.png
___________________________________________________________________
Added: svn:mime-type
753 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_mr.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_mr.png
___________________________________________________________________
Added: svn:mime-type
854 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/prev_mon.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/prev_mon.gif
___________________________________________________________________
Added: svn:mime-type
955 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_br.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_br.png
___________________________________________________________________
Added: svn:mime-type
1056 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/next_mon.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/next_mon.gif
___________________________________________________________________
Added: svn:mime-type
1157 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_tr.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/calendar/img/shade_tr.png
___________________________________________________________________
Added: svn:mime-type
1258 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/calendar/calendar_eu.js
@@ -0,0 +1,335 @@
 2+// Tigra Calendar v4.0.2 (12-01-2009) European (dd-mm-yyyy)
 3+// http://www.softcomplex.com/products/tigra_calendar/
 4+// Public Domain Software... You're welcome.
 5+
 6+// default settins
 7+var A_TCALDEF = {
 8+ 'months' : ['January', 'February', 'March', 'April', 'May', 'June', 'July', 'August', 'September', 'October', 'November', 'December'],
 9+ 'weekdays' : ['Su', 'Mo', 'Tu', 'We', 'Th', 'Fr', 'Sa'],
 10+ 'yearscroll': true, // show year scroller
 11+ 'weekstart': 1, // first day of week: 0-Su or 1-Mo
 12+ 'centyear' : 70, // 2 digit years less than 'centyear' are in 20xx, othewise in 19xx.
 13+ 'imgpath' : 'img/' // directory with calendar images
 14+}
 15+// date parsing function
 16+function f_tcalParseDate (s_date) {
 17+
 18+ var re_date = /^\s*(\d{1,2})\-(\d{1,2})\-(\d{2,4})\s*$/;
 19+ if (!re_date.exec(s_date))
 20+ return alert ("Invalid date: '" + s_date + "'.\nAccepted format is dd-mm-yyyy.")
 21+ var n_day = Number(RegExp.$1),
 22+ n_month = Number(RegExp.$2),
 23+ n_year = Number(RegExp.$3);
 24+
 25+ if (n_year < 100)
 26+ n_year += (n_year < this.a_tpl.centyear ? 2000 : 1900);
 27+ if (n_month < 1 || n_month > 12)
 28+ return alert ("Invalid month value: '" + n_month + "'.\nAllowed range is 01-12.");
 29+ var d_numdays = new Date(n_year, n_month, 0);
 30+ if (n_day > d_numdays.getDate())
 31+ return alert("Invalid day of month value: '" + n_day + "'.\nAllowed range for selected month is 01 - " + d_numdays.getDate() + ".");
 32+
 33+ return new Date (n_year, n_month - 1, n_day);
 34+}
 35+// date generating function
 36+function f_tcalGenerDate (d_date) {
 37+ return (
 38+ (d_date.getDate() < 10 ? '0' : '') + d_date.getDate() + "-"
 39+ + (d_date.getMonth() < 9 ? '0' : '') + (d_date.getMonth() + 1) + "-"
 40+ + d_date.getFullYear()
 41+ );
 42+}
 43+
 44+// implementation
 45+function tcal (a_cfg, a_tpl) {
 46+
 47+ // apply default template if not specified
 48+ if (!a_tpl)
 49+ a_tpl = A_TCALDEF;
 50+
 51+ // register in global collections
 52+ if (!window.A_TCALS)
 53+ window.A_TCALS = [];
 54+ if (!window.A_TCALSIDX)
 55+ window.A_TCALSIDX = [];
 56+
 57+ this.s_id = a_cfg.id ? a_cfg.id : A_TCALS.length;
 58+ window.A_TCALS[this.s_id] = this;
 59+ window.A_TCALSIDX[window.A_TCALSIDX.length] = this;
 60+
 61+ // assign methods
 62+ this.f_show = f_tcalShow;
 63+ this.f_hide = f_tcalHide;
 64+ this.f_toggle = f_tcalToggle;
 65+ this.f_update = f_tcalUpdate;
 66+ this.f_relDate = f_tcalRelDate;
 67+ this.f_parseDate = f_tcalParseDate;
 68+ this.f_generDate = f_tcalGenerDate;
 69+
 70+ // create calendar icon
 71+ this.s_iconId = 'tcalico_' + this.s_id;
 72+ this.e_icon = f_getElement(this.s_iconId);
 73+ if (!this.e_icon) {
 74+ document.write('<img src="' + a_tpl.imgpath + 'cal.gif" id="' + this.s_iconId + '" onclick="A_TCALS[\'' + this.s_id + '\'].f_toggle()" class="tcalIcon" alt="Open Calendar" />');
 75+ this.e_icon = f_getElement(this.s_iconId);
 76+ }
 77+ // save received parameters
 78+ this.a_cfg = a_cfg;
 79+ this.a_tpl = a_tpl;
 80+}
 81+
 82+function f_tcalShow (d_date) {
 83+
 84+ // find input field
 85+ if (!this.a_cfg.controlname)
 86+ throw("TC: control name is not specified");
 87+ if (this.a_cfg.formname) {
 88+ var e_form = document.forms[this.a_cfg.formname];
 89+ if (!e_form)
 90+ throw("TC: form '" + this.a_cfg.formname + "' can not be found");
 91+ this.e_input = e_form.elements[this.a_cfg.controlname];
 92+ }
 93+ else
 94+ this.e_input = f_getElement(this.a_cfg.controlname);
 95+
 96+ if (!this.e_input || !this.e_input.tagName || this.e_input.tagName != 'INPUT')
 97+ throw("TC: element '" + this.a_cfg.controlname + "' does not exist in "
 98+ + (this.a_cfg.formname ? "form '" + this.a_cfg.controlname + "'" : 'this document'));
 99+
 100+ // dynamically create HTML elements if needed
 101+ this.e_div = f_getElement('tcal');
 102+ if (!this.e_div) {
 103+ this.e_div = document.createElement("DIV");
 104+ this.e_div.id = 'tcal';
 105+ document.body.appendChild(this.e_div);
 106+ }
 107+ this.e_shade = f_getElement('tcalShade');
 108+ if (!this.e_shade) {
 109+ this.e_shade = document.createElement("DIV");
 110+ this.e_shade.id = 'tcalShade';
 111+ document.body.appendChild(this.e_shade);
 112+ }
 113+ this.e_iframe = f_getElement('tcalIF')
 114+ if (b_ieFix && !this.e_iframe) {
 115+ this.e_iframe = document.createElement("IFRAME");
 116+ this.e_iframe.style.filter = 'alpha(opacity=0)';
 117+ this.e_iframe.id = 'tcalIF';
 118+ this.e_iframe.src = this.a_tpl.imgpath + 'pixel.gif';
 119+ document.body.appendChild(this.e_iframe);
 120+ }
 121+
 122+ // hide all calendars
 123+ f_tcalHideAll();
 124+
 125+ // generate HTML and show calendar
 126+ this.e_icon = f_getElement(this.s_iconId);
 127+ if (!this.f_update())
 128+ return;
 129+
 130+ this.e_div.style.visibility = 'visible';
 131+ this.e_shade.style.visibility = 'visible';
 132+ if (this.e_iframe)
 133+ this.e_iframe.style.visibility = 'visible';
 134+
 135+ // change icon and status
 136+ this.e_icon.src = this.a_tpl.imgpath + 'no_cal.gif';
 137+ this.e_icon.title = 'Close Calendar';
 138+ this.b_visible = true;
 139+}
 140+
 141+function f_tcalHide (n_date) {
 142+ if (n_date)
 143+ this.e_input.value = this.f_generDate(new Date(n_date));
 144+
 145+ // no action if not visible
 146+ if (!this.b_visible)
 147+ return;
 148+
 149+ // hide elements
 150+ if (this.e_iframe)
 151+ this.e_iframe.style.visibility = 'hidden';
 152+ if (this.e_shade)
 153+ this.e_shade.style.visibility = 'hidden';
 154+ this.e_div.style.visibility = 'hidden';
 155+
 156+ // change icon and status
 157+ this.e_icon = f_getElement(this.s_iconId);
 158+ this.e_icon.src = this.a_tpl.imgpath + 'cal.gif';
 159+ this.e_icon.title = 'Open Calendar';
 160+ this.b_visible = false;
 161+}
 162+
 163+function f_tcalToggle () {
 164+ return this.b_visible ? this.f_hide() : this.f_show();
 165+}
 166+
 167+function f_tcalUpdate (d_date) {
 168+
 169+ var d_today = this.a_cfg.today ? this.f_parseDate(this.a_cfg.today) : f_tcalResetTime(new Date());
 170+ var d_selected = this.e_input.value == ''
 171+ ? (this.a_cfg.selected ? this.f_parseDate(this.a_cfg.selected) : d_today)
 172+ : this.f_parseDate(this.e_input.value);
 173+
 174+ // figure out date to display
 175+ if (!d_date)
 176+ // selected by default
 177+ d_date = d_selected;
 178+ else if (typeof(d_date) == 'number')
 179+ // get from number
 180+ d_date = f_tcalResetTime(new Date(d_date));
 181+ else if (typeof(d_date) == 'string')
 182+ // parse from string
 183+ this.f_parseDate(d_date);
 184+
 185+ if (!d_date) return false;
 186+
 187+ // first date to display
 188+ var d_firstday = new Date(d_date);
 189+ d_firstday.setDate(1);
 190+ d_firstday.setDate(1 - (7 + d_firstday.getDay() - this.a_tpl.weekstart) % 7);
 191+
 192+ var a_class, s_html = '<table class="ctrl"><tbody><tr>'
 193+ + (this.a_tpl.yearscroll ? '<td' + this.f_relDate(d_date, -1, 'y') + ' title="Previous Year"><img src="' + this.a_tpl.imgpath + 'prev_year.gif" /></td>' : '')
 194+ + '<td' + this.f_relDate(d_date, -1) + ' title="Previous Month"><img src="' + this.a_tpl.imgpath + 'prev_mon.gif" /></td><th>'
 195+ + this.a_tpl.months[d_date.getMonth()] + ' ' + d_date.getFullYear()
 196+ + '</th><td' + this.f_relDate(d_date, 1) + ' title="Next Month"><img src="' + this.a_tpl.imgpath + 'next_mon.gif" /></td>'
 197+ + (this.a_tpl.yearscroll ? '<td' + this.f_relDate(d_date, 1, 'y') + ' title="Next Year"><img src="' + this.a_tpl.imgpath + 'next_year.gif" /></td></td>' : '')
 198+ + '</tr></tbody></table><table><tbody><tr class="wd">';
 199+
 200+ // print weekdays titles
 201+ for (var i = 0; i < 7; i++)
 202+ s_html += '<th>' + this.a_tpl.weekdays[(this.a_tpl.weekstart + i) % 7] + '</th>';
 203+ s_html += '</tr>' ;
 204+
 205+ // print calendar table
 206+ var n_date, n_month, d_current = new Date(d_firstday);
 207+ while (d_current.getMonth() == d_date.getMonth() ||
 208+ d_current.getMonth() == d_firstday.getMonth()) {
 209+
 210+ // print row heder
 211+ s_html +='<tr>';
 212+ for (var n_wday = 0; n_wday < 7; n_wday++) {
 213+
 214+ a_class = [];
 215+ n_date = d_current.getDate();
 216+ n_month = d_current.getMonth();
 217+
 218+ // other month
 219+ if (d_current.getMonth() != d_date.getMonth())
 220+ a_class[a_class.length] = 'othermonth';
 221+ // weekend
 222+ if (d_current.getDay() == 0 || d_current.getDay() == 6)
 223+ a_class[a_class.length] = 'weekend';
 224+ // today
 225+ if (d_current.valueOf() == d_today.valueOf())
 226+ a_class[a_class.length] = 'today';
 227+ // selected
 228+ if (d_current.valueOf() == d_selected.valueOf())
 229+ a_class[a_class.length] = 'selected';
 230+
 231+ s_html += '<td onclick="A_TCALS[\'' + this.s_id + '\'].f_hide(' + d_current.valueOf() + ')"' + (a_class.length ? ' class="' + a_class.join(' ') + '">' : '>') + n_date + '</td>'
 232+
 233+ d_current.setDate(++n_date);
 234+ while (d_current.getDate() != n_date && d_current.getMonth() == n_month) {
 235+ d_current.setHours(d_current.getHours + 1);
 236+ d_current = f_tcalResetTime(d_current);
 237+ }
 238+ }
 239+ // print row footer
 240+ s_html +='</tr>';
 241+ }
 242+ s_html +='</tbody></table>';
 243+
 244+ // update HTML, positions and sizes
 245+ this.e_div.innerHTML = s_html;
 246+
 247+ var n_width = this.e_div.offsetWidth;
 248+ var n_height = this.e_div.offsetHeight;
 249+ var n_top = f_getPosition (this.e_icon, 'Top') + this.e_icon.offsetHeight;
 250+ var n_left = f_getPosition (this.e_icon, 'Left') - n_width + this.e_icon.offsetWidth;
 251+ if (n_left < 0) n_left = 0;
 252+
 253+ this.e_div.style.left = n_left + 'px';
 254+ this.e_div.style.top = n_top + 'px';
 255+
 256+ this.e_shade.style.width = (n_width + 8) + 'px';
 257+ this.e_shade.style.left = (n_left - 1) + 'px';
 258+ this.e_shade.style.top = (n_top - 1) + 'px';
 259+ this.e_shade.innerHTML = b_ieFix
 260+ ? '<table><tbody><tr><td rowspan="2" colspan="2" width="6"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td width="7" height="7" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_tr.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td height="' + (n_height - 7) + '" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_mr.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td width="7" style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_bl.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_bm.png\', sizingMethod=\'scale\');" height="7" align="left"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td style="filter:progid:DXImageTransform.Microsoft.AlphaImageLoader(src=\'' + this.a_tpl.imgpath + 'shade_br.png\', sizingMethod=\'scale\');"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tbody></table>'
 261+ : '<table><tbody><tr><td rowspan="2" width="6"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td rowspan="2"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td width="7" height="7"><img src="' + this.a_tpl.imgpath + 'shade_tr.png"></td></tr><tr><td background="' + this.a_tpl.imgpath + 'shade_mr.png" height="' + (n_height - 7) + '"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td></tr><tr><td><img src="' + this.a_tpl.imgpath + 'shade_bl.png"></td><td background="' + this.a_tpl.imgpath + 'shade_bm.png" height="7" align="left"><img src="' + this.a_tpl.imgpath + 'pixel.gif"></td><td><img src="' + this.a_tpl.imgpath + 'shade_br.png"></td></tr><tbody></table>';
 262+
 263+ if (this.e_iframe) {
 264+ this.e_iframe.style.left = n_left + 'px';
 265+ this.e_iframe.style.top = n_top + 'px';
 266+ this.e_iframe.style.width = (n_width + 6) + 'px';
 267+ this.e_iframe.style.height = (n_height + 6) +'px';
 268+ }
 269+ return true;
 270+}
 271+
 272+function f_getPosition (e_elemRef, s_coord) {
 273+ var n_pos = 0, n_offset,
 274+ e_elem = e_elemRef;
 275+
 276+ while (e_elem) {
 277+ n_offset = e_elem["offset" + s_coord];
 278+ n_pos += n_offset;
 279+ e_elem = e_elem.offsetParent;
 280+ }
 281+ // margin correction in some browsers
 282+ if (b_ieMac)
 283+ n_pos += parseInt(document.body[s_coord.toLowerCase() + 'Margin']);
 284+ else if (b_safari)
 285+ n_pos -= n_offset;
 286+
 287+ e_elem = e_elemRef;
 288+ while (e_elem != document.body) {
 289+ n_offset = e_elem["scroll" + s_coord];
 290+ if (n_offset && e_elem.style.overflow == 'scroll')
 291+ n_pos -= n_offset;
 292+ e_elem = e_elem.parentNode;
 293+ }
 294+ return n_pos;
 295+}
 296+
 297+function f_tcalRelDate (d_date, d_diff, s_units) {
 298+ var s_units = (s_units == 'y' ? 'FullYear' : 'Month');
 299+ var d_result = new Date(d_date);
 300+ d_result['set' + s_units](d_date['get' + s_units]() + d_diff);
 301+ if (d_result.getDate() != d_date.getDate())
 302+ d_result.setDate(0);
 303+ return ' onclick="A_TCALS[\'' + this.s_id + '\'].f_update(' + d_result.valueOf() + ')"';
 304+}
 305+
 306+function f_tcalHideAll () {
 307+ for (var i = 0; i < window.A_TCALSIDX.length; i++)
 308+ window.A_TCALSIDX[i].f_hide();
 309+}
 310+
 311+function f_tcalResetTime (d_date) {
 312+ d_date.setHours(0);
 313+ d_date.setMinutes(0);
 314+ d_date.setSeconds(0);
 315+ d_date.setMilliseconds(0);
 316+ return d_date;
 317+}
 318+
 319+f_getElement = document.all ?
 320+ function (s_id) { return document.all[s_id] } :
 321+ function (s_id) { return document.getElementById(s_id) };
 322+
 323+if (document.addEventListener)
 324+ window.addEventListener('scroll', f_tcalHideAll, false);
 325+if (window.attachEvent)
 326+ window.attachEvent('onscroll', f_tcalHideAll);
 327+
 328+// global variables
 329+var s_userAgent = navigator.userAgent.toLowerCase(),
 330+ re_webkit = /WebKit\/(\d+)/i;
 331+var b_mac = s_userAgent.indexOf('mac') != -1,
 332+ b_ie5 = s_userAgent.indexOf('msie 5') != -1,
 333+ b_ie6 = s_userAgent.indexOf('msie 6') != -1 && s_userAgent.indexOf('opera') == -1;
 334+var b_ieFix = b_ie5 || b_ie6,
 335+ b_ieMac = b_mac && b_ie5,
 336+ b_safari = b_mac && re_webkit.exec(s_userAgent) && Number(RegExp.$1) < 500;
Index: trunk/extensions/SemanticProjectManagement/libs/jscolor/hv.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/jscolor/hv.png
___________________________________________________________________
Added: svn:mime-type
1337 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/jscolor/jscolor.js
@@ -0,0 +1,840 @@
 2+/**
 3+ * jscolor, JavaScript Color Picker
 4+ *
 5+ * @version 1.3.1
 6+ * @license GNU Lesser General Public License, http://www.gnu.org/copyleft/lesser.html
 7+ * @author Jan Odvarko, http://odvarko.cz
 8+ * @created 2008-06-15
 9+ * @updated 2010-01-23
 10+ * @link http://jscolor.com
 11+ */
 12+
 13+
 14+var jscolor = {
 15+
 16+
 17+ dir : '', // location of jscolor directory (leave empty to autodetect)
 18+ bindClass : 'color', // class name
 19+ binding : true, // automatic binding via <input class="...">
 20+ preloading : true, // use image preloading?
 21+
 22+
 23+ install : function() {
 24+ jscolor.addEvent(window, 'load', jscolor.init);
 25+ },
 26+
 27+
 28+ init : function() {
 29+ if(jscolor.binding) {
 30+ jscolor.bind();
 31+ }
 32+ if(jscolor.preloading) {
 33+ jscolor.preload();
 34+ }
 35+ },
 36+
 37+
 38+ getDir : function() {
 39+ if(!jscolor.dir) {
 40+ var detected = jscolor.detectDir();
 41+ jscolor.dir = detected!==false ? detected : 'jscolor/';
 42+ }
 43+ return jscolor.dir;
 44+ },
 45+
 46+
 47+ detectDir : function() {
 48+ var base = location.href;
 49+
 50+ var e = document.getElementsByTagName('base');
 51+ for(var i=0; i<e.length; i+=1) {
 52+ if(e[i].href) { base = e[i].href; }
 53+ }
 54+
 55+ var e = document.getElementsByTagName('script');
 56+ for(var i=0; i<e.length; i+=1) {
 57+ if(e[i].src && /(^|\/)jscolor\.js([?#].*)?$/i.test(e[i].src)) {
 58+ var src = new jscolor.URI(e[i].src);
 59+ var srcAbs = src.toAbsolute(base);
 60+ srcAbs.path = srcAbs.path.replace(/[^\/]+$/, ''); // remove filename
 61+ srcAbs.query = null;
 62+ srcAbs.fragment = null;
 63+ return srcAbs.toString();
 64+ }
 65+ }
 66+ return false;
 67+ },
 68+
 69+
 70+ bind : function() {
 71+ var matchClass = new RegExp('(^|\\s)('+jscolor.bindClass+')\\s*(\\{[^}]*\\})?', 'i');
 72+ var e = document.getElementsByTagName('input');
 73+ for(var i=0; i<e.length; i+=1) {
 74+ var m;
 75+ if(!e[i].color && e[i].className && (m = e[i].className.match(matchClass))) {
 76+ var prop = {};
 77+ if(m[3]) {
 78+ try {
 79+ eval('prop='+m[3]);
 80+ } catch(eInvalidProp) {}
 81+ }
 82+ e[i].color = new jscolor.color(e[i], prop);
 83+ }
 84+ }
 85+ },
 86+
 87+
 88+ preload : function() {
 89+ for(var fn in jscolor.imgRequire) {
 90+ if(jscolor.imgRequire.hasOwnProperty(fn)) {
 91+ jscolor.loadImage(fn);
 92+ }
 93+ }
 94+ },
 95+
 96+
 97+ images : {
 98+ pad : [ 181, 101 ],
 99+ sld : [ 16, 101 ],
 100+ cross : [ 15, 15 ],
 101+ arrow : [ 7, 11 ]
 102+ },
 103+
 104+
 105+ imgRequire : {},
 106+ imgLoaded : {},
 107+
 108+
 109+ requireImage : function(filename) {
 110+ jscolor.imgRequire[filename] = true;
 111+ },
 112+
 113+
 114+ loadImage : function(filename) {
 115+ if(!jscolor.imgLoaded[filename]) {
 116+ jscolor.imgLoaded[filename] = new Image();
 117+ jscolor.imgLoaded[filename].src = jscolor.getDir()+filename;
 118+ }
 119+ },
 120+
 121+
 122+ fetchElement : function(mixed) {
 123+ return typeof mixed === 'string' ? document.getElementById(mixed) : mixed;
 124+ },
 125+
 126+
 127+ addEvent : function(el, evnt, func) {
 128+ if(el.addEventListener) {
 129+ el.addEventListener(evnt, func, false);
 130+ } else if(el.attachEvent) {
 131+ el.attachEvent('on'+evnt, func);
 132+ }
 133+ },
 134+
 135+
 136+ fireEvent : function(el, evnt) {
 137+ if(!el) {
 138+ return;
 139+ }
 140+ if(document.createEventObject) {
 141+ var ev = document.createEventObject();
 142+ el.fireEvent('on'+evnt, ev);
 143+ } else if(document.createEvent) {
 144+ var ev = document.createEvent('HTMLEvents');
 145+ ev.initEvent(evnt, true, true);
 146+ el.dispatchEvent(ev);
 147+ } else if(el['on'+evnt]) { // alternatively use the traditional event model (IE5)
 148+ el['on'+evnt]();
 149+ }
 150+ },
 151+
 152+
 153+ getElementPos : function(e) {
 154+ var e1=e, e2=e;
 155+ var x=0, y=0;
 156+ if(e1.offsetParent) {
 157+ do {
 158+ x += e1.offsetLeft;
 159+ y += e1.offsetTop;
 160+ } while(e1 = e1.offsetParent);
 161+ }
 162+ while((e2 = e2.parentNode) && e2.nodeName.toUpperCase() !== 'BODY') {
 163+ x -= e2.scrollLeft;
 164+ y -= e2.scrollTop;
 165+ }
 166+ return [x, y];
 167+ },
 168+
 169+
 170+ getElementSize : function(e) {
 171+ return [e.offsetWidth, e.offsetHeight];
 172+ },
 173+
 174+
 175+ getMousePos : function(e) {
 176+ if(!e) { e = window.event; }
 177+ if(typeof e.pageX === 'number') {
 178+ return [e.pageX, e.pageY];
 179+ } else if(typeof e.clientX === 'number') {
 180+ return [
 181+ e.clientX + document.body.scrollLeft + document.documentElement.scrollLeft,
 182+ e.clientY + document.body.scrollTop + document.documentElement.scrollTop
 183+ ];
 184+ }
 185+ },
 186+
 187+
 188+ getViewPos : function() {
 189+ if(typeof window.pageYOffset === 'number') {
 190+ return [window.pageXOffset, window.pageYOffset];
 191+ } else if(document.body && (document.body.scrollLeft || document.body.scrollTop)) {
 192+ return [document.body.scrollLeft, document.body.scrollTop];
 193+ } else if(document.documentElement && (document.documentElement.scrollLeft || document.documentElement.scrollTop)) {
 194+ return [document.documentElement.scrollLeft, document.documentElement.scrollTop];
 195+ } else {
 196+ return [0, 0];
 197+ }
 198+ },
 199+
 200+
 201+ getViewSize : function() {
 202+ if(typeof window.innerWidth === 'number') {
 203+ return [window.innerWidth, window.innerHeight];
 204+ } else if(document.body && (document.body.clientWidth || document.body.clientHeight)) {
 205+ return [document.body.clientWidth, document.body.clientHeight];
 206+ } else if(document.documentElement && (document.documentElement.clientWidth || document.documentElement.clientHeight)) {
 207+ return [document.documentElement.clientWidth, document.documentElement.clientHeight];
 208+ } else {
 209+ return [0, 0];
 210+ }
 211+ },
 212+
 213+
 214+ URI : function(uri) { // See RFC3986
 215+
 216+ this.scheme = null;
 217+ this.authority = null;
 218+ this.path = '';
 219+ this.query = null;
 220+ this.fragment = null;
 221+
 222+ this.parse = function(uri) {
 223+ var m = uri.match(/^(([A-Za-z][0-9A-Za-z+.-]*)(:))?((\/\/)([^\/?#]*))?([^?#]*)((\?)([^#]*))?((#)(.*))?/);
 224+ this.scheme = m[3] ? m[2] : null;
 225+ this.authority = m[5] ? m[6] : null;
 226+ this.path = m[7];
 227+ this.query = m[9] ? m[10] : null;
 228+ this.fragment = m[12] ? m[13] : null;
 229+ return this;
 230+ };
 231+
 232+ this.toString = function() {
 233+ var result = '';
 234+ if(this.scheme !== null) { result = result + this.scheme + ':'; }
 235+ if(this.authority !== null) { result = result + '//' + this.authority; }
 236+ if(this.path !== null) { result = result + this.path; }
 237+ if(this.query !== null) { result = result + '?' + this.query; }
 238+ if(this.fragment !== null) { result = result + '#' + this.fragment; }
 239+ return result;
 240+ };
 241+
 242+ this.toAbsolute = function(base) {
 243+ var base = new jscolor.URI(base);
 244+ var r = this;
 245+ var t = new jscolor.URI;
 246+
 247+ if(base.scheme === null) { return false; }
 248+
 249+ if(r.scheme !== null && r.scheme.toLowerCase() === base.scheme.toLowerCase()) {
 250+ r.scheme = null;
 251+ }
 252+
 253+ if(r.scheme !== null) {
 254+ t.scheme = r.scheme;
 255+ t.authority = r.authority;
 256+ t.path = removeDotSegments(r.path);
 257+ t.query = r.query;
 258+ } else {
 259+ if(r.authority !== null) {
 260+ t.authority = r.authority;
 261+ t.path = removeDotSegments(r.path);
 262+ t.query = r.query;
 263+ } else {
 264+ if(r.path === '') { // TODO: == or === ?
 265+ t.path = base.path;
 266+ if(r.query !== null) {
 267+ t.query = r.query;
 268+ } else {
 269+ t.query = base.query;
 270+ }
 271+ } else {
 272+ if(r.path.substr(0,1) === '/') {
 273+ t.path = removeDotSegments(r.path);
 274+ } else {
 275+ if(base.authority !== null && base.path === '') { // TODO: == or === ?
 276+ t.path = '/'+r.path;
 277+ } else {
 278+ t.path = base.path.replace(/[^\/]+$/,'')+r.path;
 279+ }
 280+ t.path = removeDotSegments(t.path);
 281+ }
 282+ t.query = r.query;
 283+ }
 284+ t.authority = base.authority;
 285+ }
 286+ t.scheme = base.scheme;
 287+ }
 288+ t.fragment = r.fragment;
 289+
 290+ return t;
 291+ };
 292+
 293+ function removeDotSegments(path) {
 294+ var out = '';
 295+ while(path) {
 296+ if(path.substr(0,3)==='../' || path.substr(0,2)==='./') {
 297+ path = path.replace(/^\.+/,'').substr(1);
 298+ } else if(path.substr(0,3)==='/./' || path==='/.') {
 299+ path = '/'+path.substr(3);
 300+ } else if(path.substr(0,4)==='/../' || path==='/..') {
 301+ path = '/'+path.substr(4);
 302+ out = out.replace(/\/?[^\/]*$/, '');
 303+ } else if(path==='.' || path==='..') {
 304+ path = '';
 305+ } else {
 306+ var rm = path.match(/^\/?[^\/]*/)[0];
 307+ path = path.substr(rm.length);
 308+ out = out + rm;
 309+ }
 310+ }
 311+ return out;
 312+ }
 313+
 314+ if(uri) {
 315+ this.parse(uri);
 316+ }
 317+
 318+ },
 319+
 320+
 321+ /*
 322+ * Usage example:
 323+ * var myColor = new jscolor.color(myInputElement)
 324+ */
 325+
 326+ color : function(target, prop) {
 327+
 328+
 329+ this.required = true; // refuse empty values?
 330+ this.adjust = true; // adjust value to uniform notation?
 331+ this.hash = false; // prefix color with # symbol?
 332+ this.caps = true; // uppercase?
 333+ this.valueElement = target; // value holder
 334+ this.styleElement = target; // where to reflect current color
 335+ this.hsv = [0, 0, 1]; // read-only 0-6, 0-1, 0-1
 336+ this.rgb = [1, 1, 1]; // read-only 0-1, 0-1, 0-1
 337+
 338+ this.pickerOnfocus = true; // display picker on focus?
 339+ this.pickerMode = 'HSV'; // HSV | HVS
 340+ this.pickerPosition = 'bottom'; // left | right | top | bottom
 341+ this.pickerFace = 10; // px
 342+ this.pickerFaceColor = 'ThreeDFace'; // CSS color
 343+ this.pickerBorder = 1; // px
 344+ this.pickerBorderColor = 'ThreeDHighlight ThreeDShadow ThreeDShadow ThreeDHighlight'; // CSS color
 345+ this.pickerInset = 1; // px
 346+ this.pickerInsetColor = 'ThreeDShadow ThreeDHighlight ThreeDHighlight ThreeDShadow'; // CSS color
 347+ this.pickerZIndex = 10000;
 348+
 349+
 350+ for(var p in prop) {
 351+ if(prop.hasOwnProperty(p)) {
 352+ this[p] = prop[p];
 353+ }
 354+ }
 355+
 356+
 357+ this.hidePicker = function() {
 358+ if(isPickerOwner()) {
 359+ removePicker();
 360+ }
 361+ };
 362+
 363+
 364+ this.showPicker = function() {
 365+ if(!isPickerOwner()) {
 366+ var tp = jscolor.getElementPos(target); // target pos
 367+ var ts = jscolor.getElementSize(target); // target size
 368+ var vp = jscolor.getViewPos(); // view pos
 369+ var vs = jscolor.getViewSize(); // view size
 370+ var ps = [ // picker size
 371+ 2*this.pickerBorder + 4*this.pickerInset + 2*this.pickerFace + jscolor.images.pad[0] + 2*jscolor.images.arrow[0] + jscolor.images.sld[0],
 372+ 2*this.pickerBorder + 2*this.pickerInset + 2*this.pickerFace + jscolor.images.pad[1]
 373+ ];
 374+ var a, b, c;
 375+ switch(this.pickerPosition.toLowerCase()) {
 376+ case 'left': a=1; b=0; c=-1; break;
 377+ case 'right':a=1; b=0; c=1; break;
 378+ case 'top': a=0; b=1; c=-1; break;
 379+ default: a=0; b=1; c=1; break;
 380+ }
 381+ var l = (ts[b]+ps[b])/2;
 382+ var pp = [ // picker pos
 383+ -vp[a]+tp[a]+ps[a] > vs[a] ?
 384+ (-vp[a]+tp[a]+ts[a]/2 > vs[a]/2 && tp[a]+ts[a]-ps[a] >= 0 ? tp[a]+ts[a]-ps[a] : tp[a]) :
 385+ tp[a],
 386+ -vp[b]+tp[b]+ts[b]+ps[b]-l+l*c > vs[b] ?
 387+ (-vp[b]+tp[b]+ts[b]/2 > vs[b]/2 && tp[b]+ts[b]-l-l*c >= 0 ? tp[b]+ts[b]-l-l*c : tp[b]+ts[b]-l+l*c) :
 388+ (tp[b]+ts[b]-l+l*c >= 0 ? tp[b]+ts[b]-l+l*c : tp[b]+ts[b]-l-l*c)
 389+ ];
 390+ drawPicker(pp[a], pp[b]);
 391+ }
 392+ };
 393+
 394+
 395+ this.importColor = function() {
 396+ if(!valueElement) {
 397+ this.exportColor();
 398+ } else {
 399+ if(!this.adjust) {
 400+ if(!this.fromString(valueElement.value, leaveValue)) {
 401+ styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
 402+ styleElement.style.color = styleElement.jscStyle.color;
 403+ this.exportColor(leaveValue | leaveStyle);
 404+ }
 405+ } else if(!this.required && /^\s*$/.test(valueElement.value)) {
 406+ valueElement.value = '';
 407+ styleElement.style.backgroundColor = styleElement.jscStyle.backgroundColor;
 408+ styleElement.style.color = styleElement.jscStyle.color;
 409+ this.exportColor(leaveValue | leaveStyle);
 410+
 411+ } else if(this.fromString(valueElement.value)) {
 412+ // OK
 413+ } else {
 414+ this.exportColor();
 415+ }
 416+ }
 417+ };
 418+
 419+
 420+ this.exportColor = function(flags) {
 421+ if(!(flags & leaveValue) && valueElement) {
 422+ var value = this.toString();
 423+ if(this.caps) { value = value.toUpperCase(); }
 424+ if(this.hash) { value = '#'+value; }
 425+ valueElement.value = value;
 426+ }
 427+ if(!(flags & leaveStyle) && styleElement) {
 428+ styleElement.style.backgroundColor =
 429+ '#'+this.toString();
 430+ styleElement.style.color =
 431+ 0.213 * this.rgb[0] +
 432+ 0.715 * this.rgb[1] +
 433+ 0.072 * this.rgb[2]
 434+ < 0.5 ? '#FFF' : '#000';
 435+ }
 436+ if(!(flags & leavePad) && isPickerOwner()) {
 437+ redrawPad();
 438+ }
 439+ if(!(flags & leaveSld) && isPickerOwner()) {
 440+ redrawSld();
 441+ }
 442+ };
 443+
 444+
 445+ this.fromHSV = function(h, s, v, flags) { // null = don't change
 446+ h<0 && (h=0) || h>6 && (h=6);
 447+ s<0 && (s=0) || s>1 && (s=1);
 448+ v<0 && (v=0) || v>1 && (v=1);
 449+ this.rgb = HSV_RGB(
 450+ h===null ? this.hsv[0] : (this.hsv[0]=h),
 451+ s===null ? this.hsv[1] : (this.hsv[1]=s),
 452+ v===null ? this.hsv[2] : (this.hsv[2]=v)
 453+ );
 454+ this.exportColor(flags);
 455+ };
 456+
 457+
 458+ this.fromRGB = function(r, g, b, flags) { // null = don't change
 459+ r<0 && (r=0) || r>1 && (r=1);
 460+ g<0 && (g=0) || g>1 && (g=1);
 461+ b<0 && (b=0) || b>1 && (b=1);
 462+ var hsv = RGB_HSV(
 463+ r===null ? this.rgb[0] : (this.rgb[0]=r),
 464+ g===null ? this.rgb[1] : (this.rgb[1]=g),
 465+ b===null ? this.rgb[2] : (this.rgb[2]=b)
 466+ );
 467+ if(hsv[0] !== null) {
 468+ this.hsv[0] = hsv[0];
 469+ }
 470+ if(hsv[2] !== 0) {
 471+ this.hsv[1] = hsv[1];
 472+ }
 473+ this.hsv[2] = hsv[2];
 474+ this.exportColor(flags);
 475+ };
 476+
 477+
 478+ this.fromString = function(hex, flags) {
 479+ var m = hex.match(/^\W*([0-9A-F]{3}([0-9A-F]{3})?)\W*$/i);
 480+ if(!m) {
 481+ return false;
 482+ } else {
 483+ if(m[1].length === 6) { // 6-char notation
 484+ this.fromRGB(
 485+ parseInt(m[1].substr(0,2),16) / 255,
 486+ parseInt(m[1].substr(2,2),16) / 255,
 487+ parseInt(m[1].substr(4,2),16) / 255,
 488+ flags
 489+ );
 490+ } else { // 3-char notation
 491+ this.fromRGB(
 492+ parseInt(m[1].charAt(0)+m[1].charAt(0),16) / 255,
 493+ parseInt(m[1].charAt(1)+m[1].charAt(1),16) / 255,
 494+ parseInt(m[1].charAt(2)+m[1].charAt(2),16) / 255,
 495+ flags
 496+ );
 497+ }
 498+ return true;
 499+ }
 500+ };
 501+
 502+
 503+ this.toString = function() {
 504+ return (
 505+ (0x100 | Math.round(255*this.rgb[0])).toString(16).substr(1) +
 506+ (0x100 | Math.round(255*this.rgb[1])).toString(16).substr(1) +
 507+ (0x100 | Math.round(255*this.rgb[2])).toString(16).substr(1)
 508+ );
 509+ };
 510+
 511+
 512+ function RGB_HSV(r, g, b) {
 513+ var n = Math.min(Math.min(r,g),b);
 514+ var v = Math.max(Math.max(r,g),b);
 515+ var m = v - n;
 516+ if(m === 0) { return [ null, 0, v ]; }
 517+ var h = r===n ? 3+(b-g)/m : (g===n ? 5+(r-b)/m : 1+(g-r)/m);
 518+ return [ h===6?0:h, m/v, v ];
 519+ }
 520+
 521+
 522+ function HSV_RGB(h, s, v) {
 523+ if(h === null) { return [ v, v, v ]; }
 524+ var i = Math.floor(h);
 525+ var f = i%2 ? h-i : 1-(h-i);
 526+ var m = v * (1 - s);
 527+ var n = v * (1 - s*f);
 528+ switch(i) {
 529+ case 6:
 530+ case 0: return [v,n,m];
 531+ case 1: return [n,v,m];
 532+ case 2: return [m,v,n];
 533+ case 3: return [m,n,v];
 534+ case 4: return [n,m,v];
 535+ case 5: return [v,m,n];
 536+ }
 537+ }
 538+
 539+
 540+ function removePicker() {
 541+ delete jscolor.picker.owner;
 542+ document.getElementsByTagName('body')[0].removeChild(jscolor.picker.boxB);
 543+ }
 544+
 545+
 546+ function drawPicker(x, y) {
 547+ if(!jscolor.picker) {
 548+ jscolor.picker = {
 549+ box : document.createElement('div'),
 550+ boxB : document.createElement('div'),
 551+ pad : document.createElement('div'),
 552+ padB : document.createElement('div'),
 553+ padM : document.createElement('div'),
 554+ sld : document.createElement('div'),
 555+ sldB : document.createElement('div'),
 556+ sldM : document.createElement('div')
 557+ };
 558+ for(var i=0,segSize=4; i<jscolor.images.sld[1]; i+=segSize) {
 559+ var seg = document.createElement('div');
 560+ seg.style.height = segSize+'px';
 561+ seg.style.fontSize = '1px';
 562+ seg.style.lineHeight = '0';
 563+ jscolor.picker.sld.appendChild(seg);
 564+ }
 565+ jscolor.picker.sldB.appendChild(jscolor.picker.sld);
 566+ jscolor.picker.box.appendChild(jscolor.picker.sldB);
 567+ jscolor.picker.box.appendChild(jscolor.picker.sldM);
 568+ jscolor.picker.padB.appendChild(jscolor.picker.pad);
 569+ jscolor.picker.box.appendChild(jscolor.picker.padB);
 570+ jscolor.picker.box.appendChild(jscolor.picker.padM);
 571+ jscolor.picker.boxB.appendChild(jscolor.picker.box);
 572+ }
 573+
 574+ var p = jscolor.picker;
 575+
 576+ // recompute controls positions
 577+ posPad = [
 578+ x+THIS.pickerBorder+THIS.pickerFace+THIS.pickerInset,
 579+ y+THIS.pickerBorder+THIS.pickerFace+THIS.pickerInset ];
 580+ posSld = [
 581+ null,
 582+ y+THIS.pickerBorder+THIS.pickerFace+THIS.pickerInset ];
 583+
 584+ // controls interaction
 585+ p.box.onmouseup =
 586+ p.box.onmouseout = function() { target.focus(); };
 587+ p.box.onmousedown = function() { abortBlur=true; };
 588+ p.box.onmousemove = function(e) { holdPad && setPad(e); holdSld && setSld(e); };
 589+ p.padM.onmouseup =
 590+ p.padM.onmouseout = function() { if(holdPad) { holdPad=false; jscolor.fireEvent(valueElement,'change'); } };
 591+ p.padM.onmousedown = function(e) { holdPad=true; setPad(e); };
 592+ p.sldM.onmouseup =
 593+ p.sldM.onmouseout = function() { if(holdSld) { holdSld=false; jscolor.fireEvent(valueElement,'change'); } };
 594+ p.sldM.onmousedown = function(e) { holdSld=true; setSld(e); };
 595+
 596+ // picker
 597+ p.box.style.width = 4*THIS.pickerInset + 2*THIS.pickerFace + jscolor.images.pad[0] + 2*jscolor.images.arrow[0] + jscolor.images.sld[0] + 'px';
 598+ p.box.style.height = 2*THIS.pickerInset + 2*THIS.pickerFace + jscolor.images.pad[1] + 'px';
 599+
 600+ // picker border
 601+ p.boxB.style.position = 'absolute';
 602+ p.boxB.style.clear = 'both';
 603+ p.boxB.style.left = x+'px';
 604+ p.boxB.style.top = y+'px';
 605+ p.boxB.style.zIndex = THIS.pickerZIndex;
 606+ p.boxB.style.border = THIS.pickerBorder+'px solid';
 607+ p.boxB.style.borderColor = THIS.pickerBorderColor;
 608+ p.boxB.style.background = THIS.pickerFaceColor;
 609+
 610+ // pad image
 611+ p.pad.style.width = jscolor.images.pad[0]+'px';
 612+ p.pad.style.height = jscolor.images.pad[1]+'px';
 613+
 614+ // pad border
 615+ p.padB.style.position = 'absolute';
 616+ p.padB.style.left = THIS.pickerFace+'px';
 617+ p.padB.style.top = THIS.pickerFace+'px';
 618+ p.padB.style.border = THIS.pickerInset+'px solid';
 619+ p.padB.style.borderColor = THIS.pickerInsetColor;
 620+
 621+ // pad mouse area
 622+ p.padM.style.position = 'absolute';
 623+ p.padM.style.left = '0';
 624+ p.padM.style.top = '0';
 625+ p.padM.style.width = THIS.pickerFace + 2*THIS.pickerInset + jscolor.images.pad[0] + jscolor.images.arrow[0] + 'px';
 626+ p.padM.style.height = p.box.style.height;
 627+ p.padM.style.cursor = 'crosshair';
 628+
 629+ // slider image
 630+ p.sld.style.overflow = 'hidden';
 631+ p.sld.style.width = jscolor.images.sld[0]+'px';
 632+ p.sld.style.height = jscolor.images.sld[1]+'px';
 633+
 634+ // slider border
 635+ p.sldB.style.position = 'absolute';
 636+ p.sldB.style.right = THIS.pickerFace+'px';
 637+ p.sldB.style.top = THIS.pickerFace+'px';
 638+ p.sldB.style.border = THIS.pickerInset+'px solid';
 639+ p.sldB.style.borderColor = THIS.pickerInsetColor;
 640+
 641+ // slider mouse area
 642+ p.sldM.style.position = 'absolute';
 643+ p.sldM.style.right = '0';
 644+ p.sldM.style.top = '0';
 645+ p.sldM.style.width = jscolor.images.sld[0] + jscolor.images.arrow[0] + THIS.pickerFace + 2*THIS.pickerInset + 'px';
 646+ p.sldM.style.height = p.box.style.height;
 647+ try {
 648+ p.sldM.style.cursor = 'pointer';
 649+ } catch(eOldIE) {
 650+ p.sldM.style.cursor = 'hand';
 651+ }
 652+
 653+ // load images in optimal order
 654+ switch(modeID) {
 655+ case 0: var padImg = 'hs.png'; break;
 656+ case 1: var padImg = 'hv.png'; break;
 657+ }
 658+ p.padM.style.background = "url('"+jscolor.getDir()+"cross.gif') no-repeat";
 659+ p.sldM.style.background = "url('"+jscolor.getDir()+"arrow.gif') no-repeat";
 660+ p.pad.style.background = "url('"+jscolor.getDir()+padImg+"') 0 0 no-repeat";
 661+
 662+ // place pointers
 663+ redrawPad();
 664+ redrawSld();
 665+
 666+ jscolor.picker.owner = THIS;
 667+ document.getElementsByTagName('body')[0].appendChild(p.boxB);
 668+ }
 669+
 670+
 671+ function redrawPad() {
 672+ // redraw the pad pointer
 673+ switch(modeID) {
 674+ case 0: var yComponent = 1; break;
 675+ case 1: var yComponent = 2; break;
 676+ }
 677+ var x = Math.round((THIS.hsv[0]/6) * (jscolor.images.pad[0]-1));
 678+ var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.pad[1]-1));
 679+ jscolor.picker.padM.style.backgroundPosition =
 680+ (THIS.pickerFace+THIS.pickerInset+x - Math.floor(jscolor.images.cross[0]/2)) + 'px ' +
 681+ (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.cross[1]/2)) + 'px';
 682+
 683+ // redraw the slider image
 684+ var seg = jscolor.picker.sld.childNodes;
 685+
 686+ switch(modeID) {
 687+ case 0:
 688+ var rgb = HSV_RGB(THIS.hsv[0], THIS.hsv[1], 1);
 689+ for(var i=0; i<seg.length; i+=1) {
 690+ seg[i].style.backgroundColor = 'rgb('+
 691+ (rgb[0]*(1-i/seg.length)*100)+'%,'+
 692+ (rgb[1]*(1-i/seg.length)*100)+'%,'+
 693+ (rgb[2]*(1-i/seg.length)*100)+'%)';
 694+ }
 695+ break;
 696+ case 1:
 697+ var rgb, s, c = [ THIS.hsv[2], 0, 0 ];
 698+ var i = Math.floor(THIS.hsv[0]);
 699+ var f = i%2 ? THIS.hsv[0]-i : 1-(THIS.hsv[0]-i);
 700+ switch(i) {
 701+ case 6:
 702+ case 0: rgb=[0,1,2]; break;
 703+ case 1: rgb=[1,0,2]; break;
 704+ case 2: rgb=[2,0,1]; break;
 705+ case 3: rgb=[2,1,0]; break;
 706+ case 4: rgb=[1,2,0]; break;
 707+ case 5: rgb=[0,2,1]; break;
 708+ }
 709+ for(var i=0; i<seg.length; i+=1) {
 710+ s = 1 - 1/(seg.length-1)*i;
 711+ c[1] = c[0] * (1 - s*f);
 712+ c[2] = c[0] * (1 - s);
 713+ seg[i].style.backgroundColor = 'rgb('+
 714+ (c[rgb[0]]*100)+'%,'+
 715+ (c[rgb[1]]*100)+'%,'+
 716+ (c[rgb[2]]*100)+'%)';
 717+ }
 718+ break;
 719+ }
 720+ }
 721+
 722+
 723+ function redrawSld() {
 724+ // redraw the slider pointer
 725+ switch(modeID) {
 726+ case 0: var yComponent = 2; break;
 727+ case 1: var yComponent = 1; break;
 728+ }
 729+ var y = Math.round((1-THIS.hsv[yComponent]) * (jscolor.images.sld[1]-1));
 730+ jscolor.picker.sldM.style.backgroundPosition =
 731+ '0 ' + (THIS.pickerFace+THIS.pickerInset+y - Math.floor(jscolor.images.arrow[1]/2)) + 'px';
 732+ }
 733+
 734+
 735+ function isPickerOwner() {
 736+ return jscolor.picker && jscolor.picker.owner === THIS;
 737+ }
 738+
 739+
 740+ function blurTarget() {
 741+ if(valueElement === target) {
 742+ THIS.importColor();
 743+ }
 744+ if(THIS.pickerOnfocus) {
 745+ THIS.hidePicker();
 746+ }
 747+ }
 748+
 749+
 750+ function blurValue() {
 751+ if(valueElement !== target) {
 752+ THIS.importColor();
 753+ }
 754+ }
 755+
 756+
 757+ function setPad(e) {
 758+ var posM = jscolor.getMousePos(e);
 759+ var x = posM[0]-posPad[0];
 760+ var y = posM[1]-posPad[1];
 761+ switch(modeID) {
 762+ case 0: THIS.fromHSV(x*(6/(jscolor.images.pad[0]-1)), 1 - y/(jscolor.images.pad[1]-1), null, leaveSld); break;
 763+ case 1: THIS.fromHSV(x*(6/(jscolor.images.pad[0]-1)), null, 1 - y/(jscolor.images.pad[1]-1), leaveSld); break;
 764+ }
 765+ }
 766+
 767+
 768+ function setSld(e) {
 769+ var posM = jscolor.getMousePos(e);
 770+ var y = posM[1]-posPad[1];
 771+ switch(modeID) {
 772+ case 0: THIS.fromHSV(null, null, 1 - y/(jscolor.images.sld[1]-1), leavePad); break;
 773+ case 1: THIS.fromHSV(null, 1 - y/(jscolor.images.sld[1]-1), null, leavePad); break;
 774+ }
 775+ }
 776+
 777+
 778+ var THIS = this;
 779+ var modeID = this.pickerMode.toLowerCase()==='hvs' ? 1 : 0;
 780+ var abortBlur = false;
 781+ var
 782+ valueElement = jscolor.fetchElement(this.valueElement),
 783+ styleElement = jscolor.fetchElement(this.styleElement);
 784+ var
 785+ holdPad = false,
 786+ holdSld = false;
 787+ var
 788+ posPad,
 789+ posSld;
 790+ var
 791+ leaveValue = 1<<0,
 792+ leaveStyle = 1<<1,
 793+ leavePad = 1<<2,
 794+ leaveSld = 1<<3;
 795+
 796+ // target
 797+ jscolor.addEvent(target, 'focus', function() {
 798+ if(THIS.pickerOnfocus) { THIS.showPicker(); }
 799+ });
 800+ jscolor.addEvent(target, 'blur', function() {
 801+ if(!abortBlur) {
 802+ window.setTimeout(function(){ abortBlur || blurTarget(); abortBlur=false; }, 0);
 803+ } else {
 804+ abortBlur = false;
 805+ }
 806+ });
 807+
 808+ // valueElement
 809+ if(valueElement) {
 810+ var updateField = function() {
 811+ THIS.fromString(valueElement.value, leaveValue);
 812+ };
 813+ jscolor.addEvent(valueElement, 'keyup', updateField);
 814+ jscolor.addEvent(valueElement, 'input', updateField);
 815+ jscolor.addEvent(valueElement, 'blur', blurValue);
 816+ valueElement.setAttribute('autocomplete', 'off');
 817+ }
 818+
 819+ // styleElement
 820+ if(styleElement) {
 821+ styleElement.jscStyle = {
 822+ backgroundColor : styleElement.style.backgroundColor,
 823+ color : styleElement.style.color
 824+ };
 825+ }
 826+
 827+ // require images
 828+ switch(modeID) {
 829+ case 0: jscolor.requireImage('hs.png'); break;
 830+ case 1: jscolor.requireImage('hv.png'); break;
 831+ }
 832+ jscolor.requireImage('cross.gif');
 833+ jscolor.requireImage('arrow.gif');
 834+
 835+ this.importColor();
 836+ }
 837+
 838+};
 839+
 840+
 841+jscolor.install();
Index: trunk/extensions/SemanticProjectManagement/libs/jscolor/cross.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/jscolor/cross.gif
___________________________________________________________________
Added: svn:mime-type
1842 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/jscolor/hs.png
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/jscolor/hs.png
___________________________________________________________________
Added: svn:mime-type
2843 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/libs/jscolor/arrow.gif
Cannot display: file marked as a binary type.
svn:mime-type = application/octet-stream
Property changes on: trunk/extensions/SemanticProjectManagement/libs/jscolor/arrow.gif
___________________________________________________________________
Added: svn:mime-type
3844 + application/octet-stream
Index: trunk/extensions/SemanticProjectManagement/README
@@ -0,0 +1,38 @@
 2+= Semantic Project Management =
 3+
 4+Semantic Project Management is an extension to MediaWiki that offers two new
 5+result formats for Semantic MediaWiki's inline queries.
 6+
 7+The functionality provided by Semantic Project Management are:
 8+* Rendering of project structures by displaying them as Gantt charts.
 9+* Export of project structures as XML-files
 10+
 11+
 12+For more information, see the SRF homepage at:
 13+http://www.mediawiki.org/wiki/Extension:Semantic_Project_Management
 14+
 15+== Included formats ==
 16+
 17+=== ganttchart ===
 18+
 19+Displays project management tasks in a Gantt chart embedded in the wiki page.
 20+
 21+=== wbs ===
 22+
 23+Enables exports of project management tasks using the MS-Project XML Schema
 24+format. Using this format creates an according download link in the wiki.
 25+
 26+== Contact ==
 27+
 28+If you have remarks, questions, or suggestions, please send them to
 29+dengler (at) kit.edu.
 30+
 31+
 32+== Developers ==
 33+
 34+Development is coordinated by Frank Dengler and Jonas Bissinger.
 35+If you are interested in taking over coordination, please contact Frank.
 36+
 37+
 38+The development tasks have also been supported by the European Union
 39+under the project Active.
\ No newline at end of file
Index: trunk/extensions/SemanticProjectManagement/SemanticProjectManagement.php
@@ -0,0 +1,114 @@
 2+<?php
 3+/*******************************************************************************
 4+ *
 5+ * Copyright (c) 2010 Frank Dengler, Jonas Bissinger
 6+ *
 7+ * Semantic Project Management is free software: you can redistribute it and/or modify
 8+ * it under the terms of the GNU General Public License as published by
 9+ * the Free Software Foundation, either version 3 of the License, or
 10+ * (at your option) any later version.
 11+ *
 12+ * Semantic Project Management is distributed in the hope that it will be useful,
 13+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
 14+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
 15+ * GNU General Public License for more details.
 16+ *
 17+ * You should have received a copy of the GNU General Public License
 18+ * along with Semantic Project Management. If not, see <http://www.gnu.org/licenses/>.
 19+ *******************************************************************************/
 20+
 21+if( !defined( 'MEDIAWIKI' ) ) {
 22+ die( 'Not an entry point.' );
 23+}
 24+
 25+/**
 26+ *
 27+ * @author Frank Dengler, Jonas Bissinger
 28+ *
 29+ * @ingroup SemanticProjectManagement
 30+ *
 31+ */
 32+if ( !defined( 'MEDIAWIKI' ) ) {
 33+ die( 'Not an entry point.' );
 34+}
 35+
 36+define( 'SPM_VERSION', '0.3' );
 37+
 38+$spmgScriptPath = $wgScriptPath . '/extensions/SemanticProjectManagement';
 39+$spmgIP = $IP . '/extensions/SemanticProjectManagement';
 40+
 41+$wgExtensionFunctions[] = 'spmfSetup';
 42+
 43+require_once( $spmgIP . '/includes/SPM_ProjectManagementClass.php' );
 44+
 45+//set permission to change SPMsetup
 46+$wgGroupPermissions['sysop']['SPMsetup'] = true;
 47+$wgAvailableRights[] = 'SPMsetup';
 48+
 49+//define semanticprojectmanagement special page
 50+
 51+$wgAutoloadClasses['SemanticProjectManagement'] = $spmgIP. '/includes/SPM_SpecialPage.php';
 52+$wgExtensionMessagesFiles['SemanticProjectManagement'] = $spmgIP . '/includes/SPM_Messages.php';
 53+$wgExtensionAliasesFiles['SemanticProjectManagement'] = $spmgIP . '/includes/SPM_Alias.php';
 54+$wgSpecialPages['SemanticProjectManagement'] = 'SemanticProjectManagement';
 55+
 56+// FIXME: Can be removed when new style magic words are used (introduced in r52503)
 57+
 58+$wgHooks['AdminLinks'][] = 'spmfAddToAdminLinks';
 59+
 60+$spmgFormats = array( 'ganttchart','wbs');
 61+
 62+function spmfSetup() {
 63+ global $spmgFormats, $wgExtensionCredits, $wgOut;
 64+
 65+ foreach ( $spmgFormats as $fn ) spmfInitFormat( $fn );
 66+
 67+ $formats_list = implode( ', ', $spmgFormats );
 68+ $wgExtensionCredits['specialpage'][] = array(
 69+ 'path' => __FILE__,
 70+ 'name' => 'Semantic Project Management',
 71+ 'version' => SPM_VERSION,
 72+ 'author' => array( 'Frank Dengler, Jonas Bissinger'),
 73+ 'url' => 'http://www.mediawiki.org/wiki/Extension:Semantic_Project_Management',
 74+ 'descriptionmsg' => 'semanticprojectmanagement-desc'
 75+ );
 76+
 77+ $dir = dirname(__FILE__);
 78+
 79+}
 80+
 81+function spmfInitFormat( $format ) {
 82+ global $smwgResultFormats, $wgAutoloadClasses, $spmgIP;
 83+
 84+ $class = '';
 85+ $file = '';
 86+ switch ( $format ) {
 87+ case 'ganttchart':
 88+ $class = 'SPMGanttChart';
 89+ $file = $spmgIP . '/includes/SPM_GanttChart.php';
 90+ break;
 91+ case 'wbs':
 92+ $class = 'SPMWBS';
 93+ $file = $spmgIP . '/includes/SPM_WBS.php';
 94+ break;
 95+ }
 96+ if ( ( $class != '') && ( $file !='') ) {
 97+ $smwgResultFormats[$format] = $class;
 98+ $wgAutoloadClasses[$class] = $file;
 99+ }
 100+}
 101+
 102+/**
 103+ * Adds a link to Admin Links page
 104+ */
 105+function spmfAddToAdminLinks( &$admin_links_tree ) {
 106+ $displaying_data_section = $admin_links_tree->getSection( wfMsg( 'smw_adminlinks_displayingdata' ) );
 107+ // escape is SMW hasn't added links
 108+ if ( is_null( $displaying_data_section ) )
 109+ return true;
 110+ $smw_docu_row = $displaying_data_section->getRow( 'smw' );
 111+ wfLoadExtensionMessages( 'SemanticProjectManagement' );
 112+ $srf_docu_label = wfMsg( 'adminlinks_documentation', wfMsg( 'spm-name' ) );
 113+ $smw_docu_row->addItem( AlItem::newFromExternalLink( "http://www.mediawiki.org/wiki/Extension:Semantic_Project_Management", $spm_docu_label ) );
 114+ return true;
 115+}
\ No newline at end of file

Status & tagging log