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 var first = true;
00555 do {
00556 if ((parent === null || parent === undefined) && currentName.indexOf("___") >= 0) {
00557 var parentSelector = tag.selector.split(" ").slice(0, -1).join(" ");
00558 var parentRow = $(parentSelector + " #treeGrid").jqxTreeGrid("getRow", currentName.slice(0, -4));
00559 parent = parentRow[0];
00560 while ((parent !== null && parent !== undefined) && parent.constructor === Array) {
00561 parent = parent[0];
00562 }
00563 }
00564 else if ((parent === null || parent === undefined) && rowData.name.indexOf("___") >= 0 && first) {
00565 first = false;
00566 var parentSelector = tag.selector.split(" ").slice(0, -1).join(" ");
00567 var parentName = tag.selector.split(" ").slice(-1).join(" ").slice(1);
00568 parentName = parentName.slice(0, parentName.indexOf("___"));
00569 var parentRow = $(parentSelector + " #treeGrid").jqxTreeGrid("getRow", parentName);
00570 parent = parentRow[0];
00571 while ((parent !== null && parent !== undefined) && parent.constructor === Array) {
00572 parent = parent[0];
00573 }
00574 }
00575
00576 if (parent !== null && parent !== undefined) {
00577 currentName = parent.name;
00578 path = parent.name + "/" + path;
00579 parent = parent.parent;
00580 }
00581 } while (parent !== null && parent !== undefined);
00582
00583 if (CurrentCollection && CurrentEntity) {
00584 path = CurrentCollection + "/" + CurrentEntity + "/" + path;
00585 } else {
00586 var pathTmp = path.split('/');
00587 CurrentCollection = pathTmp.shift();
00588 CurrentEntity = pathTmp.shift();
00589 }
00590 console.log("Path is " + path);
00591
00592 var columnDataField = args.dataField;
00593
00594 var columnName = args.dataField;
00595 for (var i in args.owner._columns) {
00596 if (args.owner._columns.hasOwnProperty(i)) {
00597 if (args.owner._columns[i].dataField === columnName) {
00598 columnName = args.owner._columns[i].text;
00599 break;
00600 }
00601 }
00602 }
00603 EditedValues[CurrentCollection + "/" + CurrentEntity + "/" + rowKey] = true;
00604 $("li.active :visible").parent().addClass("editedValue");
00605
00606 var value = args.value;
00607
00608 AjaxPost("/db/Update", {
00609 configName: CurrentNamedConfig,
00610 table: path,
00611 column: columnDataField,
00612 id: rowData.id,
00613 name: rowData.name,
00614 value: value,
00615 user: UserId
00616 }, function (retval) {
00617 if (retval.Success) {
00618 var now = new Date;
00619 var selector = $("#changes", $(".file-tab.active a").attr("href"));
00620 selector.val(now.toISOString() + ": Edit - File: " + CurrentCollection + "/" + CurrentEntity + ", Name: " + rowData.name + ", Column: " + columnName + ", Value: " + value + "\n" + selector.val());
00621 $("#masterChanges").val(now.toISOString() + ": Edit - File: " + CurrentCollection + "/" + CurrentEntity + ", Name: " + rowData.name + ", Column: " + columnName + ", Value: " + value + "\n" + $("#masterChanges").val());
00622 UpdateHeader(false, true, "There are pending unsaved changes. Please save or discard before closing the editor!");
00623 } else {
00624 UpdateHeader(true, false, "Sending Update to server failed");
00625 }
00626 });
00627 });
00628 };
00629
00630 function CellClass(row, dataField, cellText, rowData) {
00631 var edited = false;
00632 for (var val in EditedValues) {
00633 if (EditedValues.hasOwnProperty(val)) {
00634 if (val === CurrentCollection + "/" + CurrentEntity + "/" + rowData.uid) {
00635 edited = EditedValues[val];
00636 break;
00637 }
00638 }
00639 }
00640 if (edited) {
00641 return "editedValue";
00642 }
00643 return "value";
00644 };
00645
00646 function TranslateColumns(columns) {
00647 var displayColumns = [];
00648
00649 for (var c in columns) {
00650 if (columns.hasOwnProperty(c)) {
00651 var title = columns[c].title;
00652 if (title === undefined || title === null || title.length === 0) {
00653 title = columns[c].name.charAt(0).toUpperCase() + columns[c].name.slice(1);
00654 }
00655 if (columns[c].type === "string" && columns[c].display) {
00656 displayColumns.push({
00657 text: title,
00658 dataField: columns[c].name,
00659 editable: columns[c].editable,
00660 columnGroup: columns[c].columnGroup,
00661 createEditor: CreateRowEditor,
00662 initEditor: InitRowEditor,
00663 getEditorValue: GetRowEditorValue,
00664 cellClassName: CellClass
00665 });
00666 } else if (columns[c].type === "number" && columns[c].display) {
00667 columns[c].type = "string";
00668 columns[c].dataType = "number";
00669 displayColumns.push({
00670 text: title,
00671 dataField: columns[c].name,
00672 editable: columns[c].editable,
00673 columnGroup: columns[c].columnGroup,
00674 createEditor: CreateRowEditor,
00675 initEditor: InitRowEditor,
00676 getEditorValue: GetRowEditorValue,
00677 cellClassName: CellClass
00678 });
00679 }
00680 }
00681 }
00682 return displayColumns;
00683 }
00684
00685 function LoadTable(tag) {
00686
00687 AjaxPost("/db/GetData", { configName: CurrentNamedConfig, entity: CurrentEntity, collection: CurrentCollection, user: UserId }, function (data) {
00688 if (!data.Success) {
00689 UpdateHeader(true, false, "Fetch of data from database failed");
00690 return;
00691 }
00692 var columns = data.data.columns;
00693
00694 MakeTreeGrid(tag, columns, data.data.children);
00695
00696 });
00697 };
00698
00699 function SetupConfigVersionPicker(element, target) {
00700
00701 element.on("change", function () {
00702 var thisConfig = element.find(":selected").text();
00703 var configVersionHtml = "";
00704 for (var version in ConfigVersionData[thisConfig]) {
00705 if (ConfigVersionData[thisConfig].hasOwnProperty(version)) {
00706 configVersionHtml += "<option name=\"" + ConfigVersionData[thisConfig][version].name
00707 + "\" value=" + ConfigVersionData[thisConfig][version].data + ">" + ConfigVersionData[thisConfig][version].version + "</option>";
00708 }
00709 }
00710 $("#" + target).html(configVersionHtml).trigger("create").selectmenu("refresh");
00711 $("#" + target).html($("#" + target + " option").sort(function (a, b) {
00712 return parseInt(a.text) === parseInt(b.text) ? 0 : parseInt(a.text) > parseInt(b.text) ? -1 : 1;
00713 }));
00714 var option = $("#" + target).find('option:eq(0)');
00715 option.prop('selected', true);
00716 $("#"+target).trigger("create").selectmenu("refresh");
00717 });
00718 }
00719
00720 function GetConfigList() {
00721 UpdateHeader(false, false, "");
00722 $("#masterChanges").val("");
00723 ResizeTextAreas();
00724 for (var i = 2; i <= LastTabId; i++) {
00725 $("#tab" + i).remove();
00726 $("#tablink" + i).remove();
00727 }
00728
00729 $("#reloadConfigsButton").text("Reload Configurations");
00730
00731
00732 AjaxPost("/db/NamedConfigs", { configFilter: $("#configurationFilter").val(), user: UserId }, function (data) {
00733 if (!data.Success) {
00734 UpdateHeader(true, false, "Error retrieving Configuration list. Please contact an expert!");
00735 return;
00736 }
00737 var configsHtml = "";
00738 for (var name in data.data) {
00739 if (data.data.hasOwnProperty(name)) {
00740 configsHtml += "<option>" + name + "</option>";
00741 ConfigVersionData[name] = data.data[name];
00742 }
00743 }
00744 $("#configs").html(configsHtml).trigger("create").selectmenu("refresh");
00745 $("#oldConfigName").html(configsHtml).trigger("create").selectmenu("refresh");
00746 $("#exportConfigName").html(configsHtml).trigger("create").selectmenu("refresh");
00747
00748 SetupConfigVersionPicker($("#configs"), "configversions");
00749 $("#configs").trigger("change");
00750 SetupConfigVersionPicker($("#oldConfigName"), "oldConfigVersion");
00751 $("#oldConfigName").trigger("change");
00752 SetupConfigVersionPicker($("#exportConfigName"), "exportConfigVersion");
00753 $("#exportConfigName").trigger("change");
00754
00755 var config = GetUrlParameter("configs");
00756 if (config !== undefined) {
00757 $("#configs").val(config);
00758 }
00759 });
00760 $("#configLoad").collapsible("option", "disabled", false).collapsible("option", "collapsed", false);
00761 $("#configSave").collapsible("option", "disabled", true).collapsible("option", "collapsed", true);
00762 $("#configMetadata").collapsible("option", "disabled", true).collapsible("option", "collapsed", true);
00763 $("#searchConfig").collapsible("option", "disabled", false);
00764 $("#exportFile").collapsible("option", "collapsed", true);
00765 $("#newConfig").collapsible("option", "collapsed", true);
00766 };
00767
00768 function RegisterTabFunctions() {
00769 $(".file-tab a").off();
00770 $(".collection-tab a").off();
00771 $(".tabs .tab-links a").off().on("click", function (e) {
00772 var currentAttrValue = $(this).attr("href");
00773 var tab = $(this).parent();
00774 var div = tab.parent();
00775 div.scrollLeft(0);
00776 var left = Math.floor(tab.position().left - 20);
00777 div.scrollLeft(left);
00778
00779 $(".tabs " + currentAttrValue).show().siblings().hide();
00780
00781
00782 $(this).parent("li").addClass("active").siblings().removeClass("active");
00783
00784 e.preventDefault();
00785 });
00786 $(".collection-tab a").on("click", function () {
00787 CurrentCollection = $(this).text();
00788 });
00789 $(".file-tab a").on("click", function () {
00790 var fileName = $(this).text();
00791 CurrentEntity = fileName;
00792 LoadFile($(this).attr("href"));
00793 ResizeTextAreas();
00794 });
00795 };
00796
00797 function GetUrlParameter(sParam) {
00798 var sUrlVariables = window.location.search.substring(1).split("&");
00799
00800 for (var i = 0; i < sUrlVariables.length; i++) {
00801 var sParameterName = sUrlVariables[i].split("=");
00802
00803 if (sParameterName[0].search(sParam) >= 0) {
00804
00805 return sParameterName[1];
00806 }
00807 }
00808 return "";
00809 };
00810
00811 function LoadConfigMetadata() {
00812 console.log("Loading configuration metadata");
00813
00814 AjaxPost("/db/LoadConfigMetadata", { configName: CurrentNamedConfig, user: UserId }, function (metadata) {
00815 if (!metadata.Success) {
00816 UpdateHeader(true, false, "Error loading configuration metadata from database");
00817 return;
00818 }
00819 var metadataObj = metadata.data;
00820
00821
00822 var displayColumns = [
00823 {
00824 text: "Entity Name",
00825 dataField: "name",
00826 editable: false
00827 },
00828 {
00829 text: "Collection Name",
00830 dataField: "collection",
00831 editable: false
00832 },
00833 {
00834 text: "Version",
00835 dataField: "version",
00836 editable: false
00837 },
00838 {
00839 text: "Edit", cellsAlign: "center", align: "center", columnType: "none", editable: false, sortable: false, dataField: null, cellsRenderer: function (row) {
00840
00841 return "<button data-row='" + row + "' class='editButtons' onclick=''>Edit</button>";
00842 }
00843 }
00844 ];
00845 var dataFields = [
00846 { name: "name", type: "string", editable: false, display: true },
00847 { name: "collection", type: "string", editable: false, display: true },
00848 { name: "file", type: "string", editable: false, display: false },
00849 { name: "version", type: "string", editable: false, display: true }
00850 ];
00851 var source = {
00852 dataType: "json",
00853 dataFields: dataFields,
00854 id: "file",
00855 hierarchy: {
00856 root: "values"
00857 },
00858 localData: metadataObj.entities
00859 };
00860
00861 var dataAdapter = new $.jqx.dataAdapter(source);
00862
00863 var grid = $("#configurationEntities");
00864 grid.addClass("jqxTreeGrid").jqxTreeGrid(
00865 {
00866 width: "100%",
00867 source: dataAdapter,
00868 editable: false,
00869 sortable: true,
00870 columnsResize: true,
00871 columns: displayColumns,
00872 rendering: function () {
00873
00874 if ($(".editButtons").length > 0) {
00875 $(".editButtons").jqxButton("destroy");
00876 }
00877 },
00878 rendered: function () {
00879 if ($(".editButtons").length > 0) {
00880 $(".editButtons").jqxButton();
00881
00882 var editClick = function (event) {
00883
00884 var rowKey = event.target.getAttribute("data-row");
00885 var row = grid.jqxTreeGrid("getRow", rowKey);
00886 var collection = row["collection"];
00887 var collectionTab = $(".collection-tab[collection-name=\"" + collection + "\"] a");
00888 collectionTab.trigger("click");
00889 var file = row["name"];
00890 var fileNameTab = $(collectionTab[0].hash).find(".file-tab[file-name=\"" + file + "\"] a");
00891 fileNameTab.trigger("click");
00892 };
00893 $(".editButtons").on("click", function (event) {
00894 editClick(event);
00895 return false;
00896 });
00897
00898 }
00899 }
00900 });
00901 });
00902 };
00903
00904 function AddEntityToFile(id) {
00905 var newEntityName = $(id + " #newEntityName").val();
00906 $(id + " #newEntityName").val("");
00907 if (newEntityName !== "") {
00908 AjaxPost("/db/AddEntityToFile", { configName: CurrentNamedConfig, entity: CurrentEntity, collection: CurrentCollection, user: UserId, name: newEntityName }, function (res) {
00909 if (res.Success) {
00910 LoadFile(id);
00911 }
00912 else {
00913 UpdateHeader(true, false, "Error adding Entity to configuration file");
00914 }
00915 });
00916 }
00917 }
00918
00919 function LoadFile(id) {
00920
00921 AjaxPost("/db/LoadFileMetadata", { configName: CurrentNamedConfig, entity: CurrentEntity, collection: CurrentCollection, user: UserId }, function (metadata) {
00922 if (!metadata.Success) {
00923 UpdateHeader(true, false, "Error loading file metadata from database");
00924 return;
00925 }
00926 console.log("Loading file metadata");
00927 var metadataObj = metadata.data;
00928 console.log(metadata);
00929 $(id + " #metadataCollection").val(metadataObj.collection);
00930 $(id + " #metadataVersion").val(metadataObj.version);
00931 $(id + " #changeLog").val(metadataObj.changelog);
00932
00933 var displayColumns = [
00934 {
00935 text: "Name",
00936 dataField: "name",
00937 editable: false
00938 },
00939 {
00940 text: "Date Assigned",
00941 dataField: "assigned",
00942 editable: false
00943 }
00944 ];
00945 var dataFields = [
00946 { name: "name", type: "string", editable: false, display: true },
00947 { name: "assigned", type: "date", editable: false, display: true }
00948 ];
00949 var entitiesSource = {
00950 dataType: "json",
00951 dataFields: dataFields,
00952 id: "name",
00953 hierarchy: {
00954 root: "values"
00955 },
00956 localData: metadataObj.entities
00957 };
00958
00959 var entitiesDataAdapter = new $.jqx.dataAdapter(entitiesSource);
00960
00961 $(id + " #metadataEntities").addClass("jqxTreeGrid").jqxTreeGrid(
00962 {
00963 width: "100%",
00964 source: entitiesDataAdapter,
00965 editable: false,
00966 sortable: true,
00967 columnsResize: true,
00968 columns: displayColumns
00969 });
00970 var configsSource = {
00971 dataType: "json",
00972 dataFields: dataFields,
00973 id: "name",
00974 hierarchy: {
00975 root: "values"
00976 },
00977 localData: metadataObj.configurations
00978 };
00979
00980 var configsDataAdapter = new $.jqx.dataAdapter(configsSource);
00981
00982 $(id + " #metadataConfigurations").addClass("jqxTreeGrid").jqxTreeGrid(
00983 {
00984 width: "100%",
00985 source: configsDataAdapter,
00986 editable: false,
00987 sortable: true,
00988 columnsResize: true,
00989 columns: displayColumns
00990 });
00991 LoadTable($(id + " #fileTable"));
00992 });
00993 };
00994
00995 function SearchCurrentConfig() {
00996 console.log("Searching Configuration");
00997
00998 var searchKey = $("#searchKey").val();
00999 console.log("SearchKey is " + searchKey);
01000
01001 AjaxPost("/db/SearchLoadedConfig", { configName: CurrentNamedConfig, user: UserId, searchKey: searchKey }, function (results) {
01002 if (!results.Success) {
01003 UpdateHeader(true, false, "Error searching configuration");
01004 return;
01005 }
01006
01007 MakeTreeGrid($("#searchResults"), results.columns, results.collections);
01008 });
01009 }
01010
01011 function LoadConfig() {
01012 console.log("Loading Configuration");
01013 $("#masterChanges").val("");
01014 UpdateHeader(false, false, "");
01015 var selected = $("#configversions").find(":selected");
01016 if (selected.text() === "No Configurations Found" || selected.text() === "Click \"Load Configurations\" To Load Configuration Names") { return; }
01017 CurrentNamedConfig = selected.attr("name");
01018 $("#configName").val(CurrentNamedConfig);
01019 for (var i = 2; i <= LastTabId; i++) {
01020 $("#tab" + i).remove();
01021 $("#tablink" + i).remove();
01022 }
01023 LastTabId = 1;
01024
01025 AjaxPost("/db/LoadNamedConfig", { configName: CurrentNamedConfig, query: selected.val(), user: UserId }, function (config) {
01026 if (!config.Success) {
01027 UpdateHeader(true, false, "Error loading configuration files from database");
01028 return;
01029 }
01030 ResizeTextAreas();
01031 for (var collection in config.collections) {
01032 if (config.collections.hasOwnProperty(collection)) {
01033 LastTabId++;
01034 var parentTab = LastTabId;
01035 $("#tabLinks").append("<li id=\"tablink" + LastTabId + "\"collection-name=\"" + config.collections[collection].name + "\" tabNum=\"" + LastTabId + "\" class=\"collection-tab\"><a href=\"#tab" + LastTabId + "\">" + config
01036 .collections[collection].name + "</a></li>");
01037 $("#tabContents").append("<div id=tab" + LastTabId + " class=\"tab\"></div>");
01038 $("#tab" + LastTabId).html(TableHtml);
01039
01040 for (var file in config.collections[collection].files) {
01041 if (config.collections[collection].files.hasOwnProperty(file)) {
01042 var name = config.collections[collection].files[file];
01043
01044 LastTabId++;
01045 $("#tab" + parentTab + " #tabLinks").append("<li id=\"tablink" + LastTabId + "\" file-name=\"" + name + "\" tabNum=\"" + LastTabId + "\" class=\"file-tab\"><a href=\"#tab" + LastTabId + "\">" + name + "</a></li>");
01046 $("#tab" + parentTab + " #tabContents").append("<div id=tab" + LastTabId + " class=\"tab\"></div>");
01047 $("#tab" + LastTabId).html(InfoHtml).trigger("create");;
01048 }
01049 }
01050 }
01051 }
01052 $("#configLoad").collapsible("option", "disabled", false).collapsible("option", "collapsed", true);
01053 $("#configSave").collapsible("option", "disabled", false).collapsible("option", "collapsed", false);
01054 LoadConfigMetadata();
01055 $("#configMetadata").collapsible("option", "disabled", false).collapsible("option", "collapsed", false);
01056 $("#searchConfig").collapsible("option", "disabled", false);
01057 RegisterTabFunctions();
01058 });
01059 };
01060
01061 function BaseConfig() {
01062
01063 AjaxPost("/db/LoadConfigMetadata", { configName: $("#oldConfigName :selected").text(), user: UserId }, function (metadata) {
01064 if (!metadata.Success) {
01065 UpdateHeader(true, false, "Error loading configuration metadata from database");
01066 return;
01067 }
01068 var metadataObj = metadata.data;
01069
01070
01071 $("#newConfigName").val($("#oldConfigName :selected").text());
01072 var tag = $("#configurationPicker");
01073 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01074 for (var r in rows) {
01075 if (rows.hasOwnProperty(r)) {
01076 var thisRow = rows[r];
01077 var isChecked = false;
01078 for (var e in metadataObj.entities) {
01079 if (isChecked) break;
01080 if (metadataObj.entities.hasOwnProperty(e)) {
01081 var entity = metadataObj.entities[e];
01082 if (thisRow.name === entity.collection) {
01083 for (var r in thisRow.records) {
01084 if (thisRow.records.hasOwnProperty(r)) {
01085 var record = thisRow.records[r];
01086 if (record.id === entity.collection + entity.name) {
01087 tag.find("#grid").jqxTreeGrid("updateRow", record.uid, { name: entity.name, version: entity.version });
01088 tag.find("#grid").jqxTreeGrid("checkRow", record.uid);
01089 isChecked = true;
01090 break;
01091 }
01092 }
01093 }
01094 }
01095 }
01096 }
01097 if (!isChecked && thisRow.checked) {
01098 tag.find("#grid").jqxTreeGrid("uncheckRow", thisRow.uid);
01099 }
01100 }
01101 }
01102 });
01103 };
01104
01105 function BaseExportConfig() {
01106
01107 AjaxPost("/db/LoadConfigMetadata", { configName: $("#exportConfigName :selected").text(), user: UserId }, function (metadata) {
01108 if (!metadata.Success) {
01109 UpdateHeader(true, false, "Error loading configuration metadata from database");
01110 return;
01111 }
01112 ExportTarFileName = $("#exportConfigName :selected").text();
01113 var metadataObj = metadata.data;
01114
01115
01116 var tag = $("#filePicker");
01117 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01118 for (var r in rows) {
01119 if (rows.hasOwnProperty(r)) {
01120 var thisRow = rows[r];
01121 var isChecked = false;
01122 for (var e in metadataObj.entities) {
01123 if (isChecked) break;
01124 if (metadataObj.entities.hasOwnProperty(e)) {
01125 var entity = metadataObj.entities[e];
01126 if (thisRow.name === entity.collection) {
01127 for (var r in thisRow.records) {
01128 if (thisRow.records.hasOwnProperty(r)) {
01129 var record = thisRow.records[r];
01130 if (record.id === entity.collection + entity.name) {
01131 tag.find("#grid").jqxTreeGrid("updateRow", record.uid, { name: entity.name, version: entity.version });
01132 tag.find("#grid").jqxTreeGrid("checkRow", record.uid);
01133 isChecked = true;
01134 break;
01135 }
01136 }
01137 }
01138 }
01139 }
01140 }
01141 if (!isChecked && thisRow.checked) {
01142 tag.find("#grid").jqxTreeGrid("uncheckRow", thisRow.uid);
01143 }
01144 }
01145 }
01146
01147 });
01148 };
01149
01150 function SaveNewConfig() {
01151 console.log("Saving New Configuration");
01152 var tag = $("#configurationPicker");
01153 var rows = tag.find("#grid").jqxTreeGrid("getCheckedRows");
01154 var configObj = {
01155 entities: []
01156 };
01157
01158 for (var r in rows) {
01159 if (rows.hasOwnProperty(r) &&
01160 (typeof rows[r].collection !== "undefined" && rows[r].collection.length > 0) &&
01161 (typeof rows[r].version !== "undefined" && rows[r].version.length > 0)) {
01162 configObj.entities.push({ name: rows[r].name, version: rows[r].version, collection: rows[r].collection });
01163 }
01164 }
01165
01166
01167 AjaxPost("/db/MakeNewConfig", { user: UserId, config: JSON.stringify(configObj), name: $("#newConfigName").val() }, function (retval) {
01168 if (retval.Success) {
01169 $("#newConfig").collapsible("option", "collapsed", true);
01170 GetConfigList();
01171 } else {
01172 UpdateHeader(true, false, "MakeNewConfig operation failed.");
01173 }
01174 });
01175 };
01176
01177 function ExportFiles() {
01178 console.log("Exporting Files");
01179 var tag = $("#filePicker");
01180 var rows = tag.find("#grid").jqxTreeGrid("getCheckedRows");
01181 var configObj = {
01182 entities: []
01183 };
01184
01185 for (var r in rows) {
01186 if (rows.hasOwnProperty(r) &&
01187 (typeof rows[r].collection !== "undefined" && rows[r].collection.length > 0) &&
01188 (typeof rows[r].version !== "undefined" && rows[r].version.length > 0)) {
01189 configObj.entities.push({ name: rows[r].name, version: rows[r].version, collection: rows[r].collection });
01190 }
01191 }
01192
01193
01194 var xhr = new XMLHttpRequest();
01195 xhr.open("POST", "/db/DownloadConfigurationFile", true);
01196 xhr.responseType = "arraybuffer";
01197 xhr.onload = function () {
01198 if (this.status === 200) {
01199 var filename = "";
01200 var disposition = xhr.getResponseHeader("Content-Disposition");
01201 if (disposition && disposition.indexOf("attachment") !== -1) {
01202 var filenameRegex = /filename[^;=\n]*=((['"]).*?\2|[^;\n]*)/;
01203 var matches = filenameRegex.exec(disposition);
01204 if (matches != null && matches[1]) filename = matches[1].replace(/['"]/g, "");
01205 }
01206 var type = xhr.getResponseHeader("Content-Type");
01207
01208 var blob = new Blob([this.response], { type: type });
01209 if (typeof window.navigator.msSaveBlob !== "undefined") {
01210 // 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."
01211 window.navigator.msSaveBlob(blob, filename);
01212 } else {
01213 var url = window.URL || window.webkitURL;
01214 var downloadUrl = url.createObjectURL(blob);
01215
01216 if (filename) {
01217 // use HTML5 a[download] attribute to specify filename
01218 var a = document.createElement("a");
01219 // safari doesn't support this yet
01220 if (typeof a.download === "undefined") {
01221 window.location = downloadUrl;
01222 } else {
01223 a.href = downloadUrl;
01224 a.download = filename;
01225 document.body.appendChild(a);
01226 a.click();
01227 }
01228 } else {
01229 window.location = downloadUrl;
01230 }
01231
01232 setTimeout(function () { url.revokeObjectURL(downloadUrl); }, 100); // cleanup
01233 }
01234 } else if (this.status === 500) {
01235 UpdateHeader(true, false, "An error occurred on the server. Contact an expert if the situation persists");
01236 }
01237 };
01238 xhr.setRequestHeader("Content-type", "application/x-www-form-urlencoded");
01239 xhr.send($.param({ user: UserId, config: JSON.stringify(configObj), tarFileName: ExportTarFileName, type: $("#exportFileFormat :selected").val() }));
01240 ExportTarFileName = "export";
01241 };
01242
01243 function AddRowToFileUploader() {
01244 $("#fileUploader").find("#grid").jqxTreeGrid("addRow", null, {});
01245 }
01246
01247 function SetupFileUploadTable(tag) {
01248 var displayColumns = [
01249 {
01250 text: "File",
01251 dataField: "fileName",
01252 editable: true,
01253 cellClassName: CellClass,
01254 columntype: "template",
01255 initEditor: function (row, cellvalue, editor) {
01256 if (cellvalue === "" || cellvalue === "undefined" || !cellvalue) {
01257 editor.html("<input type=\"file\" id=\"fileName\"/>");
01258 } else {
01259 editor.text(cellvalue);
01260 }
01261 },
01262 getEditorValue: function (row, cellvalue, editor) {
01263
01264 if (cellvalue === "" || cellvalue === "undefined" || !cellvalue) {
01265 var fileName = editor.find("#fileName")[0];
01266 UploadFiles[row] = fileName.files[0];
01267 return fileName.files[0].name;
01268 }
01269 return cellvalue;
01270 }
01271 },
01272 {
01273 text: "File Type",
01274 dataField: "fileType",
01275 editable: true,
01276 cellClassName: CellClass,
01277 columntype: "template",
01278 initEditor: function (row, cellvalue, editor) {
01279
01280 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 });
01281 editor.jqxDropDownList({ source: versionsAdapter, displayMember: "name", valueMember: "value", selectedIndex: 0 }).jqxDropDownList("refresh");
01282
01283 editor.jqxDropDownList("selectItem", cellvalue);
01284 },
01285 getEditorValue: function (row, cellvalue, editor) {
01286
01287 return editor.val();
01288 }
01289 },
01290 {
01291 text: "Collection",
01292 dataField: "collection",
01293 editable: true,
01294 cellClassName: CellClass
01295 },
01296 {
01297 text: "Entity Name",
01298 dataField: "entity",
01299 editable: true,
01300 cellClassName: CellClass
01301 },
01302 {
01303 text: "Version",
01304 dataField: "version",
01305 editable: true,
01306 cellClassName: CellClass
01307 },
01308 {
01309 text: "Remove", cellsAlign: "center", align: "center", columnType: "none", editable: false, sortable: false, dataField: null, cellsRenderer: function (row) {
01310
01311 return "<button data-row='" + row + "' class='removeButtons' onclick=''>Remove</button>";
01312 }
01313 }
01314 ];
01315
01316 tag.html("<div id=\"grid\" class=\"jqxTreeGrid\"></div><br>");
01317
01318 var dataFields = [
01319 { name: "id", type: "string", editable: false, display: false },
01320 { name: "fileName", type: "string", editable: true, display: true },
01321 { name: "fileType", type: "string", editable: true, display: true },
01322 { name: "collection", type: "string", editable: true, display: true },
01323 { name: "entity", type: "string", editable: true, display: true },
01324 { name: "version", type: "string", editable: true, display: true }
01325 ];
01326 var source = {
01327 dataType: "json",
01328 dataFields: dataFields,
01329 id: "id",
01330 hierarchy: {
01331 root: "entities"
01332 },
01333 localData: {}
01334 };
01335
01336 var dataAdapter = new $.jqx.dataAdapter(source);
01337
01338 tag.find("#grid").jqxTreeGrid({
01339 width: "100%",
01340 source: dataAdapter,
01341 sortable: true,
01342 editable: true,
01343 columnsResize: true,
01344 columns: displayColumns,
01345 rendering: function () {
01346
01347 if ($(".removeButtons").length > 0) {
01348 $(".removeButtons").jqxButton("destroy");
01349 }
01350 },
01351 rendered: function () {
01352 if ($(".removeButtons").length > 0) {
01353 $(".removeButtons").jqxButton();
01354
01355 var removeClick = function (event) {
01356
01357 var rowKey = event.target.getAttribute("data-row");
01358 delete UploadFiles[rowKey];
01359 tag.find("#grid").jqxTreeGrid("deleteRow", rowKey);
01360 };
01361 $(".removeButtons").on("click", function (event) {
01362 removeClick(event);
01363 return false;
01364 });
01365
01366 }
01367 }
01368 });
01369 }
01370
01371 function SetupReader(file) {
01372 var f = UploadFiles[file];
01373 var r = new FileReader();
01374 r.fileid = file;
01375 r.onload = function (e) {
01376 var contents = e.target.result;
01377 var thisfile = e.target.fileid;
01378 var row = $("#fileUploader").find("#grid").jqxTreeGrid("getRow", thisfile);
01379 console.log("Calling AjaxPost with parameters: Collection: " +
01380 row.collection +
01381 ", Version: " +
01382 row.version +
01383 ", Entity: " +
01384 row.entity +
01385 ", Type: " +
01386 row.fileType + ", fileName: " + row.fileName + ", file.name: " + f.name);
01387
01388
01389 AjaxPost("/db/UploadConfigurationFile",
01390 {
01391 file: contents,
01392 collection: row.collection,
01393 version: row.version,
01394 entity: row.entity,
01395 user: UserId,
01396 type: row.fileType
01397 },
01398 function (res) {
01399 if (!res.Success) {
01400 UpdateHeader(true, false, "File upload failed");
01401 } else {
01402 console.log("Upload: " + row.fileName + " returned: " + JSON.stringify(res));
01403 }
01404 delete UploadFiles[thisfile];
01405 });
01406 };
01407 r.readAsText(f);
01408 }
01409
01410 function UploadFhiclFile() {
01411 $("#uploadFhiclFileButton").text("Uploading... Please Wait.");
01412
01413 var didAnything = false;
01414 for (var file in UploadFiles) {
01415 if (UploadFiles.hasOwnProperty(file)) {
01416 didAnything = true;
01417 var f = UploadFiles[file];
01418
01419 var row = $("#fileUploader").find("#grid").jqxTreeGrid("getRow", file);
01420 if (!f) {
01421 alert("Failed to load file");
01422 continue;
01423 }
01424
01425 if (row.fileType === "fhicl" && f.name.search(".fcl") === -1) {
01426 alert(f.name + " is not a valid fhicl file.");
01427 continue;
01428 }
01429
01430 if (row.fileType === "json" && f.name.search(".json") === -1) {
01431 alert(f.name + " is not a valid json file.");
01432 continue;
01433 }
01434
01435 if ((row.fileType !== "fhicl" &&
01436 row.fileType !== "json") ||
01437 row.collection === "" ||
01438 row.version === "" ||
01439 row.entity === "") {
01440 alert(f.name + " missing needed metadata");
01441 continue;
01442 }
01443
01444 SetupReader(file);
01445 }
01446 break;
01447 }
01448
01449 if (!didAnything) {
01450 $("#uploadFile").collapsible("option", "collapsed", true);
01451 $("#uploadFhiclFileButton").text("Store File(s) In Database");
01452 } else {
01453 setTimeout(function () { UploadFhiclFile(); }, 1000);
01454 }
01455 };
01456
01457 function SetupEntityVersionPicker(tag) {
01458
01459 AjaxGet("/db/EntitiesAndVersions", function (data) {
01460 console.log(JSON.stringify(data));
01461 if (!data.Success) {
01462 UpdateHeader(true, false, "Error retrieving entities and versions lists. Please contact an expert!");
01463 return;
01464 }
01465 var collectionsObj = data.collections;
01466 var dataObj = [];
01467 var collectionNames = [];
01468 for (var c in collectionsObj) {
01469 if (collectionsObj.hasOwnProperty(c)) {
01470 var collection = [];
01471 var entitiesObj = collectionsObj[c];
01472 for (var e in entitiesObj.entities) {
01473 if (entitiesObj.entities.hasOwnProperty(e)) {
01474 var entity = entitiesObj.entities[e];
01475 var versions = [];
01476 var search = entity.versions.search;
01477 for (var v in search) {
01478 if (search.hasOwnProperty(v)) {
01479 versions.push({ name: search[v].name });
01480 }
01481 }
01482 collection.push({ id: entitiesObj.name + entity.name, name: entity.name, collection: entity.collection, edited: false, version: versions[0].name, versions: versions });
01483 }
01484 }
01485 dataObj.push({ id: entitiesObj.name, name: entitiesObj.name, entities: collection });
01486 collectionNames.push(entitiesObj.name);
01487 }
01488 }
01489
01490 var displayColumns = [
01491 {
01492 text: "Entity Name",
01493 dataField: "name",
01494 editable: false,
01495 cellClassName: CellClass
01496 },
01497 {
01498 text: "Version",
01499 dataField: "version",
01500 editable: true,
01501 columntype: "template",
01502 initEditor: function (rowKey, cellvalue, editor) {
01503 var row = tag.find("#grid").jqxTreeGrid("getRow", rowKey);
01504 var index1 = -1;
01505 var index2 = -1;
01506 for (var r in dataObj) {
01507 if (dataObj.hasOwnProperty(r)) {
01508 if (row.id.indexOf(dataObj[r].name) === 0) {
01509 index1 = r;
01510 }
01511 }
01512 }
01513 if (index1 >= 0) {
01514 var localData = dataObj[index1];
01515 for (var rr in localData.entities) {
01516 if (localData.entities.hasOwnProperty(rr)) {
01517 if (row.id === localData.entities[rr].id) {
01518 index2 = rr;
01519 }
01520 }
01521 }
01522 if (index2 >= 0) {
01523 var versionsSource = { datatype: "array", datafields: [{ name: "name", type: "string" }], localdata: dataObj[index1].entities[index2].versions };
01524
01525 var versionsAdapter = new $.jqx.dataAdapter(versionsSource, { autoBind: true });
01526 editor.jqxDropDownList({ source: versionsAdapter, displayMember: "name", valueMember: "name", selectedIndex: 0 }).jqxDropDownList("refresh");
01527 }
01528 }
01529
01530 editor.jqxDropDownList("selectItem", cellvalue);
01531 },
01532 getEditorValue: function (row, cellvalue, editor) {
01533
01534 return editor.val();
01535 },
01536 cellClassName: CellClass
01537 }
01538 ];
01539
01540 tag.html("<br><button type=\"button\" class=\"miniButton\" id=\"all1\"> Select All </button><button type=\"button\" class=\"miniButton\" id=\"none1\"> Select None </button><br>" +
01541 "<div id=\"grid\" class=\"jqxTreeGrid\"></div><br>" +
01542 "<button type=\"button\" class=\"miniButton\" id=\"all2\"> Select All </button><button type=\"button\" class=\"miniButton\" id=\"none2\"> Select None </button>");
01543
01544 tag.find("#none1").jqxButton({ height: 30 });
01545 tag.find("#all1").jqxButton({ height: 30 });
01546 tag.find("#none2").jqxButton({ height: 30 });
01547 tag.find("#all2").jqxButton({ height: 30 });
01548
01549 var dataFields = [
01550 { name: "id", type: "string", editable: false, display: false },
01551 { name: "name", type: "string", editable: false, display: true },
01552 { name: "version", type: "string", editable: true, display: true },
01553 { name: "versions", type: "array", editable: false, display: false },
01554 { name: "edited", type: "boolean", editable: false, display: false },
01555 { name: "entities", type: "array", editable: false, display: false }
01556 ];
01557 var source = {
01558 dataType: "json",
01559 dataFields: dataFields,
01560 id: "id",
01561 hierarchy: {
01562 root: "entities"
01563 },
01564 localData: dataObj
01565 };
01566
01567 var dataAdapter = new $.jqx.dataAdapter(source);
01568
01569 tag.find("#grid").jqxTreeGrid({
01570 width: "100%",
01571 source: dataAdapter,
01572 sortable: true,
01573 editable: true,
01574 columnsResize: true,
01575 checkboxes: true,
01576 hierarchicalCheckboxes: true,
01577 columns: displayColumns
01578 });
01579 for (var n in collectionNames) {
01580 if (collectionNames.hasOwnProperty(n)) {
01581 tag.find("#grid").jqxTreeGrid("lockRow", collectionNames[n]);
01582 }
01583 }
01584
01585
01586
01587 tag.find("#none1").mousedown(function () {
01588 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01589 for (var r in rows) {
01590 if (rows.hasOwnProperty(r)) {
01591 if (rows[r].checked) {
01592 tag.find("#grid").jqxTreeGrid("uncheckRow", rows[r].uid);
01593 }
01594 }
01595 }
01596 });
01597 tag.find("#all1").mousedown(function () {
01598 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01599 for (var r in rows) {
01600 if (rows.hasOwnProperty(r)) {
01601 if (!rows[r].checked) {
01602 tag.find("#grid").jqxTreeGrid("checkRow", rows[r].uid);
01603 }
01604 }
01605 }
01606 });
01607 tag.find("#none2").mousedown(function () {
01608 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01609 for (var r in rows) {
01610 if (rows.hasOwnProperty(r)) {
01611 if (rows[r].checked) {
01612 tag.find("#grid").jqxTreeGrid("uncheckRow", rows[r].uid);
01613 }
01614 }
01615 }
01616 });
01617
01618 tag.find("#all2").mousedown(function () {
01619 var rows = tag.find("#grid").jqxTreeGrid("getRows");
01620 for (var r in rows) {
01621 if (rows.hasOwnProperty(r)) {
01622 if (!rows[r].checked) {
01623 tag.find("#grid").jqxTreeGrid("checkRow", rows[r].uid);
01624 }
01625 }
01626 }
01627 });
01628 });
01629 }
01630
01631 function SaveConfig() {
01632 console.log("Saving Configuration Changes");
01633 var files = [];
01634 $(".file-tab.editedValue a")
01635 .each(function () {
01636 var log = $("#changes", $(this).attr("href")).val();
01637 var collection = $("#metadataCollection", $(this).attr("href")).val();
01638 var entities = [];
01639 var rows = $("#metadataEntities", $(this).attr("href")).jqxTreeGrid('getRows');
01640 for (var i = 0; i < rows.length; i++) {
01641
01642 entities.push(rows[i].name);
01643 }
01644 var version = $("#metadataVersion", $(this).attr("href")).val();
01645 files.push({ entities: entities, changelog: log, collection: collection, version: version });
01646 });
01647
01648 AjaxPost("/db/saveConfig",
01649 {
01650 oldConfigName: CurrentNamedConfig,
01651 newConfigName: $("#configName").val(),
01652 files: files,
01653 user: UserId
01654 },
01655 function (res) {
01656 if (res !== null && res !== undefined && res.Success) {
01657 UpdateHeader(false, false, "Configuration Saved.");
01658 GetConfigList();
01659 } else {
01660 UpdateHeader(true, false, "Failed to save configuration!");
01661 }
01662 });
01663 EditedValues = {};
01664 };
01665
01666 function DiscardConfig() {
01667 console.log("Discarding Configuration Changes");
01668 var files = [];
01669 $(".file-tab.editedValue").each(function () {
01670 files.push({ name: $(this).text() });
01671 });
01672
01673 AjaxPost("/db/discardConfig", { configName: CurrentNamedConfig, files: files, user: UserId }, function (res) {
01674 if (res.Success) {
01675 GetConfigList();
01676 } else {
01677 UpdateHeader(true, false, "Failed to discard configuration. Make sure you have a valid configuration selected.\nIf this problem persists, call an expert.");
01678 }
01679 });
01680 EditedValues = {};
01681 };
01682
01683 function GetDbConfig() {
01684
01685 AjaxGet("/db/getDbConfig",
01686 function (data) {
01687 if (data.Success) {
01688 $("#dbType").val(data.dbprovider).trigger("change");
01689 $("#baseDir").val(data.baseDir);
01690 $("#databases").html(data.data.join("")).trigger("create").selectmenu("refresh");
01691 var database = GetUrlParameter("database");
01692 if (database !== undefined && database !== "") {
01693 $("#databases").val(database).trigger("change");
01694 } else {
01695 $("#databases").val(data.instanceName).trigger("change");
01696 }
01697 }
01698 GetConfigList();
01699 });
01700 }
01701
01702 function UpdateDbConfig() {
01703 var config = {
01704 dbprovider: $("#dbType").val(),
01705 baseDir: $("#baseDir").val(),
01706 instanceName: $("#databases").val()
01707 };
01708
01709 AjaxPost("/db/updateDbConfig",
01710 config,
01711 function (res) {
01712 if (res.Success) {
01713 GetDbConfig();
01714 } else {
01715 UpdateHeader(true,
01716 false,
01717 "Failed to update Database Module Configuration. Please See server logs for more details.");
01718 }
01719 }
01720 );
01721 }
01722
01723 function MakeNewDatabase() {
01724 var newDBName = { name: $("#newDatabaseName").val() };
01725 AjaxPost("/db/makeNewDBInstance",
01726 newDBName, function (res) {
01727 if (res.Success) {
01728 GetDbConfig();
01729 } else {
01730 UpdateHeader(true, false, "Failed to create new Database Instance. Please see server logs for more details.");
01731 }
01732 }
01733 );
01734 }
01735
01736 function RegisterButtonFunctions() {
01737 $("#loadConfigButton").on("click", function () { LoadConfig(); });
01738 $("#getConfigListButton").on("click", function () { GetConfigList(); });
01739 $("#saveConfigButton").on("click", function () { SaveConfig(); });
01740 $("#discardConfigButton").on("click", function () { DiscardConfig(); });
01741 $("#searchCurrentConfigButton").on("click", function () { SearchCurrentConfig(); });
01742 $("#baseConfigButton").on("click", function () { BaseConfig(); });
01743 $("#saveNewConfigButton").on("click", function () { SaveNewConfig(); });
01744 $("#baseExportConfigButton").on("click", function () { BaseExportConfig(); });
01745 $("#exportFilesButton").on("click", function () { ExportFiles(); });
01746 $("#addRowToFileUploaderButton").on("click", function () { AddRowToFileUploader(); });
01747 $("#uploadFhiclFileButton").on("click", function () { UploadFhiclFile(); });
01748 $("#updateDBConfigButton").on("click", function () { UpdateDbConfig(); });
01749 $("#createNewDatabaseButton").on("click", function () { MakeNewDatabase(); });
01750 }
01751
01752 (function ($, sr) {
01753
01754
01755
01756 var debounce = function (func, threshold, execAsap) {
01757 var timeout;
01758
01759 return function debounced() {
01760 var obj = this, args = arguments;
01761 function delayed() {
01762 if (!execAsap)
01763 func.apply(obj, args);
01764 timeout = null;
01765 };
01766
01767 if (timeout)
01768 clearTimeout(timeout);
01769 else if (execAsap)
01770 func.apply(obj, args);
01771
01772 timeout = setTimeout(delayed, threshold || 100);
01773 };
01774 };
01775
01776
01777 jQuery.fn[sr] = function (fn) { return fn ? this.bind("resize", debounce(fn)) : this.trigger(sr); };
01778
01779 })(jQuery, "smartresize");
01780
01781 $(document).ready(function () {
01782 DefaultColor = $("#header").css("background-color");
01783 DefaultShadow = $("#header").css("text-shadow");
01784
01785 $.get("/db/Tables.html", function (data) {
01786 TableHtml = data;
01787 });
01788
01789 $.get("/db/FileInfo.html", function (data) {
01790 InfoHtml = data;
01791 });
01792
01793 $.get("/db/TreeGrid.html", function (data) {
01794 TreeGridHtml = data;
01795 });
01796
01797 $.get("/db/Dialog.html", function (data) { DialogContentHtml = data; });
01798
01799 $(".configInfo-tab").on("click", function () {
01800 ResizeTextAreas();
01801 });
01802
01803 RegisterTabFunctions();
01804 $(".tabs #tab1").show().siblings().hide();
01805
01806 $(".triggersModified").change(function () {
01807 UpdateHeader(false, true, "There are pending unsaved changes. Please save or discard before closing the editor!");
01808 });
01809
01810 $(window).smartresize(function () {
01811 $(".jqxTreeGrid").jqxTreeGrid({ width: "100%" }).jqxTreeGrid("refresh");
01812 });
01813
01814 $("#newConfig").on("collapsibleexpand", function () {
01815 SetupEntityVersionPicker($("#configurationPicker"));
01816 });
01817
01818 $("#exportFile").on("collapsibleexpand", function () {
01819 SetupEntityVersionPicker($("#filePicker"));
01820 });
01821
01822 $("#uploadFile")
01823 .on("collapsibleexpand",
01824 function () {
01825 SetupFileUploadTable($("#fileUploader"));
01826 });
01827
01828 $("#dbType").on("change", function () {
01829 var dbtype = $("#dbType").val();
01830 if (dbtype === "filesystem") {
01831 $("#filesystemdbConfig").show();
01832 $("#mongodbConfig").hide();
01833 } else if (dbtype === "mongo") {
01834 $("#filesystemdbConfig").hide();
01835 $("#mongodbConfig").show();
01836 }
01837 }).trigger("change");
01838
01839 $("#databases").on("change", function () {
01840 var instanceName = $("#databases").val();
01841 if (instanceName === "NONE") {
01842 $("#newDatabaseFS").show();
01843 } else {
01844 $("#newDatabaseFS").hide();
01845 UpdateDbConfig();
01846 }
01847 }).trigger("change");
01848
01849 GetDbConfig();
01850
01851 RegisterButtonFunctions();
01852 });