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