00001 var DefaultColor = "";
00002 var DefaultShadow = "";
00003 var TableHtml;
00004 var InfoHtml;
00005 var TreeGridHtml;
00006 var DialogContentHtml;
00007 var CurrentNamedConfig = "";
00008 var CurrentEntity;
00009 var CurrentCollection;
00010 var LastTabId = 1;
00011 var EditedValues = {};
00012 var ExportTarFileName = "export";
00013 var UploadFiles = {};
00014 var ConfigVersionData = {};
00015
00016
00017
00018 var UserId = "1";
00019
00020
00021 function GenerateUuid() {
00022 var d = Date.now();
00023 if (window.performance && typeof window.performance.now === "function") {
00024 d += performance.now();
00025 }
00026 var uuid = "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, function (c) {
00027 var r = (d + Math.random() * 16) % 16 | 0;
00028 d = Math.floor(d / 16);
00029 return (c === "x" ? r : (r & 0x3 | 0x8)).toString(16);
00030 });
00031 return uuid;
00032 };
00033
00034 function UpdateHeader(error, change, text) {
00035 if (error) {
00036 $("#header").css("background-color", "#D59595").css("text-shadow", "#D99 0 1px 0");
00037 $("#info").text(text);
00038 text = "ERROR: " + text;
00039 } else if (change) {
00040 $("#header").css("background-color", "#E7F29B").css("text-shadow", "#EF9 0 1px 0");
00041 $("#info").text(text);
00042 text = "CHANGE: " + text;
00043 } else {
00044 $("#header").css("background-color", DefaultColor).css("text-shadow", DefaultShadow);
00045 $("#info").text(text);
00046 }
00047 if (text.length > 0) {
00048 console.log(text);
00049 }
00050 };
00051
00052 function ResizeTextAreas() {
00053 $("textarea").each(function (i, el) {
00054 $(el).height(el.scrollHeight);
00055 });
00056 };
00057
00058 function GetRadix(value) {
00059 var output = {
00060 radix: 10,
00061 value: value
00062 };
00063 value = "" + value;
00064 if (value.search("0x") === 0) {
00065 output.value = value.slice(2);
00066 output.radix = 16;
00067 if (("" + output.value).search(/[^0-9a-fA-F]/) >= 0) { output.radix = -1; }
00068 } else if (value.search("0") === 0) {
00069 output.value = value.slice(1);
00070 output.radix = 8;
00071 if (isNaN(output.value)) { output.radix = -1; }
00072 } else if (value.search("b") === value.length - 1) {
00073 output.value = value.slice(0, -1);
00074 output.radix = 2;
00075 if (isNaN(output.value)) { output.radix = -1; }
00076 } else if (isNaN(value)) {
00077 output.radix = -1;
00078 }
00079 if (value === "0") {
00080 output.radix = 10;
00081 output.value = "0";
00082 }
00083 if (output.value === " " || ("" + output.value).length === 0 || ("" + output.value).indexOf(".") >= 0) {
00084 output.radix = -1;
00085 }
00086
00087 return output;
00088 }
00089
00090 function CreateRowEditor(row, cellvalue, editor, cellText, width, height) {
00091 editor.after("<div></div><div></div>");
00092 var radixObj = GetRadix(cellText);
00093 if (radixObj.radix > 0) {
00094 editor.parent().jqxFormattedInput({ radix: radixObj.radix, value: radixObj.value, width: width, height: height, upperCase: true, dropDown: true, spinButtons: true });
00095 }
00096 };
00097
00098 function InitRowEditor(row, cellvalue, editor) {
00099 editor.parent().val(cellvalue);
00100 };
00101
00102 function GetRowEditorValue(row, cellvalue, editor) {
00103 if (editor.parent()) {
00104 if (editor.val().length === 0) {
00105 editor.parent().parent().empty();
00106 return "";
00107 }
00108 var radix = editor.parent().jqxFormattedInput("radix");
00109 if (radix === 2 || radix === "binary") {
00110 return editor.val() + "b";
00111 }
00112 if (radix === 16 || radix === "hexadecimal") {
00113 return "0x" + editor.val().toUpperCase();
00114 }
00115 if (radix === 8 || radix === "octal") {
00116 if (editor.val()[0] === "0") {
00117 return editor.val();
00118 }
00119 return "0" + editor.val();
00120 }
00121 }
00122 return editor.val();
00123 };
00124
00125 function RowEditDialogSave(dataFields, newRowId, grid) {
00126 var row = {};
00127
00128 for (var i in dataFields) {
00129 if (dataFields.hasOwnProperty(i)) {
00130 var name = dataFields[i].name + "_Editor";
00131 var value = "" + $("#" + name).val();
00132 if (value === "undefined") {
00133 value = "";
00134 }
00135 row[dataFields[i].name] = value;
00136 }
00137 }
00138
00139 var path = row.name;
00140 var currentName = path;
00141 var rowData = grid.jqxTreeGrid("getRow", newRowId);
00142 var parent = rowData.parent;
00143 do {
00144 if ((parent === null || parent === undefined) && currentName.indexOf("___") >= 0) {
00145 var parentSelector = grid.selector.split(" ").slice(0, -1).join(" ");
00146 var parentRow = $(parentSelector + " #treeGrid").jqxTreeGrid("getRow", currentName.slice(0, -4));
00147 parent = parentRow[0];
00148 }
00149 if (parent !== null && parent !== undefined) {
00150 currentName = parent.name;
00151 path = parent.name + "/" + path;
00152 parent = parent.parent;
00153 }
00154 } while (parent !== null && parent !== undefined);
00155
00156 if (CurrentCollection && CurrentEntity) {
00157 path = CurrentCollection + "/" + CurrentEntity + "/" + path;
00158 } else {
00159 var pathTmp = path.split('/');
00160 var collection = pathTmp.shift();
00161 var entity = pathTmp.shift();
00162 var collectionTab = $(".collection-tab[collection-name=\"" + collection + "\"] a");
00163 collectionTab.trigger("click");
00164 var fileNameTab = $(collectionTab[0].hash).find(".file-tab[file-name=\"" + entity + "\"] a");
00165 fileNameTab.trigger("click");
00166 $("li.active :visible").parent().addClass("editedValue");
00167 $(".configInfo-tab a").trigger("click");
00168 CurrentCollection = collection;
00169 CurrentEntity = entity;
00170 }
00171
00172 grid.jqxTreeGrid("updateRow", newRowId, row);
00173 EditedValues[CurrentCollection + "/" + CurrentEntity + "/" + row.name] = true;
00174 $("li.active :visible").parent().addClass("editedValue");
00175 $(".configInfo-tab").removeClass("editedValue");
00176
00177
00178 AjaxPost("/db/AddOrUpdate", {
00179 configName: CurrentNamedConfig,
00180 table: path,
00181 id: row.id,
00182 row: row,
00183 user: UserId
00184 }, function (retval) {
00185 if (retval.Success) {
00186 var now = new Date;
00187 $("#changes", $(".file-tab.active a").attr("href")).val(now.toISOString() + ": Edit - Path: " + path + ", Name: " + row.name + " Dialog Edit - multiple columns may have been changed!");
00188 $("#masterChanges").val(now.toISOString() + ": Edit - Path: " + path + ", Name: " + row.name + " Dialog Edit - multiple columns may have been changed!");
00189 ResizeTextAreas();
00190 UpdateHeader(false, true, "There are pending unsaved changes. Please save or discard before closing the editor!");
00191 } else {
00192 UpdateHeader(true, false, "Sending Update to server failed");
00193 }
00194 });
00195
00196 }
00197
00198 function MakeTreeGrid(tag, dataFields, data, columnGroups) {
00199 tag.html(TreeGridHtml);
00200 var grid = tag.find("#treeGrid");
00201 var contextMenu = tag.find("#Menu");
00202 var dialog = tag.find("#dialog");
00203 var newRowId = null;
00204 var displayColumns = TranslateColumns(dataFields);
00205
00206
00207 console.log("DisplayColumns is " + JSON.stringify(displayColumns));
00208 console.log("DataFields is " + JSON.stringify(dataFields));
00209
00210 var source = {
00211 dataType: "json",
00212 dataFields: dataFields,
00213 hierarchy: {
00214 root: "children"
00215 },
00216 localData: data,
00217 comment: "comment",
00218 addRow: function (rowID, rowData, position, parentID, commit) {
00219 newRowId = rowID;
00220 commit(true);
00221 }
00222 };
00223
00224 var dataAdapter = new $.jqx.dataAdapter(source, {
00225 beforeLoadComplete: function (records) {
00226 var numberFields = [];
00227 for (var c in source.dataFields) {
00228 if (source.dataFields.hasOwnProperty(c)) {
00229 if (source.dataFields[c].dataType === "number") {
00230 numberFields.push({ name: source.dataFields[c].name, radix: source.dataFields[c].radix });
00231 }
00232 }
00233 }
00234 for (var i in records) {
00235 if (records.hasOwnProperty(i)) {
00236 for (var f in numberFields) {
00237 if (numberFields.hasOwnProperty(f)) {
00238 var radix = numberFields[f].radix;
00239 if (!radix) {
00240 radix = 10;
00241 }
00242 var value = records[i][numberFields[f].name];
00243 if (value) {
00244 if (typeof value === "number" || !(value.search("0x") === 0 || value.search("0") === 0 || value.search("b") === value.length - 1)) {
00245
00246 value = parseInt(value).toString(radix).toUpperCase();
00247 records[i][numberFields[f].name] = value;
00248 if (radix === 2) {
00249 records[i][numberFields[f].name] += "b";
00250 }
00251 if (radix === 16) {
00252 records[i][numberFields[f].name] = "0x" + value;
00253 }
00254 if (radix === 8) {
00255 records[i][numberFields[f].name] = "0" + value;
00256 }
00257 }
00258 }
00259 }
00260 }
00261 }
00262 }
00263 return records;
00264 }
00265 });
00266
00267 var sequenceTables = [];
00268
00269 grid.addClass("jqxTreeGrid").jqxTreeGrid(
00270 {
00271 width: "100%",
00272 source: dataAdapter,
00273 editable: true,
00274 editSettings: { saveOnPageChange: true, saveOnBlur: true, saveOnSelectionChange: true, cancelOnEsc: true, saveOnEnter: true, editSingleCell: true, editOnDoubleClick: true, editOnF2: true },
00275 sortable: true,
00276 columnsResize: true,
00277 columns: displayColumns,
00278 columnGroups: columnGroups,
00279 rowDetails: true,
00280 rowDetailsRenderer: function (rowKey, row) {
00281 if (row.isSequence) {
00282 var indent = (1 + row.level) * 20;
00283 var details = "<div id=\"" + rowKey + "___Table\" style=\"margin-left: " + indent + "px;padding-right: 5px\"></div>";
00284 sequenceTables.push({ key: rowKey, data: row.table });
00285 return details;
00286 }
00287 return "";
00288 }
00289 ,
00290 rendered: function () {
00291 $(".jqx-tooltip").remove();
00292 var setupRow = function (rowObject) {
00293 if (rowObject[source.comment] && rowObject[source.comment].length > 0 && rowObject[source.comment] !== " ") {
00294 var selector = $("tr[data-key=\'" + rowObject.uid + "\']");
00295 if (selector.length) {
00296 selector.jqxTooltip({ content: rowObject[source.comment], position: "mouse" });
00297 }
00298 }
00299 for (var trow in rowObject.records) {
00300 if (rowObject.records.hasOwnProperty(trow)) {
00301 setupRow(rowObject.records[trow]);
00302 }
00303 }
00304 };
00305 var rows = grid.jqxTreeGrid("getRows");
00306 for (var ttrow = 0; ttrow < rows.length; ttrow++) {
00307 setupRow(rows[ttrow]);
00308 }
00309 for (var seq in sequenceTables) {
00310 if (sequenceTables.hasOwnProperty(seq)) {
00311 var elem = tag.find("#" + sequenceTables[seq].key + "___Table");
00312 var data = sequenceTables[seq].data;
00313 MakeTreeGrid(elem, data.columns, data.rows, data.columnGroups);
00314 }
00315 }
00316 },
00317 ready: function () {
00318 dialog.on("close", function () {
00319
00320 grid.jqxTreeGrid({ disabled: false });
00321 });
00322 dialog.jqxWindow({
00323 resizable: true,
00324 width: 270,
00325 position: { left: grid.offset().left + 75, top: grid.offset().top + 35 },
00326 autoOpen: false,
00327 showCloseButton: false
00328 });
00329 dialog.css("visibility", "visible");
00330 }
00331 });
00332
00333
00334 grid.jqxTreeGrid("expandAll");
00335
00336 contextMenu.jqxMenu({ width: 200, height: 90, autoOpenPopup: false, mode: "popup" });
00337 grid.on("contextmenu", function () {
00338 return false;
00339 });
00340 grid.on("rowClick", function (event) {
00341 var args = event.args;
00342 if (args.originalEvent.button === 2) {
00343 var scrollTop = $(window).scrollTop();
00344 var scrollLeft = $(window).scrollLeft();
00345
00346 if (args.row.type === "table" || args.row.type === "sequence") {
00347 contextMenu.jqxMenu("disable", "edit", true);
00348 contextMenu.jqxMenu("disable", "bitedit", true);
00349 contextMenu.jqxMenu("disable", "add", false);
00350 } else {
00351 contextMenu.jqxMenu("disable", "edit", false);
00352 contextMenu.jqxMenu("disable", "bitedit", false);
00353 contextMenu.jqxMenu("disable", "add", true);
00354 }
00355
00356 contextMenu.jqxMenu("open", parseInt(event.args.originalEvent.clientX) + 5 + scrollLeft, parseInt(event.args.originalEvent.clientY) + 5 + scrollTop);
00357 return false;
00358 }
00359 return true;
00360 });
00361 var edit = function (row, key, newRow, x, y, deleteOnCancel) {
00362 newRowId = key;
00363
00364 dialog.jqxWindow("setTitle", "Edit Row: " + row.name);
00365 dialog.jqxWindow("setContent", DialogContentHtml);
00366 dialog.jqxWindow("move", x, y);
00367 var jqEditors = [];
00368 for (var i in dataFields) {
00369 if (dataFields.hasOwnProperty(i)) {
00370 var name = dataFields[i].name;
00371 var value = "" + row[name];
00372 if (value === "undefined") {
00373 value = "";
00374 }
00375 if (dataFields[i].editable || newRow) {
00376 var start = "<tr><td align=\"right\">" + name + ":</td><td align=\"left\">";
00377 var editor = "<input id=\"" + name + "_Editor\" type=\"text\" value=\"" + value + "\" />";
00378
00379 var radixObj = GetRadix(value);
00380 if (name === "name") radixObj.radix = -1;
00381
00382 if (radixObj.radix > 0) {
00383 editor = "<div id=\"" + name + "_Editor\"><input type=\"text\" /><div></div><div></div></div>";
00384 jqEditors.push({
00385 name: name + "_Editor",
00386 value: radixObj.value,
00387 radix: radixObj.radix
00388 });
00389 }
00390 var end = "</td></tr>";
00391 dialog.find("tr:last").before(start + editor + end);
00392 } else {
00393 dialog.find("tr:last").before("<tr><td align=\"right\">" + name + ":</td><td align=\"left\"><input id=\"" + name + "_Editor\" type=\"text\" value=\"" + value + "\" readonly=\"true\" disabled=\"disabled\" /></td></tr>");
00394 }
00395 }
00396 }
00397 var content = dialog.find("table").parent().html();
00398 dialog.jqxWindow("setContent", content);
00399 for (var ed in jqEditors) {
00400 if (jqEditors.hasOwnProperty(ed)) {
00401 dialog.find("#" + jqEditors[ed].name).jqxFormattedInput({ radix: jqEditors[ed].radix, value: jqEditors[ed].value, width: "100%", height: 25, upperCase: true, dropDown: true, spinButtons: true });
00402 }
00403 }
00404 dialog.find("#save").jqxButton({ height: 30, width: 80 });
00405 dialog.find("#cancel").jqxButton({ height: 30, width: 80 });
00406 dialog.find("#save").mousedown(function () {
00407 dialog.jqxWindow("close");
00408 RowEditDialogSave(dataFields, newRowId, grid);
00409 });
00410 dialog.find("#cancel").mousedown(function () {
00411 dialog.jqxWindow("close");
00412 if(deleteOnCancel) grid.jqxTreeGrid("deleteRow", newRowId);
00413 });
00414 dialog.jqxWindow("open");
00415 var newHeight = $("#bottomOfDialog").position().top + 100;
00416 dialog.jqxWindow({ height: newHeight });
00417 dialog.attr("data-row", key);
00418
00419
00420 grid.jqxTreeGrid({ disabled: true });
00421 };
00422 var bitedit = function (row, key, x, y) {
00423 newRowId = key;
00424
00425 dialog.jqxWindow("setTitle", "Bit Editor for Row: " + row.name);
00426 dialog.jqxWindow("setContent", DialogContentHtml);
00427 dialog.jqxWindow("move", x, y);
00428 var fields = [];
00429 for (var i in dataFields) {
00430 if (dataFields.hasOwnProperty(i)) {
00431 var name = dataFields[i].name;
00432 var value = "" + row[name];
00433 if (value === "undefined") {
00434 value = "";
00435 }
00436 dialog.find("tr:last").before("<input id=\"" + name + "_Editor\" type=\"hidden\" value=\"" + value + "\" />");
00437 if (dataFields[i].editable) {
00438 var radixObj = GetRadix(value);
00439 if (radixObj.radix === 2 || radixObj.radix === 8 || radixObj.radix === 16)
00440 fields.push(name);
00441 }
00442 }
00443 }
00444
00445 var selectHtml = "<select id=bitFieldSelect>";
00446 for (var f in fields) {
00447 if (fields.hasOwnProperty(f)) {
00448 selectHtml += "<option id=" + fields[f] + " value=\"" + fields[f] + "\">" + fields[f] + "</option>";
00449 }
00450 }
00451 selectHtml += "</select>";
00452 dialog.find("tr:last").before("<tr><td colspan=\"2\" align=\"right\">" + selectHtml + "</td></tr>");
00453 dialog.find("tr:last").before('<tr><td colspan="2" align="right"><div id=bitCheckboxes></div></td></tr>');
00454
00455 var content = dialog.find("table").parent().html();
00456 dialog.jqxWindow("setContent", content);
00457 dialog.find("#bitFieldSelect").change(function () {
00458 var currentValue = dialog.find("#" + this.value + "_Editor").val();
00459 var radixObj = GetRadix(currentValue);
00460 var length = String(radixObj.value).length;
00461 var bits = 0;
00462 switch (radixObj.radix) {
00463 case 2:
00464 bits = length;
00465 break;
00466 case 8:
00467 bits = 3 * length;
00468 break;
00469 case 16:
00470 bits = 4 * length;
00471 break;
00472 }
00473
00474 var bitFieldCheckboxHtml = "<table><tr>";
00475 for (var i = 0; i < bits; ++i) {
00476 if (i > 0 && i % 4 === 0) {
00477 bitFieldCheckboxHtml += "</tr><tr>";
00478 }
00479 var checkedStr = (currentValue & (1 << i)) !== 0 ? "checked" : "";
00480 bitFieldCheckboxHtml += "<td><input type=\"checkbox\" name=\"" + i + "\" class=\"bitFieldCheckBox\"" + checkedStr + ">" + i + "</input></td>";
00481 }
00482 bitFieldCheckboxHtml += "</tr></table>";
00483 dialog.find("#bitCheckboxes").html(bitFieldCheckboxHtml);
00484 var newHeight = $("#bottomOfDialog").position().top;
00485 dialog.jqxWindow({ height: newHeight });
00486 $(".bitFieldCheckBox").change(function () {
00487 var currentValue = String(dialog.find("#" + $("#bitFieldSelect").val() + "_Editor").val());
00488 var radixObj = GetRadix(currentValue);
00489 var bitId = this.name;
00490 var digit, rem, curDigit, mask;
00491 switch (radixObj.radix) {
00492 case 2:
00493 currentValue = currentValue.substr(0, currentValue.length - bitId - 1) + (this.checked ? "1" : "0") + currentValue.substr(currentValue.length - bitId);
00494 break;
00495 case 8:
00496 digit = Math.floor(bitId / 3);
00497 rem = bitId - (digit * 3);
00498 curDigit = parseInt(currentValue.charAt(currentValue.length - digit - 1), 8);
00499 if (this.checked) {
00500 curDigit = curDigit | (1 << rem);
00501 } else {
00502 mask = 7 - (1 << rem);
00503 curDigit = curDigit & mask;
00504 }
00505 currentValue = currentValue.substr(0, currentValue.length - digit - 1) + curDigit.toString(8) + currentValue.substr(currentValue.length - digit);
00506 break;
00507 case 16:
00508 digit = Math.floor(bitId / 4);
00509 rem = bitId - (digit * 4);
00510 curDigit = parseInt(currentValue.charAt(currentValue.length - digit - 1), 16);
00511 if (this.checked) {
00512 curDigit = curDigit | (1 << rem);
00513 } else {
00514 mask = 15 - (1 << rem);
00515 curDigit = curDigit & mask;
00516 }
00517 currentValue = currentValue.substr(0, currentValue.length - digit - 1) + curDigit.toString(16) + currentValue.substr(currentValue.length - digit);
00518 break;
00519 }
00520 dialog.find("#" + $("#bitFieldSelect").val() + "_Editor").val(currentValue);
00521 });
00522 }).trigger("change");
00523 dialog.find("#save").jqxButton({ height: 30, width: 80 });
00524 dialog.find("#cancel").jqxButton({ height: 30, width: 80 });
00525 dialog.find("#save").mousedown(function () {
00526 dialog.jqxWindow("close");
00527 RowEditDialogSave(dataFields, newRowId, grid);
00528 });
00529 dialog.find("#cancel").mousedown(function () {
00530 dialog.jqxWindow("close");
00531 });
00532 dialog.jqxWindow("open");
00533 var newHeight = $("#bottomOfDialog").position().top;
00534 dialog.jqxWindow({ height: newHeight });
00535 dialog.attr("data-row", key);
00536
00537
00538 grid.jqxTreeGrid({ disabled: true });
00539 };
00540 contextMenu.on("itemclick", function (event) {
00541 var args = event.args;
00542 var selection = grid.jqxTreeGrid("getSelection");
00543 var rowid = selection[0].uid;
00544 var text = $.trim($(args).text());
00545 if (text === "Edit Selected Row") {
00546 edit(selection[0], rowid, false, event.pageX, event.pageY, false);
00547 } else if (text === "Bit Editor") {
00548 bitedit(selection[0], rowid, event.pageX, event.pageY);
00549 } else {
00550 var arrayName = false;
00551 if (("" + rowid).search(/___/) > 0) {
00552 arrayName = true;
00553 }
00554 grid.jqxTreeGrid("addRow", null, {}, "last", rowid);
00555 if (arrayName) {
00556 var idx = newRowId.search(/___/);
00557 var num = newRowId.slice(idx + 3, -1);
00558 num = parseInt(num) + 1;
00559 newRowId = newRowId.slice(0, idx + 3) + num;
00560 }
00561 var obj = {};
00562 for (var i in dataFields) {
00563 if (dataFields.hasOwnProperty(i)) {
00564 obj[dataFields[i].name] = "";
00565 }
00566 }
00567 obj.name = newRowId;
00568 edit(obj, newRowId, true, event.pageX, event.pageY, true);
00569 }
00570 });
00571
00572
00573 grid.on("cellEndEdit", function (event) {
00574 var args = event.args;
00575
00576 var rowKey = args.key;
00577
00578 var rowData = args.row;
00579 var path = rowData.name;
00580 var currentName = rowKey;
00581 var parent = rowData.parent;
00582 var first = true;
00583 do {
00584 if ((parent === null || parent === undefined) && currentName.indexOf("___") >= 0) {
00585 var parentSelector = tag.selector.split(" ").slice(0, -1).join(" ");
00586 var parentRow = $(parentSelector + " #treeGrid").jqxTreeGrid("getRow", currentName.slice(0, -4));
00587 parent = parentRow[0];
00588 while ((parent !== null && parent !== undefined) && parent.constructor === Array) {
00589 parent = parent[0];
00590 }
00591 }
00592 else if ((parent === null || parent === undefined) && rowData.name.indexOf("___") >= 0 && first) {
00593 first = false;
00594 var parentSelector = tag.selector.split(" ").slice(0, -1).join(" ");
00595 var parentName = tag.selector.split(" ").slice(-1).join(" ").slice(1);
00596 parentName = parentName.slice(0, parentName.indexOf("___"));
00597 var parentRow = $(parentSelector + " #treeGrid").jqxTreeGrid("getRow", parentName);
00598 parent = parentRow[0];
00599 while ((parent !== null && parent !== undefined) && parent.constructor === Array) {
00600 parent = parent[0];
00601 }
00602 }
00603
00604 if (parent !== null && parent !== undefined) {
00605 currentName = parent.name;
00606 path = parent.name + "/" + path;
00607 parent = parent.parent;
00608 }
00609 } while (parent !== null && parent !== undefined);
00610
00611 if (CurrentCollection && CurrentEntity) {
00612 path = CurrentCollection + "/" + CurrentEntity + "/" + path;
00613 } else {
00614 var pathTmp = path.split('/');
00615 var collection = pathTmp.shift();
00616 var entity = pathTmp.shift();
00617 var collectionTab = $(".collection-tab[collection-name=\"" + collection + "\"] a");
00618 collectionTab.trigger("click");
00619 var fileNameTab = $(collectionTab[0].hash).find(".file-tab[file-name=\"" + entity + "\"] a");
00620 fileNameTab.trigger("click");
00621 $("li.active :visible").parent().addClass("editedValue");
00622 $(".configInfo-tab a").trigger("click");
00623 CurrentCollection = collection;
00624 CurrentEntity = entity;
00625 }
00626 console.log("Path is " + path);
00627
00628 var columnDataField = args.dataField;
00629
00630 var columnName = args.dataField;
00631 for (var i in args.owner._columns) {
00632 if (args.owner._columns.hasOwnProperty(i)) {
00633 if (args.owner._columns[i].dataField === columnName) {
00634 columnName = args.owner._columns[i].text;
00635 break;
00636 }
00637 }
00638 }
00639 EditedValues[CurrentCollection + "/" + CurrentEntity + "/" + rowKey] = true;
00640 $("li.active :visible").parent().addClass("editedValue");
00641 $(".configInfo-tab").removeClass("editedValue");
00642
00643 var value = args.value;
00644
00645 AjaxPost("/db/Update", {
00646 configName: CurrentNamedConfig,
00647 table: path,
00648 column: columnDataField,
00649 id: rowData.id,
00650 name: rowData.name,
00651 value: value,
00652 user: UserId
00653 }, function (retval) {
00654 if (retval.Success) {
00655 var now = new Date;
00656 var selector = $("#changes", $(".file-tab.active a").attr("href"));
00657 selector.val(now.toISOString() + ": Edit - File: " + CurrentCollection + "/" + CurrentEntity + ", Name: " + rowData.name + ", Column: " + columnName + ", Value: " + value + "\n" + selector.val());
00658 $("#masterChanges").val(now.toISOString() + ": Edit - File: " + CurrentCollection + "/" + CurrentEntity + ", Name: " + rowData.name + ", Column: " + columnName + ", Value: " + value + "\n" + $("#masterChanges").val());
00659 UpdateHeader(false, true, "There are pending unsaved changes. Please save or discard before closing the editor!");
00660 } else {
00661 UpdateHeader(true, false, "Sending Update to server failed");
00662 }
00663 });
00664 });
00665 };
00666
00667 function CellClass(row, dataField, cellText, rowData) {
00668 var edited = false;
00669 for (var val in EditedValues) {
00670 if (EditedValues.hasOwnProperty(val)) {
00671 if (val === CurrentCollection + "/" + CurrentEntity + "/" + rowData.uid) {
00672 edited = EditedValues[val];
00673 break;
00674 }
00675 }
00676 }
00677 if (edited) {
00678 return "editedValue";
00679 }
00680 return "value";
00681 };
00682
00683 function TranslateColumns(columns) {
00684 var displayColumns = [];
00685
00686 for (var c in columns) {
00687 if (columns.hasOwnProperty(c)) {
00688 var title = columns[c].title;
00689 if (title === undefined || title === null || title.length === 0) {
00690 title = columns[c].name.charAt(0).toUpperCase() + columns[c].name.slice(1);
00691 }
00692 if (columns[c].type === "string" && columns[c].display) {
00693 displayColumns.push({
00694 text: title,
00695 dataField: columns[c].name,
00696 editable: columns[c].editable,
00697 columnGroup: columns[c].columnGroup,
00698 createEditor: CreateRowEditor,
00699 initEditor: InitRowEditor,
00700 getEditorValue: GetRowEditorValue,
00701 cellClassName: CellClass
00702 });
00703 } else if (columns[c].type === "number" && columns[c].display) {
00704 columns[c].type = "string";
00705 columns[c].dataType = "number";
00706 displayColumns.push({
00707 text: title,
00708 dataField: columns[c].name,
00709 editable: columns[c].editable,
00710 columnGroup: columns[c].columnGroup,
00711 createEditor: CreateRowEditor,
00712 initEditor: InitRowEditor,
00713 getEditorValue: GetRowEditorValue,
00714 cellClassName: CellClass
00715 });
00716 }
00717 }
00718 }
00719 return displayColumns;
00720 }
00721
00722 function LoadTable(tag) {
00723
00724 AjaxPost("/db/GetData", { configName: CurrentNamedConfig, entity: CurrentEntity, collection: CurrentCollection, user: UserId }, function (data) {
00725 if (!data.Success) {
00726 UpdateHeader(true, false, "Fetch of data from database failed");
00727 return;
00728 }
00729 var columns = data.data.columns;
00730
00731 MakeTreeGrid(tag, columns, data.data.children);
00732
00733 });
00734 };
00735
00736 function SetupConfigVersionPicker(element, target) {
00737
00738 element.on("change", function () {
00739 var thisConfig = element.find(":selected").text();
00740 var configVersionHtml = "";
00741 for (var version in ConfigVersionData[thisConfig]) {
00742 if (ConfigVersionData[thisConfig].hasOwnProperty(version)) {
00743 configVersionHtml += "<option name=\"" + ConfigVersionData[thisConfig][version].name
00744 + "\" value=" + ConfigVersionData[thisConfig][version].data + ">" + ConfigVersionData[thisConfig][version].version + "</option>";
00745 }
00746 }
00747 $("#" + target).html(configVersionHtml).trigger("create").selectmenu("refresh");
00748 $("#" + target).html($("#" + target + " option").sort(function (a, b) {
00749 return parseInt(a.text) === parseInt(b.text) ? 0 : parseInt(a.text) > parseInt(b.text) ? -1 : 1;
00750 }));
00751 var option = $("#" + target).find('option:eq(0)');
00752 option.prop('selected', true);
00753 $("#"+target).trigger("create").selectmenu("refresh");
00754 });
00755 }
00756
00757 function GetConfigList() {
00758 UpdateHeader(false, false, "");
00759 $("#masterChanges").val("");
00760 ResizeTextAreas();
00761 for (var i = 2; i <= LastTabId; i++) {
00762 $("#tab" + i).remove();
00763 $("#tablink" + i).remove();
00764 }
00765
00766 $("#reloadConfigsButton").text("Reload Configurations");
00767
00768
00769 AjaxPost("/db/NamedConfigs", { configFilter: $("#configurationFilter").val(), user: UserId }, function (data) {
00770 if (!data.Success) {
00771 UpdateHeader(true, false, "Error retrieving Configuration list. Please contact an expert!");
00772 return;
00773 }
00774 var configsHtml = "";
00775 for (var name in data.data) {
00776 if (data.data.hasOwnProperty(name)) {
00777 configsHtml += "<option>" + name + "</option>";
00778 ConfigVersionData[name] = data.data[name];
00779 }
00780 }
00781 $("#configs").html(configsHtml).trigger("create").selectmenu("refresh");
00782 $("#oldConfigName").html(configsHtml).trigger("create").selectmenu("refresh");
00783 $("#exportConfigName").html(configsHtml).trigger("create").selectmenu("refresh");
00784
00785 SetupConfigVersionPicker($("#configs"), "configversions");
00786 $("#configs").trigger("change");
00787 SetupConfigVersionPicker($("#oldConfigName"), "oldConfigVersion");
00788 $("#oldConfigName").trigger("change");
00789 SetupConfigVersionPicker($("#exportConfigName"), "exportConfigVersion");
00790 $("#exportConfigName").trigger("change");
00791
00792 var config = GetUrlParameter("configs");
00793 if (config !== undefined) {
00794 $("#configs").val(config);
00795 }
00796 });
00797 $("#configLoad").collapsible("option", "disabled", false).collapsible("option", "collapsed", false);
00798 $("#configSave").collapsible("option", "disabled", true).collapsible("option", "collapsed", true);
00799 $("#configMetadata").collapsible("option", "disabled", true).collapsible("option", "collapsed", true);
00800 $("#searchConfig").collapsible("option", "disabled", false);
00801 $("#exportFile").collapsible("option", "collapsed", true);
00802 $("#newConfig").collapsible("option", "collapsed", true);
00803 };
00804
00805 function RegisterTabFunctions() {
00806 $(".file-tab a").off();
00807 $(".collection-tab a").off();
00808 $(".tabs .tab-links a").off().on("click", function (e) {
00809 var currentAttrValue = $(this).attr("href");
00810 var tab = $(this).parent();
00811 var div = tab.parent();
00812 div.scrollLeft(0);
00813 var left = Math.floor(tab.position().left - 20);
00814 div.scrollLeft(left);
00815
00816 $(".tabs " + currentAttrValue).show().siblings().hide();
00817
00818
00819 $(this).parent("li").addClass("active").siblings().removeClass("active");
00820
00821 e.preventDefault();
00822 });
00823 $(".configInfo-tab a").on("click", function () {
00824 CurrentCollection = null;
00825 CurrentEntity = null;
00826 });
00827 $(".collection-tab a").on("click", function () {
00828 CurrentCollection = $(this).text();
00829 });
00830 $(".file-tab a").on("click", function () {
00831 var fileName = $(this).text();
00832 CurrentEntity = fileName;
00833 LoadFile($(this).attr("href"));
00834 ResizeTextAreas();
00835 });
00836 };
00837
00838 function GetUrlParameter(sParam) {
00839 var sUrlVariables = window.location.search.substring(1).split("&");
00840
00841 for (var i = 0; i < sUrlVariables.length; i++) {
00842 var sParameterName = sUrlVariables[i].split("=");
00843
00844 if (sParameterName[0].search(sParam) >= 0) {
00845
00846 return sParameterName[1];
00847 }
00848 }
00849 return "";
00850 };
00851
00852 function LoadConfigMetadata() {
00853 console.log("Loading configuration metadata");
00854
00855 AjaxPost("/db/LoadConfigMetadata", { configName: CurrentNamedConfig, user: UserId }, function (metadata) {
00856 if (!metadata.Success) {
00857 UpdateHeader(true, false, "Error loading configuration metadata from database");
00858 return;
00859 }
00860 var metadataObj = metadata.data;
00861
00862
00863 var displayColumns = [
00864 {
00865 text: "Entity Name",
00866 dataField: "name",
00867 editable: false
00868 },
00869 {
00870 text: "Collection Name",
00871 dataField: "collection",
00872 editable: false
00873 },
00874 {
00875 text: "Version",
00876 dataField: "version",
00877 editable: false
00878 },
00879 {
00880 text: "Edit", cellsAlign: "center", align: "center", columnType: "none", editable: false, sortable: false, dataField: null, cellsRenderer: function (row) {
00881
00882 return "<button data-row='" + row + "' class='editButtons' onclick=''>Edit</button>";
00883 }
00884 }
00885 ];
00886 var dataFields = [
00887 { name: "name", type: "string", editable: false, display: true },
00888 { name: "collection", type: "string", editable: false, display: true },
00889 { name: "file", type: "string", editable: false, display: false },
00890 { name: "version", type: "string", editable: false, display: true }
00891 ];
00892 var source = {
00893 dataType: "json",
00894 dataFields: dataFields,
00895 id: "file",
00896 hierarchy: {
00897 root: "values"
00898 },
00899 localData: metadataObj.entities
00900 };
00901
00902 var dataAdapter = new $.jqx.dataAdapter(source);
00903
00904 var grid = $("#configurationEntities");
00905 grid.addClass("jqxTreeGrid").jqxTreeGrid(
00906 {
00907 width: "100%",
00908 source: dataAdapter,
00909 editable: false,
00910 sortable: true,
00911 columnsResize: true,
00912 columns: displayColumns,
00913 rendering: function () {
00914
00915 if ($(".editButtons").length > 0) {
00916 $(".editButtons").jqxButton("destroy");
00917 }
00918 },
00919 rendered: function () {
00920 if ($(".editButtons").length > 0) {
00921 $(".editButtons").jqxButton();
00922
00923 var editClick = function (event) {
00924
00925 var rowKey = event.target.getAttribute("data-row");
00926 var row = grid.jqxTreeGrid("getRow", rowKey);
00927 var collection = row["collection"];
00928 var collectionTab = $(".collection-tab[collection-name=\"" + collection + "\"] a");
00929 collectionTab.trigger("click");
00930 var file = row["name"];
00931 var fileNameTab = $(collectionTab[0].hash).find(".file-tab[file-name=\"" + file + "\"] a");
00932 fileNameTab.trigger("click");
00933 };
00934 $(".editButtons").on("click", function (event) {
00935 editClick(event);
00936 return false;
00937 });
00938
00939 }
00940 }
00941 });
00942 });
00943 };
00944
00945 function AddEntityToFile(id) {
00946 var newEntityName = $(id + " #newEntityName").val();
00947 $(id + " #newEntityName").val("");
00948 if (newEntityName !== "") {
00949 AjaxPost("/db/AddEntityToFile", { configName: CurrentNamedConfig, entity: CurrentEntity, collection: CurrentCollection, user: UserId, name: newEntityName }, function (res) {
00950 if (res.Success) {
00951 LoadFile(id);
00952 }
00953 else {
00954 UpdateHeader(true, false, "Error adding Entity to configuration file");
00955 }
00956 });
00957 }
00958 }
00959
00960 function LoadFile(id) {
00961
00962 AjaxPost("/db/LoadFileMetadata", { configName: CurrentNamedConfig, entity: CurrentEntity, collection: CurrentCollection, user: UserId }, function (metadata) {
00963 if (!metadata.Success) {
00964 UpdateHeader(true, false, "Error loading file metadata from database");
00965 return;
00966 }
00967 console.log("Loading file metadata");
00968 var metadataObj = metadata.data;
00969 console.log(metadata);
00970 $(id + " #metadataCollection").val(metadataObj.collection);
00971 $(id + " #metadataVersion").val(metadataObj.version);
00972 $(id + " #changeLog").val(metadataObj.changelog);
00973
00974 var displayColumns = [
00975 {
00976 text: "Name",
00977 dataField: "name",
00978 editable: false
00979 },
00980 {
00981 text: "Date Assigned",
00982 dataField: "assigned",
00983 editable: false
00984 }
00985 ];
00986 var dataFields = [
00987 { name: "name", type: "string", editable: false, display: true },
00988 { name: "assigned", type: "date", editable: false, display: true }
00989 ];
00990 var entitiesSource = {
00991 dataType: "json",
00992 dataFields: dataFields,
00993 id: "name",
00994 hierarchy: {
00995 root: "values"
00996 },
00997 localData: metadataObj.entities
00998 };
00999
01000 var entitiesDataAdapter = new $.jqx.dataAdapter(entitiesSource);
01001
01002 $(id + " #metadataEntities").addClass("jqxTreeGrid").jqxTreeGrid(
01003 {
01004 width: "100%",
01005 source: entitiesDataAdapter,
01006 editable: false,
01007 sortable: true,
01008 columnsResize: true,
01009 columns: displayColumns
01010 });
01011 var configsSource = {
01012 dataType: "json",
01013 dataFields: dataFields,
01014 id: "name",
01015 hierarchy: {
01016 root: "values"
01017 },
01018 localData: metadataObj.configurations
01019 };
01020
01021 var configsDataAdapter = new $.jqx.dataAdapter(configsSource);
01022
01023 $(id + " #metadataConfigurations").addClass("jqxTreeGrid").jqxTreeGrid(
01024 {
01025 width: "100%",
01026 source: configsDataAdapter,
01027 editable: false,
01028 sortable: true,
01029 columnsResize: true,
01030 columns: displayColumns
01031 });
01032 LoadTable($(id + " #fileTable"));
01033 });
01034 };
01035
01036 function SearchCurrentConfig() {
01037 console.log("Searching Configuration");
01038
01039 var searchKey = $("#searchKey").val();
01040 console.log("SearchKey is " + searchKey);
01041
01042 AjaxPost("/db/SearchLoadedConfig", { configName: CurrentNamedConfig, user: UserId, searchKey: searchKey }, function (results) {
01043 if (!results.Success) {
01044 UpdateHeader(true, false, "Error searching configuration");
01045 return;
01046 }
01047
01048 MakeTreeGrid($("#searchResults"), results.columns, results.collections);
01049 });
01050 }
01051
01052 function LoadConfig() {
01053 console.log("Loading Configuration");
01054 $("#masterChanges").val("");
01055 UpdateHeader(false, false, "");
01056 var selected = $("#configversions").find(":selected");
01057 if (selected.text() === "No Configurations Found" || selected.text() === "Click \"Load Configurations\" To Load Configuration Names") { return; }
01058 CurrentNamedConfig = selected.attr("name");
01059 $("#configName").val(CurrentNamedConfig);
01060 for (var i = 2; i <= LastTabId; i++) {
01061 $("#tab" + i).remove();
01062 $("#tablink" + i).remove();
01063 }
01064 LastTabId = 1;
01065
01066 AjaxPost("/db/LoadNamedConfig", { configName: CurrentNamedConfig, query: selected.val(), user: UserId }, function (config) {
01067 if (!config.Success) {
01068 UpdateHeader(true, false, "Error loading configuration files from database");
01069 return;
01070 }
01071 ResizeTextAreas();
01072 for (var collection in config.collections) {
01073 if (config.collections.hasOwnProperty(collection)) {
01074 LastTabId++;
01075 var parentTab = LastTabId;
01076 $("#tabLinks").append("<li id=\"tablink" + LastTabId + "\"collection-name=\"" + config.collections[collection].name + "\" tabNum=\"" + LastTabId + "\" class=\"collection-tab\"><a href=\"#tab" + LastTabId + "\">" + config
01077 .collections[collection].name + "</a></li>");
01078 $("#tabContents").append("<div id=tab" + LastTabId + " class=\"tab\"></div>");
01079 $("#tab" + LastTabId).html(TableHtml);
01080
01081 for (var file in config.collections[collection].files) {
01082 if (config.collections[collection].files.hasOwnProperty(file)) {
01083 var name = config.collections[collection].files[file];
01084
01085 LastTabId++;
01086 $("#tab" + parentTab + " #tabLinks").append("<li id=\"tablink" + LastTabId + "\" file-name=\"" + name + "\" tabNum=\"" + LastTabId + "\" class=\"file-tab\"><a href=\"#tab" + LastTabId + "\">" + name + "</a></li>");
01087 $("#tab" + parentTab + " #tabContents").append("<div id=tab" + LastTabId + " class=\"tab\"></div>");
01088 $("#tab" + LastTabId).html(InfoHtml).trigger("create");;
01089 }
01090 }
01091 }
01092 }
01093 $("#configLoad").collapsible("option", "disabled", false).collapsible("option", "collapsed", true);
01094 $("#configSave").collapsible("option", "disabled", false).collapsible("option", "collapsed", false);
01095 LoadConfigMetadata();
01096 $("#configMetadata").collapsible("option", "disabled", false).collapsible("option", "collapsed", false);
01097 $("#searchConfig").collapsible("option", "disabled", false);
01098 RegisterTabFunctions();
01099 });
01100 };
01101
01102 function BaseConfig() {
01103
01104 AjaxPost("/db/LoadConfigMetadata", { configName: $("#oldConfigName :selected").text(), user: UserId }, function (metadata) {
01105 if (!metadata.Success) {
01106 UpdateHeader(true, false, "Error loading configuration metadata from database");
01107 return;
01108 }
01109 var metadataObj = metadata.data;
01110
01111
01112 $("#newConfigName").val($("#oldConfigName :selected").text());
01113 var tag = $("#configurationPicker");
01114 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01115 for (var r in rows) {
01116 if (rows.hasOwnProperty(r)) {
01117 var thisRow = rows[r];
01118 var isChecked = false;
01119 for (var e in metadataObj.entities) {
01120 if (isChecked) break;
01121 if (metadataObj.entities.hasOwnProperty(e)) {
01122 var entity = metadataObj.entities[e];
01123 if (thisRow.name === entity.collection) {
01124 for (var r in thisRow.records) {
01125 if (thisRow.records.hasOwnProperty(r)) {
01126 var record = thisRow.records[r];
01127 if (record.id === entity.collection + entity.name) {
01128 tag.find("#grid").jqxTreeGrid("updateRow", record.uid, { name: entity.name, version: entity.version });
01129 tag.find("#grid").jqxTreeGrid("checkRow", record.uid);
01130 isChecked = true;
01131 break;
01132 }
01133 }
01134 }
01135 }
01136 }
01137 }
01138 if (!isChecked && thisRow.checked) {
01139 tag.find("#grid").jqxTreeGrid("uncheckRow", thisRow.uid);
01140 }
01141 }
01142 }
01143 });
01144 };
01145
01146 function BaseExportConfig() {
01147
01148 AjaxPost("/db/LoadConfigMetadata", { configName: $("#exportConfigName :selected").text(), user: UserId }, function (metadata) {
01149 if (!metadata.Success) {
01150 UpdateHeader(true, false, "Error loading configuration metadata from database");
01151 return;
01152 }
01153 ExportTarFileName = $("#exportConfigName :selected").text();
01154 var metadataObj = metadata.data;
01155
01156
01157 var tag = $("#filePicker");
01158 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01159 for (var r in rows) {
01160 if (rows.hasOwnProperty(r)) {
01161 var thisRow = rows[r];
01162 var isChecked = false;
01163 for (var e in metadataObj.entities) {
01164 if (isChecked) break;
01165 if (metadataObj.entities.hasOwnProperty(e)) {
01166 var entity = metadataObj.entities[e];
01167 if (thisRow.name === entity.collection) {
01168 for (var r in thisRow.records) {
01169 if (thisRow.records.hasOwnProperty(r)) {
01170 var record = thisRow.records[r];
01171 if (record.id === entity.collection + entity.name) {
01172 tag.find("#grid").jqxTreeGrid("updateRow", record.uid, { name: entity.name, version: entity.version });
01173 tag.find("#grid").jqxTreeGrid("checkRow", record.uid);
01174 isChecked = true;
01175 break;
01176 }
01177 }
01178 }
01179 }
01180 }
01181 }
01182 if (!isChecked && thisRow.checked) {
01183 tag.find("#grid").jqxTreeGrid("uncheckRow", thisRow.uid);
01184 }
01185 }
01186 }
01187
01188 });
01189 };
01190
01191 function SaveNewConfig() {
01192 console.log("Saving New Configuration");
01193 var tag = $("#configurationPicker");
01194 var rows = tag.find("#grid").jqxTreeGrid("getCheckedRows");
01195 var configObj = {
01196 entities: []
01197 };
01198
01199 for (var r in rows) {
01200 if (rows.hasOwnProperty(r) &&
01201 (typeof rows[r].collection !== "undefined" && rows[r].collection.length > 0) &&
01202 (typeof rows[r].version !== "undefined" && rows[r].version.length > 0)) {
01203 configObj.entities.push({ name: rows[r].name, version: rows[r].version, collection: rows[r].collection });
01204 }
01205 }
01206
01207
01208 AjaxPost("/db/MakeNewConfig", { user: UserId, config: JSON.stringify(configObj), name: $("#newConfigName").val() }, function (retval) {
01209 if (retval.Success) {
01210 $("#newConfig").collapsible("option", "collapsed", true);
01211 GetConfigList();
01212 } else {
01213 UpdateHeader(true, false, "MakeNewConfig operation failed.");
01214 }
01215 });
01216 };
01217
01218 function ExportFiles() {
01219 console.log("Exporting Files");
01220 var tag = $("#filePicker");
01221 var rows = tag.find("#grid").jqxTreeGrid("getCheckedRows");
01222 var configObj = {
01223 entities: []
01224 };
01225
01226 for (var r in rows) {
01227 if (rows.hasOwnProperty(r) &&
01228 (typeof rows[r].collection !== "undefined" && rows[r].collection.length > 0) &&
01229 (typeof rows[r].version !== "undefined" && rows[r].version.length > 0)) {
01230 configObj.entities.push({ name: rows[r].name, version: rows[r].version, collection: rows[r].collection });
01231 }
01232 }
01233
01234
01235 var xhr = new XMLHttpRequest();
01236 xhr.open("POST", "/db/DownloadConfigurationFile", true);
01237 xhr.responseType = "arraybuffer";
01238 xhr.onload = function () {
01239 if (this.status === 200) {
01240 var filename = "";
01241 var disposition = xhr.getResponseHeader("Content-Disposition");
01242 if (disposition && disposition.indexOf("attachment") !== -1) {
01243 var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
01244 var matches = filenameRegex.exec(disposition);
01245 if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, "");
01246 }
01247 var type = xhr.getResponseHeader("Content-Type");
01248
01249 var blob = new Blob([this.response], { type: type });
01250 if (typeof window.navigator.msSaveBlob !== "undefined") {
01251 // IE workaround for "HTML7007: One or more blob URLs were revoked by closing the blob for which they were created. These URLs will no longer resolve as the data backing the URL has been freed."
01252 window.navigator.msSaveBlob(blob, filename);
01253 } else {
01254 var url = window.URL || window.webkitURL;
01255 var downloadUrl = url.createObjectURL(blob);
01256
01257 if (filename) {
01258 // use HTML5 a[download] attribute to specify filename
01259 var a = document.createElement("a");
01260 // safari doesn't support this yet
01261 if (typeof a.download === "undefined") {
01262 window.location = downloadUrl;
01263 } else {
01264 a.href = downloadUrl;
01265 a.download = filename;
01266 document.body.appendChild(a);
01267 a.click();
01268 }
01269 } else {
01270 window.location = downloadUrl;
01271 }
01272
01273 setTimeout(function () { url.revokeObjectURL(downloadUrl); }, 100); // cleanup
01274 }
01275 } else if (this.status === 500) {
01276 UpdateHeader(true, false, "An error occurred on the server. Contact an expert if the situation persists");
01277 }
01278 };
01279 xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
01280 xhr.send($.param({ user: UserId, config: JSON.stringify(configObj), tarFileName: ExportTarFileName, type: $("#exportFileFormat :selected").val() }));
01281 ExportTarFileName = "export";
01282 };
01283
01284 function AddRowToFileUploader() {
01285 $("#fileUploader").find("#grid").jqxTreeGrid("addRow", null, {});
01286 }
01287
01288 function SetupFileUploadTable(tag) {
01289 var displayColumns = [
01290 {
01291 text: "File",
01292 dataField: "fileName",
01293 editable: true,
01294 cellClassName: CellClass,
01295 columntype: "template",
01296 initEditor: function (row, cellvalue, editor) {
01297 if (cellvalue === "" || cellvalue === "undefined" || !cellvalue) {
01298 editor.html("<input type=\"file\" id=\"fileName\"/>");
01299 } else {
01300 editor.text(cellvalue);
01301 }
01302 },
01303 getEditorValue: function (row, cellvalue, editor) {
01304
01305 if (cellvalue === "" || cellvalue === "undefined" || !cellvalue) {
01306 var fileName = editor.find("#fileName")[0];
01307 UploadFiles[row] = fileName.files[0];
01308 return fileName.files[0].name;
01309 }
01310 return cellvalue;
01311 }
01312 },
01313 {
01314 text: "File Type",
01315 dataField: "fileType",
01316 editable: true,
01317 cellClassName: CellClass,
01318 columntype: "template",
01319 initEditor: function (row, cellvalue, editor) {
01320
01321 var versionsAdapter = new $.jqx.dataAdapter({ datatype: "array", datafields: [{ name: "name", type: "string" }, { name: "value", type: "string" }], localdata: [{ name: "FHiCL", value: "fhicl" }, { name: "JSON", value: "json" }] }, { autoBind: true });
01322 editor.jqxDropDownList({ source: versionsAdapter, displayMember: "name", valueMember: "value", selectedIndex: 0 }).jqxDropDownList("refresh");
01323
01324 editor.jqxDropDownList("selectItem", cellvalue);
01325 },
01326 getEditorValue: function (row, cellvalue, editor) {
01327
01328 return editor.val();
01329 }
01330 },
01331 {
01332 text: "Collection",
01333 dataField: "collection",
01334 editable: true,
01335 cellClassName: CellClass
01336 },
01337 {
01338 text: "Entity Name",
01339 dataField: "entity",
01340 editable: true,
01341 cellClassName: CellClass
01342 },
01343 {
01344 text: "Version",
01345 dataField: "version",
01346 editable: true,
01347 cellClassName: CellClass
01348 },
01349 {
01350 text: "Remove", cellsAlign: "center", align: "center", columnType: "none", editable: false, sortable: false, dataField: null, cellsRenderer: function (row) {
01351
01352 return "<button data-row='" + row + "' class='removeButtons' onclick=''>Remove</button>";
01353 }
01354 }
01355 ];
01356
01357 tag.html("<div id=\"grid\" class=\"jqxTreeGrid\"></div><br>");
01358
01359 var dataFields = [
01360 { name: "id", type: "string", editable: false, display: false },
01361 { name: "fileName", type: "string", editable: true, display: true },
01362 { name: "fileType", type: "string", editable: true, display: true },
01363 { name: "collection", type: "string", editable: true, display: true },
01364 { name: "entity", type: "string", editable: true, display: true },
01365 { name: "version", type: "string", editable: true, display: true }
01366 ];
01367 var source = {
01368 dataType: "json",
01369 dataFields: dataFields,
01370 id: "id",
01371 hierarchy: {
01372 root: "entities"
01373 },
01374 localData: {}
01375 };
01376
01377 var dataAdapter = new $.jqx.dataAdapter(source);
01378
01379 tag.find("#grid").jqxTreeGrid({
01380 width: "100%",
01381 source: dataAdapter,
01382 sortable: true,
01383 editable: true,
01384 columnsResize: true,
01385 columns: displayColumns,
01386 rendering: function () {
01387
01388 if ($(".removeButtons").length > 0) {
01389 $(".removeButtons").jqxButton("destroy");
01390 }
01391 },
01392 rendered: function () {
01393 if ($(".removeButtons").length > 0) {
01394 $(".removeButtons").jqxButton();
01395
01396 var removeClick = function (event) {
01397
01398 var rowKey = event.target.getAttribute("data-row");
01399 delete UploadFiles[rowKey];
01400 tag.find("#grid").jqxTreeGrid("deleteRow", rowKey);
01401 };
01402 $(".removeButtons").on("click", function (event) {
01403 removeClick(event);
01404 return false;
01405 });
01406
01407 }
01408 }
01409 });
01410 }
01411
01412 function SetupReader(file) {
01413 var f = UploadFiles[file];
01414 var r = new FileReader();
01415 r.fileid = file;
01416 r.onload = function (e) {
01417 var contents = e.target.result;
01418 var thisfile = e.target.fileid;
01419 var row = $("#fileUploader").find("#grid").jqxTreeGrid("getRow", thisfile);
01420 console.log("Calling AjaxPost with parameters: Collection: " +
01421 row.collection +
01422 ", Version: " +
01423 row.version +
01424 ", Entity: " +
01425 row.entity +
01426 ", Type: " +
01427 row.fileType + ", fileName: " + row.fileName + ", file.name: " + f.name);
01428
01429
01430 AjaxPost("/db/UploadConfigurationFile",
01431 {
01432 file: contents,
01433 collection: row.collection,
01434 version: row.version,
01435 entity: row.entity,
01436 user: UserId,
01437 type: row.fileType
01438 },
01439 function (res) {
01440 if (!res.Success) {
01441 UpdateHeader(true, false, "File upload failed");
01442 } else {
01443 console.log("Upload: " + row.fileName + " returned: " + JSON.stringify(res));
01444 }
01445 delete UploadFiles[thisfile];
01446 });
01447 };
01448 r.readAsText(f);
01449 }
01450
01451 function UploadFhiclFile() {
01452 $("#uploadFhiclFileButton").text("Uploading... Please Wait.");
01453
01454 var didAnything = false;
01455 for (var file in UploadFiles) {
01456 if (UploadFiles.hasOwnProperty(file)) {
01457 didAnything = true;
01458 var f = UploadFiles[file];
01459
01460 var row = $("#fileUploader").find("#grid").jqxTreeGrid("getRow", file);
01461 if (!f) {
01462 alert("Failed to load file");
01463 continue;
01464 }
01465
01466 if (row.fileType === "fhicl" && f.name.search(".fcl") === -1) {
01467 alert(f.name + " is not a valid fhicl file.");
01468 continue;
01469 }
01470
01471 if (row.fileType === "json" && f.name.search(".json") === -1) {
01472 alert(f.name + " is not a valid json file.");
01473 continue;
01474 }
01475
01476 if ((row.fileType !== "fhicl" &&
01477 row.fileType !== "json") ||
01478 row.collection === "" ||
01479 row.version === "" ||
01480 row.entity === "") {
01481 alert(f.name + " missing needed metadata");
01482 continue;
01483 }
01484
01485 SetupReader(file);
01486 }
01487 break;
01488 }
01489
01490 if (!didAnything) {
01491 $("#uploadFile").collapsible("option", "collapsed", true);
01492 $("#uploadFhiclFileButton").text("Store File(s) In Database");
01493 } else {
01494 setTimeout(function () { UploadFhiclFile(); }, 1000);
01495 }
01496 };
01497
01498 function SetupEntityVersionPicker(tag) {
01499
01500 AjaxGet("/db/EntitiesAndVersions", function (data) {
01501 console.log(JSON.stringify(data));
01502 if (!data.Success) {
01503 UpdateHeader(true, false, "Error retrieving entities and versions lists. Please contact an expert!");
01504 return;
01505 }
01506 var collectionsObj = data.collections;
01507 var dataObj = [];
01508 var collectionNames = [];
01509 for (var c in collectionsObj) {
01510 if (collectionsObj.hasOwnProperty(c)) {
01511 var collection = [];
01512 var entitiesObj = collectionsObj[c];
01513 for (var e in entitiesObj.entities) {
01514 if (entitiesObj.entities.hasOwnProperty(e)) {
01515 var entity = entitiesObj.entities[e];
01516 var versions = [];
01517 var search = entity.versions.search;
01518 for (var v in search) {
01519 if (search.hasOwnProperty(v)) {
01520 versions.push({ name: search[v].name });
01521 }
01522 }
01523 collection.push({ id: entitiesObj.name + entity.name, name: entity.name, collection: entity.collection, edited: false, version: versions[0].name, versions: versions });
01524 }
01525 }
01526 dataObj.push({ id: entitiesObj.name, name: entitiesObj.name, entities: collection });
01527 collectionNames.push(entitiesObj.name);
01528 }
01529 }
01530
01531 var displayColumns = [
01532 {
01533 text: "Entity Name",
01534 dataField: "name",
01535 editable: false,
01536 cellClassName: CellClass
01537 },
01538 {
01539 text: "Version",
01540 dataField: "version",
01541 editable: true,
01542 columntype: "template",
01543 initEditor: function (rowKey, cellvalue, editor) {
01544 var row = tag.find("#grid").jqxTreeGrid("getRow", rowKey);
01545 var index1 = -1;
01546 var index2 = -1;
01547 for (var r in dataObj) {
01548 if (dataObj.hasOwnProperty(r)) {
01549 if (row.id.indexOf(dataObj[r].name) === 0) {
01550 index1 = r;
01551 }
01552 }
01553 }
01554 if (index1 >= 0) {
01555 var localData = dataObj[index1];
01556 for (var rr in localData.entities) {
01557 if (localData.entities.hasOwnProperty(rr)) {
01558 if (row.id === localData.entities[rr].id) {
01559 index2 = rr;
01560 }
01561 }
01562 }
01563 if (index2 >= 0) {
01564 var versionsSource = { datatype: "array", datafields: [{ name: "name", type: "string" }], localdata: dataObj[index1].entities[index2].versions };
01565
01566 var versionsAdapter = new $.jqx.dataAdapter(versionsSource, { autoBind: true });
01567 editor.jqxDropDownList({ source: versionsAdapter, displayMember: "name", valueMember: "name", selectedIndex: 0 }).jqxDropDownList("refresh");
01568 }
01569 }
01570
01571 editor.jqxDropDownList("selectItem", cellvalue);
01572 },
01573 getEditorValue: function (row, cellvalue, editor) {
01574
01575 return editor.val();
01576 },
01577 cellClassName: CellClass
01578 }
01579 ];
01580
01581 tag.html("<br><button type=\"button\" class=\"miniButton\" id=\"all1\"> Select All </button><button type=\"button\" class=\"miniButton\" id=\"none1\"> Select None </button><br>" +
01582 "<div id=\"grid\" class=\"jqxTreeGrid\"></div><br>" +
01583 "<button type=\"button\" class=\"miniButton\" id=\"all2\"> Select All </button><button type=\"button\" class=\"miniButton\" id=\"none2\"> Select None </button>");
01584
01585 tag.find("#none1").jqxButton({ height: 30 });
01586 tag.find("#all1").jqxButton({ height: 30 });
01587 tag.find("#none2").jqxButton({ height: 30 });
01588 tag.find("#all2").jqxButton({ height: 30 });
01589
01590 var dataFields = [
01591 { name: "id", type: "string", editable: false, display: false },
01592 { name: "name", type: "string", editable: false, display: true },
01593 { name: "version", type: "string", editable: true, display: true },
01594 { name: "versions", type: "array", editable: false, display: false },
01595 { name: "edited", type: "boolean", editable: false, display: false },
01596 { name: "entities", type: "array", editable: false, display: false }
01597 ];
01598 var source = {
01599 dataType: "json",
01600 dataFields: dataFields,
01601 id: "id",
01602 hierarchy: {
01603 root: "entities"
01604 },
01605 localData: dataObj
01606 };
01607
01608 var dataAdapter = new $.jqx.dataAdapter(source);
01609
01610 tag.find("#grid").jqxTreeGrid({
01611 width: "100%",
01612 source: dataAdapter,
01613 sortable: true,
01614 editable: true,
01615 columnsResize: true,
01616 checkboxes: true,
01617 hierarchicalCheckboxes: true,
01618 columns: displayColumns
01619 });
01620 for (var n in collectionNames) {
01621 if (collectionNames.hasOwnProperty(n)) {
01622 tag.find("#grid").jqxTreeGrid("lockRow", collectionNames[n]);
01623 }
01624 }
01625
01626
01627
01628 tag.find("#none1").mousedown(function () {
01629 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01630 for (var r in rows) {
01631 if (rows.hasOwnProperty(r)) {
01632 if (rows[r].checked) {
01633 tag.find("#grid").jqxTreeGrid("uncheckRow", rows[r].uid);
01634 }
01635 }
01636 }
01637 });
01638 tag.find("#all1").mousedown(function () {
01639 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01640 for (var r in rows) {
01641 if (rows.hasOwnProperty(r)) {
01642 if (!rows[r].checked) {
01643 tag.find("#grid").jqxTreeGrid("checkRow", rows[r].uid);
01644 }
01645 }
01646 }
01647 });
01648 tag.find("#none2").mousedown(function () {
01649 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01650 for (var r in rows) {
01651 if (rows.hasOwnProperty(r)) {
01652 if (rows[r].checked) {
01653 tag.find("#grid").jqxTreeGrid("uncheckRow", rows[r].uid);
01654 }
01655 }
01656 }
01657 });
01658
01659 tag.find("#all2").mousedown(function () {
01660 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01661 for (var r in rows) {
01662 if (rows.hasOwnProperty(r)) {
01663 if (!rows[r].checked) {
01664 tag.find("#grid").jqxTreeGrid("checkRow", rows[r].uid);
01665 }
01666 }
01667 }
01668 });
01669 });
01670 }
01671
01672 function SaveConfig() {
01673 console.log("Saving Configuration Changes");
01674 var files = [];
01675 $(".file-tab.editedValue a")
01676 .each(function () {
01677 var log = $("#changes", $(this).attr("href")).val();
01678 var collection = $("#metadataCollection", $(this).attr("href")).val();
01679 var entities = [];
01680 var rows = $("#metadataEntities", $(this).attr("href")).jqxTreeGrid('getRows');
01681 for (var i = 0; i < rows.length; i++) {
01682
01683 entities.push(rows[i].name);
01684 }
01685 var version = $("#metadataVersion", $(this).attr("href")).val();
01686 files.push({ entities: entities, changelog: log, collection: collection, version: version });
01687 });
01688
01689 AjaxPost("/db/saveConfig",
01690 {
01691 oldConfigName: CurrentNamedConfig,
01692 newConfigName: $("#configName").val(),
01693 files: files,
01694 user: UserId
01695 },
01696 function (res) {
01697 if (res !== null && res !== undefined && res.Success) {
01698 UpdateHeader(false, false, "Configuration Saved.");
01699 GetConfigList();
01700 } else {
01701 UpdateHeader(true, false, "Failed to save configuration!");
01702 }
01703 });
01704 EditedValues = {};
01705 };
01706
01707 function DiscardConfig() {
01708 console.log("Discarding Configuration Changes");
01709 var files = [];
01710 $(".file-tab.editedValue").each(function () {
01711 files.push({ name: $(this).text() });
01712 });
01713
01714 AjaxPost("/db/discardConfig", { configName: CurrentNamedConfig, files: files, user: UserId }, function (res) {
01715 if (res.Success) {
01716 GetConfigList();
01717 } else {
01718 UpdateHeader(true, false, "Failed to discard configuration. Make sure you have a valid configuration selected.\nIf this problem persists, call an expert.");
01719 }
01720 });
01721 EditedValues = {};
01722 };
01723
01724 function GetDbConfig() {
01725
01726 AjaxGet("/db/getDbConfig",
01727 function (data) {
01728 if (data.Success) {
01729 $("#dbType").val(data.dbprovider).trigger("change");
01730 $("#baseDir").val(data.baseDir);
01731 $("#databases").html(data.data.join("")).trigger("create").selectmenu("refresh");
01732 var database = GetUrlParameter("database");
01733 if (database !== undefined && database !== "") {
01734 $("#databases").val(database).trigger("change");
01735 } else {
01736 $("#databases").val(data.instanceName).trigger("change");
01737 }
01738 }
01739 GetConfigList();
01740 });
01741 }
01742
01743 function UpdateDbConfig() {
01744 var config = {
01745 dbprovider: $("#dbType").val(),
01746 baseDir: $("#baseDir").val(),
01747 instanceName: $("#databases").val()
01748 };
01749
01750 AjaxPost("/db/updateDbConfig",
01751 config,
01752 function (res) {
01753 if (res.Success) {
01754 GetDbConfig();
01755 } else {
01756 UpdateHeader(true,
01757 false,
01758 "Failed to update Database Module Configuration. Please See server logs for more details.");
01759 }
01760 }
01761 );
01762 }
01763
01764 function MakeNewDatabase() {
01765 var newDBName = { name: $("#newDatabaseName").val() };
01766 AjaxPost("/db/makeNewDBInstance",
01767 newDBName, function (res) {
01768 if (res.Success) {
01769 GetDbConfig();
01770 } else {
01771 UpdateHeader(true, false, "Failed to create new Database Instance. Please see server logs for more details.");
01772 }
01773 }
01774 );
01775 }
01776
01777 function RegisterButtonFunctions() {
01778 $("#loadConfigButton").on("click", function () { LoadConfig(); });
01779 $("#getConfigListButton").on("click", function () { GetConfigList(); });
01780 $("#saveConfigButton").on("click", function () { SaveConfig(); });
01781 $("#discardConfigButton").on("click", function () { DiscardConfig(); });
01782 $("#searchCurrentConfigButton").on("click", function () { SearchCurrentConfig(); });
01783 $("#baseConfigButton").on("click", function () { BaseConfig(); });
01784 $("#saveNewConfigButton").on("click", function () { SaveNewConfig(); });
01785 $("#baseExportConfigButton").on("click", function () { BaseExportConfig(); });
01786 $("#exportFilesButton").on("click", function () { ExportFiles(); });
01787 $("#addRowToFileUploaderButton").on("click", function () { AddRowToFileUploader(); });
01788 $("#uploadFhiclFileButton").on("click", function () { UploadFhiclFile(); });
01789 $("#updateDBConfigButton").on("click", function () { UpdateDbConfig(); });
01790 $("#createNewDatabaseButton").on("click", function () { MakeNewDatabase(); });
01791 }
01792
01793 (function ($, sr) {
01794
01795
01796
01797 var debounce = function (func, threshold, execAsap) {
01798 var timeout;
01799
01800 return function debounced() {
01801 var obj = this, args = arguments;
01802 function delayed() {
01803 if (!execAsap)
01804 func.apply(obj, args);
01805 timeout = null;
01806 };
01807
01808 if (timeout)
01809 clearTimeout(timeout);
01810 else if (execAsap)
01811 func.apply(obj, args);
01812
01813 timeout = setTimeout(delayed, threshold || 100);
01814 };
01815 };
01816
01817
01818 jQuery.fn[sr] = function (fn) { return fn ? this.bind("resize", debounce(fn)) : this.trigger(sr); };
01819
01820 })(jQuery, "smartresize");
01821
01822 $(document).ready(function () {
01823 DefaultColor = $("#header").css("background-color");
01824 DefaultShadow = $("#header").css("text-shadow");
01825
01826 $.get("/db/Tables.html", function (data) {
01827 TableHtml = data;
01828 });
01829
01830 $.get("/db/FileInfo.html", function (data) {
01831 InfoHtml = data;
01832 });
01833
01834 $.get("/db/TreeGrid.html", function (data) {
01835 TreeGridHtml = data;
01836 });
01837
01838 $.get("/db/Dialog.html", function (data) { DialogContentHtml = data; });
01839
01840 $(".configInfo-tab").on("click", function () {
01841 ResizeTextAreas();
01842 });
01843
01844 RegisterTabFunctions();
01845 $(".tabs #tab1").show().siblings().hide();
01846
01847 $(".triggersModified").change(function () {
01848 UpdateHeader(false, true, "There are pending unsaved changes. Please save or discard before closing the editor!");
01849 });
01850
01851 $(window).smartresize(function () {
01852 $(".jqxTreeGrid").jqxTreeGrid({ width: "100%" }).jqxTreeGrid("refresh");
01853 });
01854
01855 $("#newConfig").on("collapsibleexpand", function () {
01856 SetupEntityVersionPicker($("#configurationPicker"));
01857 });
01858
01859 $("#exportFile").on("collapsibleexpand", function () {
01860 SetupEntityVersionPicker($("#filePicker"));
01861 });
01862
01863 $("#uploadFile")
01864 .on("collapsibleexpand",
01865 function () {
01866 SetupFileUploadTable($("#fileUploader"));
01867 });
01868
01869 $("#dbType").on("change", function () {
01870 var dbtype = $("#dbType").val();
01871 if (dbtype === "filesystem") {
01872 $("#filesystemdbConfig").show();
01873 $("#mongodbConfig").hide();
01874 } else if (dbtype === "mongo") {
01875 $("#filesystemdbConfig").hide();
01876 $("#mongodbConfig").show();
01877 }
01878 }).trigger("change");
01879
01880 $("#databases").on("change", function () {
01881 var instanceName = $("#databases").val();
01882 if (instanceName === "NONE") {
01883 $("#newDatabaseFS").show();
01884 } else {
01885 $("#newDatabaseFS").hide();
01886 UpdateDbConfig();
01887 }
01888 }).trigger("change");
01889
01890 GetDbConfig();
01891
01892 RegisterButtonFunctions();
01893 });