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