强大 甘特图编辑器 jQuery jQueryGantt

  • 源码大小:230.39KB
  • 所需积分:1积分
  • 源码编号:19JP-3552
  • 浏览次数:974次
  • 最后更新:2023年06月25日
  • 所属栏目:图表
我要下载
加入收藏
本站默认解压密码:19jp.com 或 19jp_com

简介

一个强大的、可自定义的jQuery甘特图编辑器,可帮助您动态创建甘特图,以实现灵活的项目管理。

主要功能:

  • 跨浏览器。
  • 键盘交互。
  • 基于SVG的可视化编辑器。
  • 导入/导出JSON。
  • 拖放。
  • 移动/打印友好。

如何使用它:

1.在文档的标题部分加载所需的样式表。

  1. <link rel="stylesheet" href="platform.css">
  2. <link rel="stylesheet" href="libs/jquery/dateField/jquery.dateField.css">
  3. <link rel="stylesheet" href="gantt.css">
  4. <link rel="stylesheet" href="ganttPrint.css" media="print">

2.在文档末尾加载以下JavaScript文件。

  1. <script src="jquery.min.js"></script>
  2. <script src="jquery-ui.min.js"></script>
  3. <script src="libs/jquery/jquery.livequery.1.1.1.min.js"></script>
  4. <script src="libs/jquery/jquery.timers.js"></script>
  5. <script src="libs/utilities.js"></script>
  6. <script src="libs/forms.js"></script>
  7. <script src="libs/date.js"></script>
  8. <script src="libs/dialogs.js"></script>
  9. <script src="libs/layout.js"></script>
  10. <script src="libs/i18nJs.js"></script>
  11. <script src="libs/jquery/dateField/jquery.dateField.js"></script>
  12. <script src="libs/jquery/JST/jquery.JST.js"></script>
  13. <script src="libs/jquery/svg/jquery.svg.min.js"></script>
  14. <script src="libs/jquery/svg/jquery.svgdom.1.8.js"></script>
  15. <script src="ganttUtilities.js"></script>
  16. <script src="ganttTask.js"></script>
  17. <script src="ganttDrawerSVG.js"></script>
  18. <script src="ganttGridEditor.js"></script>
  19. <script src="ganttMaster.js"></script>

3.为甘特图编辑器创建HTML。

  1. <div id="workSpace"></div>
  2. <div id="gantEditorTemplates" style="display:none;">
  3. <div class="__template__" type="GANTBUTTONS"><!--
  4. <div class="ganttButtonBar noprint">
  5. <div class="buttons">
  6. <a href="https://gantt.twproject.com/"><img src="res/twGanttLogo.png" alt="Twproject" align="absmiddle" style="max-width: 136px; padding-right: 15px"></a>
  7.  
  8. <button onclick="$('#workSpace').trigger('undo.gantt');return false;" class="button textual icon requireCanWrite" title="undo"><span class="teamworkIcon">&#39;</span></button>
  9. <button onclick="$('#workSpace').trigger('redo.gantt');return false;" class="button textual icon requireCanWrite" title="redo"><span class="teamworkIcon">&middot;</span></button>
  10. <span class="ganttButtonSeparator requireCanWrite requireCanAdd"></span>
  11. <button onclick="$('#workSpace').trigger('addAboveCurrentTask.gantt');return false;" class="button textual icon requireCanWrite requireCanAdd" title="insert above"><span class="teamworkIcon">l</span></button>
  12. <button onclick="$('#workSpace').trigger('addBelowCurrentTask.gantt');return false;" class="button textual icon requireCanWrite requireCanAdd" title="insert below"><span class="teamworkIcon">X</span></button>
  13. <span class="ganttButtonSeparator requireCanWrite requireCanInOutdent"></span>
  14. <button onclick="$('#workSpace').trigger('outdentCurrentTask.gantt');return false;" class="button textual icon requireCanWrite requireCanInOutdent" title="un-indent task"><span class="teamworkIcon">.</span></button>
  15. <button onclick="$('#workSpace').trigger('indentCurrentTask.gantt');return false;" class="button textual icon requireCanWrite requireCanInOutdent" title="indent task"><span class="teamworkIcon">:</span></button>
  16. <span class="ganttButtonSeparator requireCanWrite requireCanMoveUpDown"></span>
  17. <button onclick="$('#workSpace').trigger('moveUpCurrentTask.gantt');return false;" class="button textual icon requireCanWrite requireCanMoveUpDown" title="move up"><span class="teamworkIcon">k</span></button>
  18. <button onclick="$('#workSpace').trigger('moveDownCurrentTask.gantt');return false;" class="button textual icon requireCanWrite requireCanMoveUpDown" title="move down"><span class="teamworkIcon">j</span></button>
  19. <span class="ganttButtonSeparator requireCanDelete"></span>
  20. <button onclick="$('#workSpace').trigger('deleteFocused.gantt');return false;" class="button textual icon delete requireCanWrite" title="Delete"><span class="teamworkIcon">&cent;</span></button>
  21. <span class="ganttButtonSeparator"></span>
  22. <button onclick="$('#workSpace').trigger('expandAll.gantt');return false;" class="button textual icon " title="EXPAND_ALL"><span class="teamworkIcon">6</span></button>
  23. <button onclick="$('#workSpace').trigger('collapseAll.gantt'); return false;" class="button textual icon " title="COLLAPSE_ALL"><span class="teamworkIcon">5</span></button>
  24.  
  25. <span class="ganttButtonSeparator"></span>
  26. <button onclick="$('#workSpace').trigger('zoomMinus.gantt'); return false;" class="button textual icon " title="zoom out"><span class="teamworkIcon">)</span></button>
  27. <button onclick="$('#workSpace').trigger('zoomPlus.gantt');return false;" class="button textual icon " title="zoom in"><span class="teamworkIcon">(</span></button>
  28. <span class="ganttButtonSeparator"></span>
  29. <button onclick="print();return false;" class="button textual icon " title="Print"><span class="teamworkIcon">p</span></button>
  30. <span class="ganttButtonSeparator"></span>
  31. <button onclick="ge.gantt.showCriticalPath=!ge.gantt.showCriticalPath; ge.redraw();return false;" class="button textual icon requireCanSeeCriticalPath" title="CRITICAL_PATH"><span class="teamworkIcon">&pound;</span></button>
  32. <span class="ganttButtonSeparator requireCanSeeCriticalPath"></span>
  33. <button onclick="ge.splitter.resize(.1);return false;" class="button textual icon" ><span class="teamworkIcon">F</span></button>
  34. <button onclick="ge.splitter.resize(50);return false;" class="button textual icon" ><span class="teamworkIcon">O</span></button>
  35. <button onclick="ge.splitter.resize(100);return false;" class="button textual icon"><span class="teamworkIcon">R</span></button>
  36. <span class="ganttButtonSeparator"></span>
  37. <button onclick="$('#workSpace').trigger('fullScreen.gantt');return false;" class="button textual icon" title="FULLSCREEN" id="fullscrbtn"><span class="teamworkIcon">@</span></button>
  38. <button onclick="ge.element.toggleClass('colorByStatus' );return false;" class="button textual icon"><span class="teamworkIcon">&sect;</span></button>
  39.  
  40. <button onclick="editResources();" class="button textual requireWrite" title="edit resources"><span class="teamworkIcon">M</span></button>
  41. &nbsp; &nbsp; &nbsp; &nbsp;
  42. <button onclick="saveGanttOnServer();" class="button first big requireWrite" title="Save">Save</button>
  43. <button onclick='newProject();' class='button requireWrite newproject'><em>clear project</em></button>
  44. <button class="button login" title="login/enroll" onclick="loginEnroll($(this));" style="display:none;">login/enroll</button>
  45. <button class="button opt collab" title="Start with Twproject" onclick="collaborate($(this));" style="display:none;"><em>collaborate</em></button>
  46. </div></div>
  47. --></div>
  48.  
  49. <div class="__template__" type="TASKSEDITHEAD"><!--
  50. <table class="gdfTable" cellspacing="0" cellpadding="0">
  51. <thead>
  52. <tr style="height:40px">
  53. <th class="gdfColHeader" style="width:35px; border-right: none"></th>
  54. <th class="gdfColHeader" style="width:25px;"></th>
  55. <th class="gdfColHeader gdfResizable" style="width:100px;">code/short name</th>
  56. <th class="gdfColHeader gdfResizable" style="width:300px;">name</th>
  57. <th class="gdfColHeader" align="center" style="width:17px;" title="Start date is a milestone."><span class="teamworkIcon" style="font-size: 8px;">^</span></th>
  58. <th class="gdfColHeader gdfResizable" style="width:80px;">start</th>
  59. <th class="gdfColHeader" align="center" style="width:17px;" title="End date is a milestone."><span class="teamworkIcon" style="font-size: 8px;">^</span></th>
  60. <th class="gdfColHeader gdfResizable" style="width:80px;">End</th>
  61. <th class="gdfColHeader gdfResizable" style="width:50px;">dur.</th>
  62. <th class="gdfColHeader gdfResizable" style="width:20px;">%</th>
  63. <th class="gdfColHeader gdfResizable requireCanSeeDep" style="width:50px;">depe.</th>
  64. <th class="gdfColHeader gdfResizable" style="width:1000px; text-align: left; padding-left: 10px;">assignees</th>
  65. </tr>
  66. </thead>
  67. </table>
  68. --></div>
  69.  
  70. <div class="__template__" type="TASKROW"><!--
  71. <tr taskId="(#=obj.id#)" class="taskEditRow (#=obj.isParent()?'isParent':''#) (#=obj.collapsed?'collapsed':''#)" level="(#=level#)">
  72. <th class="gdfCell edit" align="right" style="cursor:pointer;"><span class="taskRowIndex">(#=obj.getRow()+1#)</span> <span class="teamworkIcon" style="font-size:12px;" >e</span></th>
  73. <td class="gdfCell noClip" align="center"><div class="taskStatus cvcColorSquare" status="(#=obj.status#)"></div></td>
  74. <td class="gdfCell"><input type="text" name="code" value="(#=obj.code?obj.code:''#)" placeholder="code/short name"></td>
  75. <td class="gdfCell indentCell" style="padding-left:(#=obj.level*10+18#)px;">
  76. <div class="exp-controller" align="center"></div>
  77. <input type="text" name="name" value="(#=obj.name#)" placeholder="name">
  78. </td>
  79. <td class="gdfCell" align="center"><input type="checkbox" name="startIsMilestone"></td>
  80. <td class="gdfCell"><input type="text" name="start" value="" class="date"></td>
  81. <td class="gdfCell" align="center"><input type="checkbox" name="endIsMilestone"></td>
  82. <td class="gdfCell"><input type="text" name="end" value="" class="date"></td>
  83. <td class="gdfCell"><input type="text" name="duration" autocomplete="off" value="(#=obj.duration#)"></td>
  84. <td class="gdfCell"><input type="text" name="progress" class="validated" entrytype="PERCENTILE" autocomplete="off" value="(#=obj.progress?obj.progress:''#)" (#=obj.progressByWorklog?"readOnly":""#)></td>
  85. <td class="gdfCell requireCanSeeDep"><input type="text" name="depends" autocomplete="off" value="(#=obj.depends#)" (#=obj.hasExternalDep?"readonly":""#)></td>
  86. <td class="gdfCell taskAssigs">(#=obj.getAssigsString()#)</td>
  87. </tr>
  88. --></div>
  89.  
  90. <div class="__template__" type="TASKEMPTYROW"><!--
  91. <tr class="taskEditRow emptyRow" >
  92. <th class="gdfCell" align="right"></th>
  93. <td class="gdfCell noClip" align="center"></td>
  94. <td class="gdfCell"></td>
  95. <td class="gdfCell"></td>
  96. <td class="gdfCell"></td>
  97. <td class="gdfCell"></td>
  98. <td class="gdfCell"></td>
  99. <td class="gdfCell"></td>
  100. <td class="gdfCell"></td>
  101. <td class="gdfCell"></td>
  102. <td class="gdfCell requireCanSeeDep"></td>
  103. <td class="gdfCell"></td>
  104. </tr>
  105. --></div>
  106.  
  107. <div class="__template__" type="TASKBAR"><!--
  108. <div class="taskBox taskBoxDiv" taskId="(#=obj.id#)" >
  109. <div class="layout (#=obj.hasExternalDep?'extDep':''#)">
  110. <div class="taskStatus" status="(#=obj.status#)"></div>
  111. <div class="taskProgress" style="width:(#=obj.progress>100?100:obj.progress#)%; background-color:(#=obj.progress>100?'red':'rgb(153,255,51);'#);"></div>
  112. <div class="milestone (#=obj.startIsMilestone?'active':''#)" ></div>
  113.  
  114. <div class="taskLabel"></div>
  115. <div class="milestone end (#=obj.endIsMilestone?'active':''#)" ></div>
  116. </div>
  117. </div>
  118. --></div>
  119.  
  120.  
  121. <div class="__template__" type="CHANGE_STATUS"><!--
  122. <div class="taskStatusBox">
  123. <div class="taskStatus cvcColorSquare" status="STATUS_ACTIVE" title="active"></div>
  124. <div class="taskStatus cvcColorSquare" status="STATUS_DONE" title="completed"></div>
  125. <div class="taskStatus cvcColorSquare" status="STATUS_FAILED" title="failed"></div>
  126. <div class="taskStatus cvcColorSquare" status="STATUS_SUSPENDED" title="suspended"></div>
  127. <div class="taskStatus cvcColorSquare" status="STATUS_UNDEFINED" title="undefined"></div>
  128. </div>
  129. --></div>
  130.  
  131.  
  132.  
  133.  
  134.  
  135. <div class="__template__" type="TASK_EDITOR"><!--
  136. <div class="ganttTaskEditor">
  137. <h2 class="taskData">Task editor</h2>
  138. <table cellspacing="1" cellpadding="5" width="100%" class="taskData table" border="0">
  139. <tr>
  140. <td width="200" style="height: 80px" valign="top">
  141. <label for="code">code/short name</label><br>
  142. <input type="text" name="code" id="code" value="" size=15 class="formElements" autocomplete='off' maxlength=255 style='width:100%' oldvalue="1">
  143. </td>
  144. <td colspan="3" valign="top"><label for="name" class="required">name</label><br><input type="text" name="name" id="name"class="formElements" autocomplete='off' maxlength=255 style='width:100%' value="" required="true" oldvalue="1"></td>
  145. </tr>
  146.  
  147.  
  148. <tr class="dateRow">
  149. <td nowrap="">
  150. <div style="position:relative">
  151. <label for="start">start</label>&nbsp;&nbsp;&nbsp;&nbsp;
  152. <input type="checkbox" id="startIsMilestone" name="startIsMilestone" value="yes"> &nbsp;<label for="startIsMilestone">is milestone</label>&nbsp;
  153. <br><input type="text" name="start" id="start" size="8" class="formElements dateField validated date" autocomplete="off" maxlength="255" value="" oldvalue="1" entrytype="DATE">
  154. <span title="calendar" id="starts_inputDate" class="teamworkIcon openCalendar" onclick="$(this).dateField({inputField:$(this).prevAll(':input:first'),isSearchField:false});">m</span> </div>
  155. </td>
  156. <td nowrap="">
  157. <label for="end">End</label>&nbsp;&nbsp;&nbsp;&nbsp;
  158. <input type="checkbox" id="endIsMilestone" name="endIsMilestone" value="yes"> &nbsp;<label for="endIsMilestone">is milestone</label>&nbsp;
  159. <br><input type="text" name="end" id="end" size="8" class="formElements dateField validated date" autocomplete="off" maxlength="255" value="" oldvalue="1" entrytype="DATE">
  160. <span title="calendar" id="ends_inputDate" class="teamworkIcon openCalendar" onclick="$(this).dateField({inputField:$(this).prevAll(':input:first'),isSearchField:false});">m</span>
  161. </td>
  162. <td nowrap="" >
  163. <label for="duration" class=" ">Days</label><br>
  164. <input type="text" name="duration" id="duration" size="4" class="formElements validated durationdays" title="Duration is in working days." autocomplete="off" maxlength="255" value="" oldvalue="1" entrytype="DURATIONDAYS">&nbsp;
  165. </td>
  166. </tr>
  167.  
  168. <tr>
  169. <td colspan="2">
  170. <label for="status" class=" ">status</label><br>
  171. <select id="status" name="status" class="taskStatus" status="(#=obj.status#)" onchange="$(this).attr('STATUS',$(this).val());">
  172. <option value="STATUS_ACTIVE" class="taskStatus" status="STATUS_ACTIVE" >active</option>
  173. <option value="STATUS_SUSPENDED" class="taskStatus" status="STATUS_SUSPENDED" >suspended</option>
  174. <option value="STATUS_DONE" class="taskStatus" status="STATUS_DONE" >completed</option>
  175. <option value="STATUS_FAILED" class="taskStatus" status="STATUS_FAILED" >failed</option>
  176. <option value="STATUS_UNDEFINED" class="taskStatus" status="STATUS_UNDEFINED" >undefined</option>
  177. </select>
  178. </td>
  179.  
  180. <td valign="top" nowrap>
  181. <label>progress</label><br>
  182. <input type="text" name="progress" id="progress" size="7" class="formElements validated percentile" autocomplete="off" maxlength="255" value="" oldvalue="1" entrytype="PERCENTILE">
  183. </td>
  184. </tr>
  185.  
  186. </tr>
  187. <tr>
  188. <td colspan="4">
  189. <label for="description">Description</label><br>
  190. <textarea rows="3" cols="30" id="description" name="description" class="formElements" style="width:100%"></textarea>
  191. </td>
  192. </tr>
  193. </table>
  194.  
  195. <h2>Assignments</h2>
  196. <table cellspacing="1" cellpadding="0" width="100%" id="assigsTable">
  197. <tr>
  198. <th style="width:100px;">name</th>
  199. <th style="width:70px;">Role</th>
  200. <th style="width:30px;">est.wklg.</th>
  201. <th style="width:30px;" id="addAssig"><span class="teamworkIcon" style="cursor: pointer">+</span></th>
  202. </tr>
  203. </table>
  204.  
  205. <div style="text-align: right; padding-top: 20px">
  206. <span id="saveButton" class="button first" onClick="$(this).trigger('saveFullEditor.gantt');">Save</span>
  207. </div>
  208.  
  209. </div>
  210. --></div>
  211.  
  212.  
  213.  
  214. <div class="__template__" type="ASSIGNMENT_ROW"><!--
  215. <tr taskId="(#=obj.task.id#)" assId="(#=obj.assig.id#)" class="assigEditRow" >
  216. <td ><select name="resourceId" class="formElements" (#=obj.assig.id.indexOf("tmp_")==0?"":"disabled"#) ></select></td>
  217. <td ><select type="select" name="roleId" class="formElements"></select></td>
  218. <td ><input type="text" name="effort" value="(#=getMillisInHoursMinutes(obj.assig.effort)#)" size="5" class="formElements"></td>
  219. <td align="center"><span class="teamworkIcon delAssig del" style="cursor: pointer">d</span></td>
  220. </tr>
  221. --></div>
  222.  
  223.  
  224.  
  225. <div class="__template__" type="RESOURCE_EDITOR"><!--
  226. <div class="resourceEditor" style="padding: 5px;">
  227.  
  228. <h2>Project team</h2>
  229. <table cellspacing="1" cellpadding="0" width="100%" id="resourcesTable">
  230. <tr>
  231. <th style="width:100px;">name</th>
  232. <th style="width:30px;" id="addResource"><span class="teamworkIcon" style="cursor: pointer">+</span></th>
  233. </tr>
  234. </table>
  235.  
  236. <div style="text-align: right; padding-top: 20px"><button id="resSaveButton" class="button big">Save</button></div>
  237. </div>
  238. --></div>
  239.  
  240.  
  241.  
  242. <div class="__template__" type="RESOURCE_ROW"><!--
  243. <tr resId="(#=obj.id#)" class="resRow" >
  244. <td ><input type="text" name="name" value="(#=obj.name#)" style="width:100%;" class="formElements"></td>
  245. <td align="center"><span class="teamworkIcon delRes del" style="cursor: pointer">d</span></td>
  246. </tr>
  247. --></div>
  248.  
  249.  
  250. </div>
  251. <form id="gimmeBack" style="display:none;" action="gimmeBack.jsp" method="post" target="_blank"><input type="hidden" name="prj" id="gimBaPrj"></form>

4.用于激活甘特图编辑器的JavaScript。

  1. var ge;
  2. $(function() {
  3. var canWrite=true; //this is the default for test purposes
  4.  
  5. // here starts gantt initialization
  6. ge = new GanttMaster();
  7. ge.set100OnClose=true;
  8.  
  9. ge.init($("#workSpace"));
  10. loadI18n(); //overwrite with localized ones
  11.  
  12. //in order to force compute the best-fitting zoom level
  13. delete ge.gantt.zoom;
  14.  
  15.  
  16. var project=loadFromLocalStorage();
  17.  
  18.  
  19. if (!project.canWrite)
  20. $(".ganttButtonBar button.requireWrite").attr("disabled","true");
  21.  
  22. ge.loadProject(project);
  23. ge.checkpoint(); //empty the undo stack
  24.  
  25. ge.editor.element.oneTime(100, "cl", function () {$(this).find("tr.emptyRow:first").click()});
  26. });
  27.  
  28.  
  29.  
  30. function loadGanttFromServer(taskId, callback) {
  31.  
  32. //this is a simulation: load data from the local storage if you have already played with the demo or a textarea with starting demo data
  33. loadFromLocalStorage();
  34.  
  35. //this is the real implementation
  36. /*
  37. //var taskId = $("#taskSelector").val();
  38. var prof = new Profiler("loadServerSide");
  39. prof.reset();
  40.  
  41. $.getJSON("ganttAjaxController.jsp", {CM:"LOADPROJECT",taskId:taskId}, function(response) {
  42. //console.debug(response);
  43. if (response.ok) {
  44. prof.stop();
  45.  
  46. ge.loadProject(response.project);
  47. ge.checkpoint(); //empty the undo stack
  48.  
  49. if (typeof(callback)=="function") {
  50. callback(response);
  51. }
  52. } else {
  53. jsonErrorHandling(response);
  54. }
  55. });
  56. */
  57. }
  58.  
  59.  
  60. function saveGanttOnServer() {
  61.  
  62. //this is a simulation: save data to the local storage or to the textarea
  63. saveInLocalStorage();
  64.  
  65. /*
  66. var prj = ge.saveProject();
  67.  
  68. delete prj.resources;
  69. delete prj.roles;
  70.  
  71. var prof = new Profiler("saveServerSide");
  72. prof.reset();
  73.  
  74. if (ge.deletedTaskIds.length>0) {
  75. if (!confirm("TASK_THAT_WILL_BE_REMOVED\n"+ge.deletedTaskIds.length)) {
  76. return;
  77. }
  78. }
  79.  
  80. $.ajax("ganttAjaxController.jsp", {
  81. dataType:"json",
  82. data: {CM:"SVPROJECT",prj:JSON.stringify(prj)},
  83. type:"POST",
  84.  
  85. success: function(response) {
  86. if (response.ok) {
  87. prof.stop();
  88. if (response.project) {
  89. ge.loadProject(response.project); //must reload as "tmp_" ids are now the good ones
  90. } else {
  91. ge.reset();
  92. }
  93. } else {
  94. var errMsg="Errors saving project\n";
  95. if (response.message) {
  96. errMsg=errMsg+response.message+"\n";
  97. }
  98.  
  99. if (response.errorMessages.length) {
  100. errMsg += response.errorMessages.join("\n");
  101. }
  102.  
  103. alert(errMsg);
  104. }
  105. }
  106.  
  107. });
  108. */
  109. }
  110.  
  111. function newProject(){
  112. clearGantt();
  113. }
  114.  
  115.  
  116. //------------------------------------------- Create some demo data ------------------------------------------------------
  117. function setRoles() {
  118. ge.roles = [
  119. {
  120. id:"tmp_1",
  121. name:"Project Manager"
  122. },
  123. {
  124. id:"tmp_2",
  125. name:"Worker"
  126. },
  127. {
  128. id:"tmp_3",
  129. name:"Stakeholder"
  130. },
  131. {
  132. id:"tmp_4",
  133. name:"Customer"
  134. }
  135. ];
  136. }
  137.  
  138. function setResource() {
  139. var res = [];
  140. for (var i = 1; i <= 10; i++) {
  141. res.push({id:"tmp_" + i,name:"Resource " + i});
  142. }
  143. ge.resources = res;
  144. }
  145.  
  146.  
  147. function editResources(){
  148.  
  149. }
  150.  
  151. function clearGantt() {
  152. ge.reset();
  153. }
  154.  
  155. function loadI18n() {
  156. GanttMaster.messages = {
  157. "CANNOT_WRITE": "CANNOT_WRITE",
  158. "CHANGE_OUT_OF_SCOPE":"NO_RIGHTS_FOR_UPDATE_PARENTS_OUT_OF_EDITOR_SCOPE",
  159. "START_IS_MILESTONE":"START_IS_MILESTONE",
  160. "END_IS_MILESTONE":"END_IS_MILESTONE",
  161. "TASK_HAS_CONSTRAINTS":"TASK_HAS_CONSTRAINTS",
  162. "GANTT_ERROR_DEPENDS_ON_OPEN_TASK":"GANTT_ERROR_DEPENDS_ON_OPEN_TASK",
  163. "GANTT_ERROR_DESCENDANT_OF_CLOSED_TASK":"GANTT_ERROR_DESCENDANT_OF_CLOSED_TASK",
  164. "TASK_HAS_EXTERNAL_DEPS":"TASK_HAS_EXTERNAL_DEPS",
  165. "GANTT_ERROR_LOADING_DATA_TASK_REMOVED":"GANTT_ERROR_LOADING_DATA_TASK_REMOVED",
  166. "ERROR_SETTING_DATES":"ERROR_SETTING_DATES",
  167. "CIRCULAR_REFERENCE":"CIRCULAR_REFERENCE",
  168. "CANNOT_DEPENDS_ON_ANCESTORS":"CANNOT_DEPENDS_ON_ANCESTORS",
  169. "CANNOT_DEPENDS_ON_DESCENDANTS":"CANNOT_DEPENDS_ON_DESCENDANTS",
  170. "INVALID_DATE_FORMAT":"INVALID_DATE_FORMAT",
  171. "TASK_MOVE_INCONSISTENT_LEVEL":"TASK_MOVE_INCONSISTENT_LEVEL",
  172.  
  173. "GANTT_QUARTER_SHORT":"trim.",
  174. "GANTT_SEMESTER_SHORT":"sem."
  175. };
  176. }
  177.  
  178.  
  179.  
  180. //------------------------------------------- Get project file as JSON (used for migrate project from gantt to Teamwork) ------------------------------------------------------
  181. function getFile() {
  182. $("#gimBaPrj").val(JSON.stringify(ge.saveProject()));
  183. $("#gimmeBack").submit();
  184. $("#gimBaPrj").val("");
  185.  
  186. /* var uriContent = "data:text/html;charset=utf-8," + encodeURIComponent(JSON.stringify(prj));
  187. neww=window.open(uriContent,"dl");*/
  188. }
  189.  
  190.  
  191. function loadFromLocalStorage() {
  192. var ret;
  193. if (localStorage) {
  194. if (localStorage.getObject("teamworkGantDemo")) {
  195. ret = localStorage.getObject("teamworkGantDemo");
  196. }
  197. }
  198.  
  199. //if not found create a new example task
  200. if (!ret || !ret.tasks || ret.tasks.length == 0){
  201. ret= {"tasks": [
  202. {"id": -1, "name": "Gantt editor", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 0, "status": "STATUS_ACTIVE", "depends": "", "canWrite": true, "start": 1396994400000, "duration": 20, "end": 1399586399999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": true},
  203. {"id": -2, "name": "coding", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 1, "status": "STATUS_ACTIVE", "depends": "", "canWrite": true, "start": 1396994400000, "duration": 10, "end": 1398203999999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": true},
  204. {"id": -3, "name": "gantt part", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 2, "status": "STATUS_ACTIVE", "depends": "", "canWrite": true, "start": 1396994400000, "duration": 2, "end": 1397167199999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": false},
  205. {"id": -4, "name": "editor part", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 2, "status": "STATUS_SUSPENDED", "depends": "3", "canWrite": true, "start": 1397167200000, "duration": 4, "end": 1397685599999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": false},
  206. {"id": -5, "name": "testing", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 1, "status": "STATUS_SUSPENDED", "depends": "2:5", "canWrite": true, "start": 1398981600000, "duration": 5, "end": 1399586399999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": true},
  207. {"id": -6, "name": "test on safari", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 2, "status": "STATUS_SUSPENDED", "depends": "", "canWrite": true, "start": 1398981600000, "duration": 2, "end": 1399327199999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": false},
  208. {"id": -7, "name": "test on ie", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 2, "status": "STATUS_SUSPENDED", "depends": "6", "canWrite": true, "start": 1399327200000, "duration": 3, "end": 1399586399999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": false},
  209. {"id": -8, "name": "test on chrome", "progress": 0, "progressByWorklog": false, "relevance": 0, "type": "", "typeId": "", "description": "", "code": "", "level": 2, "status": "STATUS_SUSPENDED", "depends": "6", "canWrite": true, "start": 1399327200000, "duration": 2, "end": 1399499999999, "startIsMilestone": false, "endIsMilestone": false, "collapsed": false, "assigs": [], "hasChild": false}
  210. ], "selectedRow": 2, "deletedTaskIds": [],
  211. "resources": [
  212. {"id": "tmp_1", "name": "Resource 1"},
  213. {"id": "tmp_2", "name": "Resource 2"},
  214. {"id": "tmp_3", "name": "Resource 3"},
  215. {"id": "tmp_4", "name": "Resource 4"}
  216. ],
  217. "roles": [
  218. {"id": "tmp_1", "name": "Project Manager"},
  219. {"id": "tmp_2", "name": "Worker"},
  220. {"id": "tmp_3", "name": "Stakeholder"},
  221. {"id": "tmp_4", "name": "Customer"}
  222. ], "canWrite": true, "canDelete":true, "canWriteOnParent": true, "zoom": "w3"}
  223.  
  224.  
  225. //actualize data
  226. var offset=new Date().getTime()-ret.tasks[0].start;
  227. for (var i=0;i<ret.tasks.length;i++) {
  228. ret.tasks[i].start = ret.tasks[i].start + offset;
  229. }
  230. }
  231. return ret;
  232. }
  233.  
  234.  
  235. function saveInLocalStorage() {
  236. var prj = ge.saveProject();
  237. if (localStorage) {
  238. localStorage.setObject("teamworkGantDemo", prj);
  239. }
  240. }
  241.  
  242.  
  243. //------------------------------------------- Open a black popup for managing resources. This is only an axample of implementation (usually resources come from server) ------------------------------------------------------
  244. function editResources(){
  245.  
  246. //make resource editor
  247. var resourceEditor = $.JST.createFromTemplate({}, "RESOURCE_EDITOR");
  248. var resTbl=resourceEditor.find("#resourcesTable");
  249.  
  250. for (var i=0;i<ge.resources.length;i++){
  251. var res=ge.resources[i];
  252. resTbl.append($.JST.createFromTemplate(res, "RESOURCE_ROW"))
  253. }
  254.  
  255.  
  256. //bind add resource
  257. resourceEditor.find("#addResource").click(function(){
  258. resTbl.append($.JST.createFromTemplate({id:"new",name:"resource"}, "RESOURCE_ROW"))
  259. });
  260.  
  261. //bind save event
  262. resourceEditor.find("#resSaveButton").click(function(){
  263. var newRes=[];
  264. //find for deleted res
  265. for (var i=0;i<ge.resources.length;i++){
  266. var res=ge.resources[i];
  267. var row = resourceEditor.find("[resId="+res.id+"]");
  268. if (row.length>0){
  269. //if still there save it
  270. var name = row.find("input[name]").val();
  271. if (name && name!="")
  272. res.name=name;
  273. newRes.push(res);
  274. } else {
  275. //remove assignments
  276. for (var j=0;j<ge.tasks.length;j++){
  277. var task=ge.tasks[j];
  278. var newAss=[];
  279. for (var k=0;k<task.assigs.length;k++){
  280. var ass=task.assigs[k];
  281. if (ass.resourceId!=res.id)
  282. newAss.push(ass);
  283. }
  284. task.assigs=newAss;
  285. }
  286. }
  287. }
  288.  
  289. //loop on new rows
  290. var cnt=0
  291. resourceEditor.find("[resId=new]").each(function(){
  292. cnt++;
  293. var row = $(this);
  294. var name = row.find("input[name]").val();
  295. if (name && name!="")
  296. newRes.push (new Resource("tmp_"+new Date().getTime()+"_"+cnt,name));
  297. });
  298.  
  299. ge.resources=newRes;
  300.  
  301. closeBlackPopup();
  302. ge.redraw();
  303. });
  304.  
  305.  
  306. var ndo = createModalPopup(400, 500).append(resourceEditor);
  307. }
  308.  
  309. $.JST.loadDecorator("RESOURCE_ROW", function(resTr, res){
  310. resTr.find(".delRes").click(function(){$(this).closest("tr").remove()});
  311. });
  312.  
  313. $.JST.loadDecorator("ASSIGNMENT_ROW", function(assigTr, taskAssig){
  314. var resEl = assigTr.find("[name=resourceId]");
  315. var opt = $("<option>");
  316. resEl.append(opt);
  317. for(var i=0; i< taskAssig.task.master.resources.length;i++){
  318. var res = taskAssig.task.master.resources[i];
  319. opt = $("<option>");
  320. opt.val(res.id).html(res.name);
  321. if(taskAssig.assig.resourceId == res.id)
  322. opt.attr("selected", "true");
  323. resEl.append(opt);
  324. }
  325. var roleEl = assigTr.find("[name=roleId]");
  326. for(var i=0; i< taskAssig.task.master.roles.length;i++){
  327. var role = taskAssig.task.master.roles[i];
  328. var optr = $("<option>");
  329. optr.val(role.id).html(role.name);
  330. if(taskAssig.assig.roleId == role.id)
  331. optr.attr("selected", "true");
  332. roleEl.append(optr);
  333. }
  334.  
  335. if(taskAssig.task.master.permissions.canWrite && taskAssig.task.canWrite){
  336. assigTr.find(".delAssig").click(function(){
  337. var tr = $(this).closest("[assId]").fadeOut(200, function(){$(this).remove()});
  338. });
  339. }
  340.  
  341. });
  342.  
  343.  
  344. function loadI18n(){
  345. GanttMaster.messages = {
  346. "CANNOT_WRITE":"No permission to change the following task:",
  347. "CHANGE_OUT_OF_SCOPE":"Project update not possible as you lack rights for updating a parent project.",
  348. "START_IS_MILESTONE":"Start date is a milestone.",
  349. "END_IS_MILESTONE":"End date is a milestone.",
  350. "TASK_HAS_CONSTRAINTS":"Task has constraints.",
  351. "GANTT_ERROR_DEPENDS_ON_OPEN_TASK":"Error: there is a dependency on an open task.",
  352. "GANTT_ERROR_DESCENDANT_OF_CLOSED_TASK":"Error: due to a descendant of a closed task.",
  353. "TASK_HAS_EXTERNAL_DEPS":"This task has external dependencies.",
  354. "GANNT_ERROR_LOADING_DATA_TASK_REMOVED":"GANNT_ERROR_LOADING_DATA_TASK_REMOVED",
  355. "CIRCULAR_REFERENCE":"Circular reference.",
  356. "CANNOT_DEPENDS_ON_ANCESTORS":"Cannot depend on ancestors.",
  357. "INVALID_DATE_FORMAT":"The data inserted are invalid for the field format.",
  358. "GANTT_ERROR_LOADING_DATA_TASK_REMOVED":"An error has occurred while loading the data. A task has been trashed.",
  359. "CANNOT_CLOSE_TASK_IF_OPEN_ISSUE":"Cannot close a task with open issues",
  360. "TASK_MOVE_INCONSISTENT_LEVEL":"You cannot exchange tasks of different depth.",
  361. "GANTT_QUARTER_SHORT":"Quarter",
  362. "GANTT_SEMESTER_SHORT":"Sem",
  363. "CANNOT_MOVE_TASK":"CANNOT_MOVE_TASK",
  364. "PLEASE_SAVE_PROJECT":"PLEASE_SAVE_PROJECT"
  365. };
  366. }
  367.  
  368.  
  369.  
  370. function createNewResource(el) {
  371. var row = el.closest("tr[taskid]");
  372. var name = row.find("[name=resourceId_txt]").val();
  373. var url = contextPath + "/applications/teamwork/resource/resourceNew.jsp?CM=ADD&name=" + encodeURI(name);
  374.  
  375. openBlackPopup(url, 700, 320, function (response) {
  376. //fillare lo smart combo
  377. if (response && response.resId && response.resName) {
  378. //fillare lo smart combo e chiudere l'editor
  379. row.find("[name=resourceId]").val(response.resId);
  380. row.find("[name=resourceId_txt]").val(response.resName).focus().blur();
  381. }
  382.  
  383. });
  384. }

更新日志:

2022-05-30

  • JS更新

预览截图