|
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Transitional//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-transitional.dtd">
|
|
<html xmlns="http://www.w3.org/1999/xhtml">
|
|
<head>
|
|
<meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
|
|
<title>Requirements and Test Purposes</title>
|
|
<script type="text/javascript" src="unieditor_hotkeys.js"></script>
|
|
<script type="text/javascript" src="jquery/jquery.js"></script>
|
|
<script type="text/javascript" src="jquery/jquery.actual.js"></script>
|
|
<script type="text/javascript" src="ckeditor/ckeditor.js"></script>
|
|
<script type="text/javascript" src="ckeditor/adapters/jquery.js"></script>
|
|
|
|
<script type="text/javascript" src="testdb.js"></script>
|
|
<link rel="stylesheet" type="text/css" href="testdb.css" />
|
|
|
|
<style type="text/css">
|
|
body {
|
|
font-family: sans-serif;
|
|
}
|
|
blockquote.indent {
|
|
border-left: solid 1px transparent;
|
|
padding-left: 5px;
|
|
margin-bottom: 0;
|
|
margin-right: 0;
|
|
}
|
|
blockquote.collapsable {
|
|
border-left: dotted 1px black;
|
|
}
|
|
img.plusminus {
|
|
cursor: pointer;
|
|
margin-left: -18px;
|
|
float: left;
|
|
width: 9px;
|
|
height: 9px;
|
|
}
|
|
img.imgstatus {
|
|
cursor: pointer;
|
|
border: solid 1px transparent;
|
|
border-radius: 3px;
|
|
-moz-border-radius: 3px;
|
|
-webkit-border-radius: 3px;
|
|
padding: 4px;
|
|
}
|
|
img.imgstatus:hover {
|
|
background-color: #f7f7ff;
|
|
border-color: #c0c0c0;
|
|
}
|
|
.nodectrls, .nodectrls-virtual {
|
|
padding: 2px;
|
|
background-color: #e9f1fa;
|
|
background-image: linear-gradient(bottom, #dbe3f6 0%, #f7ffff 100%);
|
|
background-image: -moz-linear-gradient(bottom, #dbe3f6 0%, #f7ffff 100%);
|
|
background-image: -webkit-linear-gradient(bottom, #dbe3f6 0%, #f7ffff 100%);
|
|
border: solid 1px #c0c0c0;
|
|
border-radius: 3px;
|
|
-moz-border-radius: 3px;
|
|
-webkit-border-radius: 3px;
|
|
}
|
|
.reqctrls {
|
|
margin-right: 3px;
|
|
}
|
|
.cmtctrls {
|
|
margin: 3px 3px 0 0;
|
|
}
|
|
.menu {
|
|
padding: 2px;
|
|
}
|
|
.menu-item > table, .menu-item-disabled > table {
|
|
width: 100%;
|
|
border: none;
|
|
border-collapse: collapse;
|
|
}
|
|
.menu-item > table > tbody > tr > td, .menu-item-disabled > table > tbody > tr > td {
|
|
border: none;
|
|
}
|
|
.menu-item, .menu-item-disabled {
|
|
white-space: nowrap;
|
|
font-size: 75%;
|
|
padding: 2px;
|
|
border: solid 1px transparent;
|
|
border-radius: 3px;
|
|
-moz-border-radius: 3px;
|
|
-webkit-border-radius: 3px;
|
|
}
|
|
.menu-item {
|
|
cursor: pointer;
|
|
color: #4040c0;
|
|
}
|
|
.menu-item-disabled {
|
|
cursor: default;
|
|
color: #808080;
|
|
}
|
|
.menu-item:hover {
|
|
border-color: #a0a0d0;
|
|
background-color: #d0e0f0;
|
|
}
|
|
.menu-item > img, .menu-item-disabled > img {
|
|
vertical-align: text-bottom;
|
|
}
|
|
div.supported-node .nodectrls {
|
|
visibility: hidden;
|
|
}
|
|
div.supported-node:hover .nodectrls {
|
|
visibility: visible;
|
|
}
|
|
.reqname {
|
|
font-weight: bold;
|
|
font-size: 125%;
|
|
}
|
|
.editable, .noneditable, .renamable, .nonrenamable {
|
|
padding: 2px;
|
|
border: solid 1px transparent;
|
|
border-radius: 4px;
|
|
-moz-border-radius: 4px;
|
|
-webkit-border-radius: 4px;
|
|
}
|
|
.focused .editable, .focused .renamable {
|
|
cursor: pointer;
|
|
}
|
|
.focused .editable:hover, .focused .renamable:hover {
|
|
background-color: #f7f7ff;
|
|
border: solid 1px #c0c0c0;
|
|
}
|
|
.requirement {
|
|
border: solid 1px transparent;
|
|
border-radius: 4px;
|
|
-moz-border-radius: 4px;
|
|
-webkit-border-radius: 4px;
|
|
}
|
|
.droppable {
|
|
background-color: #efffff;
|
|
border-color: #4f6f8f;
|
|
}
|
|
.disabled {
|
|
opacity: 0.4;
|
|
}
|
|
.editable > p, .noneditable > p {
|
|
margin: 0;
|
|
}
|
|
.comment {
|
|
min-height: 28px;
|
|
margin: 0.5em 1em 0.5em 3em;
|
|
background: #e0f0ff;
|
|
border: solid 1px #004080;
|
|
border-radius: 8px;
|
|
-moz-border-radius: 8px;
|
|
-webkit-border-radius: 8px;
|
|
}
|
|
.comment > .cmtdesc {
|
|
min-height: 18px;
|
|
margin: 2px;
|
|
font-size: 75%;
|
|
font-style: italic;
|
|
}
|
|
.supported-node:hover, .supported-node-hovered {
|
|
border: solid 1px #a0a0a0;
|
|
}
|
|
.unsupported-node {
|
|
margin: 1em;
|
|
padding: 0.3em;
|
|
border: solid 1px #004080;
|
|
border-radius: 4px;
|
|
-moz-border-radius: 4px;
|
|
-webkit-border-radius: 4px;
|
|
}
|
|
.focused {
|
|
background-color: #ffefff;
|
|
border: solid 1px #ff0000;
|
|
}
|
|
.focused:hover {
|
|
border: solid 1px #ff0000;
|
|
}
|
|
.status-normal {
|
|
color: #000000;
|
|
}
|
|
.status-complete {
|
|
color: #a06000;
|
|
}
|
|
.status-verified {
|
|
color: #00a000;
|
|
}
|
|
table.attributes {
|
|
border: solid 1px gray;
|
|
background: #f3f3f3;
|
|
border-collapse: collapse;
|
|
}
|
|
table.attributes > tbody > tr > th {
|
|
border: solid 1px gray;
|
|
background: #e0e0e0;
|
|
}
|
|
table.attributes > tbody > tr > td {
|
|
font-family: monospace;
|
|
border: solid 1px gray;
|
|
}
|
|
</style>
|
|
|
|
<script type="text/javascript">
|
|
// <![CDATA[
|
|
|
|
// Assign default UniEditor hotkeys
|
|
// Note: JS cannot distinguish some keys like '=' and 'Num+'; '-' and 'Num-'; etc.
|
|
hotkeyManager.registerHotkeys({
|
|
'Ctrl+Up': { handlerGlobal: null, handlerCKEditor: editPrevious },
|
|
'Ctrl+Down': { handlerGlobal: null, handlerCKEditor: editNext },
|
|
'Esc': { handlerGlobal: closeEditor, handlerCKEditor: closeEditor },
|
|
'Ctrl+S': { handlerGlobal: saveEditor, handlerCKEditor: saveEditor },
|
|
'Up': { handlerGlobal: focusPrevious, handlerCKEditor: null },
|
|
'Down': { handlerGlobal: focusNext, handlerCKEditor: null },
|
|
'Left': { handlerGlobal: navigateLeft, handlerCKEditor: null },
|
|
'Right': { handlerGlobal: navigateRight, handlerCKEditor: null },
|
|
'PageUp': { handlerGlobal: pageUp, handlerCKEditor: null },
|
|
'PageDown': { handlerGlobal: pageDown, handlerCKEditor: null },
|
|
'Home': { handlerGlobal: focusFirst, handlerCKEditor: null },
|
|
'End': { handlerGlobal: focusLast, handlerCKEditor: null },
|
|
'Alt+Ins': { handlerGlobal: addChildRequirementConfirm, handlerCKEditor: null },
|
|
'Alt+C': { handlerGlobal: addComment, handlerCKEditor: null },
|
|
'Del': { handlerGlobal: deleteNodeConfirm, handlerCKEditor: null },
|
|
'Enter': { handlerGlobal: editDescription, handlerCKEditor: saveNameId },
|
|
'F2': { handlerGlobal: editNameId, handlerCKEditor: editNameId },
|
|
'Alt+S': { handlerGlobal: changeStatus, handlerCKEditor: null },
|
|
'Num+': { handlerGlobal: expandNode, handlerCKEditor: null },
|
|
'Num-': { handlerGlobal: collapseNode, handlerCKEditor: null },
|
|
'Ctrl+C': { handlerGlobal: copyNodeToClipboard, handlerCKEditor: null },
|
|
'Ctrl+X': { handlerGlobal: cutNodeToClipboard, handlerCKEditor: null },
|
|
'Ctrl+V': { handlerGlobal: pasteNodeAsSibling, handlerCKEditor: null },
|
|
'Ctrl+Shift+V': { handlerGlobal: pasteNodeAsChild, handlerCKEditor: null },
|
|
'Ctrl+Alt+V': { handlerGlobal: pasteSubtreeAsSibling, handlerCKEditor: null },
|
|
'Ctrl+Alt+Shift+V': { handlerGlobal: pasteSubtreeAsChild, handlerCKEditor: null }
|
|
});
|
|
|
|
// Time (in milliseconds) that animations will take
|
|
var animationPeriod = 200;
|
|
|
|
// jQuery array of all elements that can accept keyboard focus
|
|
var all_active_elems;
|
|
|
|
// jQuery array of all elements that can be opened for editing
|
|
var all_editable_elems;
|
|
|
|
// Index of the element that has keyboard focus
|
|
var keyboard_focus;
|
|
|
|
// Concept: no more than one editor instance is opened at any moment of time.
|
|
// Keep this instance in a global variable.
|
|
var editor = null;
|
|
|
|
// Keeps the current read-only mode (ORed values)
|
|
var readOnlyMode = 0;
|
|
const EDIT_MODE_REQ_RO = 0x01; // Requirements are read-only
|
|
|
|
// Custom toolbar that includes only those tools that are useful,
|
|
// plus two custom Requality buttons (Save, Exit).
|
|
CKEDITOR.config.toolbar_Requality = [
|
|
{ name: 'document', items : [ 'Source', '-', 'RequalitySave', 'RequalityExit' ] },
|
|
{ name: 'clipboard', items : [ 'SelectAll', 'Cut', 'Copy', 'Paste', 'PasteText', 'PasteFromWord', '-', 'Undo', 'Redo' ] },
|
|
'/',
|
|
{ name: 'basicstyles', items : [ 'Bold', 'Italic', 'Underline', 'Strike', 'Subscript', 'Superscript', '-', 'RemoveFormat', '-', 'NumberedList', 'BulletedList' ] },
|
|
{ name: 'links', items : [ 'Image', 'Link', 'Unlink', '-', 'Table', 'HorizontalRule', 'SpecialChar' ] }
|
|
];
|
|
|
|
// Actions to execute when CKEditor Save command is called for different types of fields
|
|
var saveAction = {
|
|
'reqname': function (uuid, new_data) {
|
|
changeNodeAttr(uuid, '_name', new_data);
|
|
},
|
|
'reqdesc': function (uuid, new_data) {
|
|
changeNodeAttr(uuid, '_description', new_data);
|
|
},
|
|
'cmtdesc': function (uuid, new_data) {
|
|
changeNodeAttr(uuid, '_description', new_data);
|
|
}
|
|
};
|
|
|
|
// Opens editor window in place of the specific DIV element. The previous editor
|
|
// instance (if present) is closed (saving all the changes).
|
|
// Input parameters:
|
|
// elem - DIV element to be replaced with the editor (if null, editor will not open)
|
|
// simplified - whether editor should be a simplified version (for in-place renaming)
|
|
// cleanHtml - whether editor should be a simplified version (for in-place renaming)
|
|
// Return value:
|
|
// none
|
|
function putEditorWithHtmlClean(elem, simplified, cleanHtml) {
|
|
if (!elem)
|
|
return;
|
|
|
|
// Clear the node-level clipboard
|
|
internalClipboard = null;
|
|
|
|
// Open new CKEditor instance
|
|
if (simplified) {
|
|
// Simplified version of the editor: no toolbar, no statusbar,
|
|
// special skin without borders
|
|
editor = CKEDITOR.replace(elem, {
|
|
bodyClass: 'miniCKE',
|
|
autoParagraph: false,
|
|
toolbarStartupExpanded: false,
|
|
toolbarCanCollapse: false,
|
|
skin: 'simple',
|
|
toolbar: [],
|
|
height: ($(elem).hasClass('reqname') ? '4ex' : '2.5ex'),
|
|
startupShowBorders: false,
|
|
resize_enabled: false,
|
|
removePlugins: 'elementspath',
|
|
forcePasteAsPlainText: cleanHtml,
|
|
extraPlugins: 'requality'
|
|
});
|
|
}
|
|
else {
|
|
editor = CKEDITOR.replace(elem, {
|
|
bodyClass: 'normalCKE',
|
|
autoParagraph: false,
|
|
toolbar: 'Requality',
|
|
toolbarStartupExpanded: !CKEDITOR.toolbarHidden,
|
|
extraPlugins: 'requality',
|
|
forcePasteAsPlainText: cleanHtml
|
|
});
|
|
}
|
|
$(document).bind('click.ckeditor', function (e) {
|
|
// If user clicked outside of editor - save & close it
|
|
e.preventDefault();
|
|
saveEditor();
|
|
});
|
|
editor.on('destroy', function (e) {
|
|
$(document).unbind('click.ckeditor');
|
|
editor = null;
|
|
});
|
|
editor.on('dialogShow', function (e) {
|
|
// Stop clicks in the dialog from bubbling up to document
|
|
// (Cannot use global live() handler because the bind()'ed event will be called anyway)
|
|
$(CKEDITOR.dialog.getCurrent().getElement().$).find('.cke_dialog').unbind('click.ckeditor').bind('click.ckeditor', function (e) {
|
|
e.preventDefault();
|
|
e.stopPropagation();
|
|
});
|
|
});
|
|
editor.on('instanceReady', function (e) {
|
|
e.editor.container.scrollIntoView();
|
|
e.editor.focus();
|
|
$(editor.container.$).bind('click', function (e) {
|
|
// If user clicked inside CKEditor stop the event bubble
|
|
// so that the document-wide click handler was not triggered
|
|
e.stopPropagation();
|
|
});
|
|
$($(editor.container.$).find('iframe')[0].contentDocument).bind('keydown', function (e) {
|
|
// Catch hotkeys pressed inside the editor
|
|
var elem = $(editor.container.$).closest('.supported-node')[0];
|
|
if (hotkeyManager.execHotkeyAction(e, 'handlerCKEditor', elem, extractUUID(elem.id))) {
|
|
e.stopPropagation();
|
|
}
|
|
});
|
|
});
|
|
var uuid = extractUUID(elem.id);
|
|
editor.on('beforeCommandExec', function (e) {
|
|
if (e.data.name == 'requalitySave') {
|
|
var elem = editor.element.$;
|
|
var new_data = e.editor.getData();
|
|
if ($(elem).html() == '')
|
|
$(elem).html(' ');
|
|
var pos = elem.id.indexOf('-');
|
|
var field_type = elem.id.substr(0, pos);
|
|
var uuid = elem.id.substr(pos + 1);
|
|
if (saveAction[field_type])
|
|
saveAction[field_type](uuid, new_data);
|
|
}
|
|
});
|
|
}
|
|
|
|
// Opens editor window in place of the specific DIV element. The previous editor
|
|
// instance (if present) is closed (saving all the changes).
|
|
// Input parameters:
|
|
// elem - DIV element to be replaced with the editor (if null, editor will not open)
|
|
// simplified - whether editor should be a simplified version (for in-place renaming)
|
|
// Return value:
|
|
// none
|
|
function putEditor(elem, simplified) {
|
|
putEditorWithHtmlClean(elem, simplified, false);
|
|
}
|
|
|
|
// Toggles (shows or hides) the block with children requirements.
|
|
// Input parameters:
|
|
// uuid - UUID of the parent requirement
|
|
// Return value:
|
|
// none
|
|
function toggleChildren(uuid) {
|
|
var req_children_div = $('#reqchildren-' + uuid);
|
|
var img_elem = $('#block-' + uuid).children('img.plusminus');
|
|
if (req_children_div.is(':hidden')) {
|
|
req_children_div.slideDown(animationPeriod);
|
|
$(img_elem).attr('src', 'images/collapse.png').attr('alt', '[−]');
|
|
}
|
|
else {
|
|
req_children_div.slideUp(animationPeriod, function () {
|
|
if ($(all_active_elems[keyboard_focus]).is(':hidden'))
|
|
setFocusByUUID(uuid);
|
|
});
|
|
$(img_elem).attr('src', 'images/expand.png').attr('alt', '[+]');
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// External functions implemented and injected by Requality
|
|
|
|
// EMULATION BEGIN
|
|
// If running outside of Eclipse the functions are missing, and emulation will be used instead
|
|
|
|
// Request for the specific node data
|
|
// Input parameters:
|
|
// uuid - (String) uuid of the requested node
|
|
// Return value:
|
|
// String value containing JSON definition of the node.
|
|
if (typeof(getNodeByUUID) == 'undefined')
|
|
getNodeByUUID = function (uuid) {
|
|
// EMULATION
|
|
var elems = {
|
|
'7547c386-6c11-43ce-843f-42a39642cd1e': '{ "attributes": {"_type": { "key": "_type", "type": "STRING", "value": "Requirement" }}, "children": [ "648c2725-4db2-4ad1-8254-aaf4d1aa67fa", "f6c854e9-9058-4b36-a6dc-461b059969cf", "e23c5275-46c7-4e6f-8669-ee6d36f4003f", "450d5815-da17-404d-af93-0e75976ef961" ], "id": "Requirements", "uuid": "7547c386-6c11-43ce-843f-42a39642cd1e" }',
|
|
'648c2725-4db2-4ad1-8254-aaf4d1aa67fa': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "Arrays — arrays of arbitrary elements which grow automatically as elements are added." }, "_locations": { "key": "_locations", "type": "LIST", "value": [ "/Documents/glib-Arrays-utf8.xhtml/f86b1005-6303-4684-8af4-ea95391ced59", "/Documents/glib-Arrays-utf8.xhtml/be322b91-624d-4ce8-ab30-bc5132f1b857" ] }, "_name": { "key": "_name", "type": "STRING", "value": "Arrays" }, "coverageStatus": { "key": "status", "type": "STRING", "value": "complete" }, "_predicate": { "key": "_predicate", "type": "STRING", "value": "" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": ["487a7a6c-97c2-4929-aac4-01bc2e09a00d"], "id": "Arrays", "uuid": "648c2725-4db2-4ad1-8254-aaf4d1aa67fa" }',
|
|
'487a7a6c-97c2-4929-aac4-01bc2e09a00d': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "asdf " }, "_name": { "key": "_name", "type": "STRING", "value": "ztest2" }, "coverageStatus": { "key": "status", "type": "STRING", "value": "verified" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [ "7908eb9f-aa8f-4675-a258-73999b85d35b", "f16d7738-4495-43d4-961d-636f2ddf8fb6", "7e59e682-3a1a-49bc-8967-db43bac7653e" ], "id": "z02", "uuid": "487a7a6c-97c2-4929-aac4-01bc2e09a00d" }',
|
|
'f16d7738-4495-43d4-961d-636f2ddf8fb6': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "Short comment test." }, "_type": { "key": "_type", "type": "STRING", "value": "Comment" } }, "children": [], "uuid": "f16d7738-4495-43d4-961d-636f2ddf8fb6" }',
|
|
'7908eb9f-aa8f-4675-a258-73999b85d35b': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "<p>\\n\\ttest<br />\\n\\t-- Expected results:<br />\\n\\tfas er awef ae w fawefawefa wefawefawsfa wefawefaw<\\/p>\\n<p>\\n\\t awe fawe<\\/p>\\n<p>\\n\\tfaw efa wefaw4 fawef<\\/p>\\n" }, "_type": { "key": "_type", "type": "STRING", "value": "TestPurpose" }, "_expectedResults": { "key": "_expectedResults", "type": "STRING", "value": "" } }, "children": [ "f1ef5c76-50de-444e-a054-0258f257e814", "fe8af46b-b212-4307-bfe2-bae87377fb5b" ], "id": "tp01", "uuid": "7908eb9f-aa8f-4675-a258-73999b85d35b" }',
|
|
'7e59e682-3a1a-49bc-8967-db43bac7653e': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "fffff<br />\\n-- Expected results:<br />\\nbbbbb" }, "_type": { "key": "_type", "type": "STRING", "value": "TestPurpose" }, "_expectedResults": { "key": "_expectedResults", "type": "STRING", "value": "" } }, "children": [], "id": "tp02", "uuid": "7e59e682-3a1a-49bc-8967-db43bac7653e" }',
|
|
'f1ef5c76-50de-444e-a054-0258f257e814': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "First comment<br />Testing multi-line<br />and also very long lines that should be wrapped automatically without any explicit line breaks that might have been inserted here by the author of this not very useful comment." }, "_type": { "key": "_type", "type": "STRING", "value": "Comment" } }, "children": [], "uuid": "f1ef5c76-50de-444e-a054-0258f257e814" }',
|
|
'fe8af46b-b212-4307-bfe2-bae87377fb5b': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "Second comment.<br />Also multi-line." }, "_type": { "key": "_type", "type": "STRING", "value": "Comment" } }, "children": [], "uuid": "fe8af46b-b212-4307-bfe2-bae87377fb5b" }',
|
|
'f6c854e9-9058-4b36-a6dc-461b059969cf': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/90d7c8a0-d6c1-4917-818f-ff3adbd22ac9"] }, "_name": { "key": "_name", "type": "STRING", "value": "Description" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": ["1b3da610-bac1-4f7f-a896-85fd630fb5fb"], "id": "Description", "uuid": "f6c854e9-9058-4b36-a6dc-461b059969cf" }',
|
|
'1b3da610-bac1-4f7f-a896-85fd630fb5fb': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "test " }, "_name": { "key": "_name", "type": "STRING", "value": "aaa" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "01", "uuid": "1b3da610-bac1-4f7f-a896-85fd630fb5fb" }',
|
|
'e23c5275-46c7-4e6f-8669-ee6d36f4003f': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/632dd13b-53d0-4dee-8657-c0e9c5379cf1"] }, "_name": { "key": "_name", "type": "STRING", "value": "Details" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [ "353f85ad-60c7-4937-aa7c-f61ad149cece", "592b2a1d-85a1-4914-a84e-611e276e6648", "32668cf8-30aa-4fba-ba48-e75440978420", "90000154-39d3-4f22-b014-8a4ce9300cbd", "305efb4b-2862-4eb0-87ea-b3be9fad5366", "7022a620-6c4e-4792-b843-a0429528ab1c", "95246ee6-7a0d-40d4-8927-cf4fb9c7c387", "0f457b52-a32e-4189-8429-ac71e09242b2", "8e3e9f17-820a-488b-b9da-c21284886a32", "92a6ea51-f4e1-4616-9265-2097f31fc315", "e29d7b37-3cd5-411c-bf14-e3b969d00648", "ea87f6b1-8a4d-4f9f-ba6f-6a7fbb5d0185", "ebd9589e-db88-4650-a86f-1bbdad43afe5", "11e3062a-22ca-4c9e-878c-b86b3bbebb94", "8aab3e88-ee47-4ebd-bc5f-32773bdd808b", "e7a50436-59c3-4049-b89a-b62e9b402d67", "150fb6e1-6db6-4175-8470-92fff817550e" ], "id": "Details", "uuid": "e23c5275-46c7-4e6f-8669-ee6d36f4003f" }',
|
|
'353f85ad-60c7-4937-aa7c-f61ad149cece': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/c8f6e1b8-3705-4f37-9a54-4439b0dae732"] }, "_name": { "key": "_name", "type": "STRING", "value": "GArray" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "1", "uuid": "353f85ad-60c7-4937-aa7c-f61ad149cece" }',
|
|
'592b2a1d-85a1-4914-a84e-611e276e6648': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/aa70f1bb-b107-42b1-855e-ba2fb25e43b8"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_insert_val()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": ["7296ee7d-0ded-4b3d-bb0e-49439c0dad40"], "id": "10", "uuid": "592b2a1d-85a1-4914-a84e-611e276e6648" }',
|
|
'7296ee7d-0ded-4b3d-bb0e-49439c0dad40': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/894685ce-1118-4c74-a234-3db81902a388"] }, "_name": { "key": "_name", "type": "STRING", "value": "Note" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "11", "uuid": "7296ee7d-0ded-4b3d-bb0e-49439c0dad40" }',
|
|
'32668cf8-30aa-4fba-ba48-e75440978420': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/d463ead6-cb30-4f1e-b113-d839809f8ba8"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_insert_vals ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "12", "uuid": "32668cf8-30aa-4fba-ba48-e75440978420" }',
|
|
'90000154-39d3-4f22-b014-8a4ce9300cbd': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/0b2ba0a2-0100-4aea-bc1f-a609077001e9"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_remove_index ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "13", "uuid": "90000154-39d3-4f22-b014-8a4ce9300cbd" }',
|
|
'305efb4b-2862-4eb0-87ea-b3be9fad5366': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/c9391045-19bf-4e93-aa52-c9cb4d6ac720"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_remove_index_fast ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "14", "uuid": "305efb4b-2862-4eb0-87ea-b3be9fad5366" }',
|
|
'7022a620-6c4e-4792-b843-a0429528ab1c': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/f9e63e83-2ffb-4da9-9338-72993bc04e9b"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_remove_range ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "15", "uuid": "7022a620-6c4e-4792-b843-a0429528ab1c" }',
|
|
'95246ee6-7a0d-40d4-8927-cf4fb9c7c387': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/249eb7f6-7382-4b64-bdb4-e58bb3657b26"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_sort ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "16", "uuid": "95246ee6-7a0d-40d4-8927-cf4fb9c7c387" }',
|
|
'0f457b52-a32e-4189-8429-ac71e09242b2': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/349098eb-7929-4982-a9e1-335ad676c67e"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_sort_with_data ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "17", "uuid": "0f457b52-a32e-4189-8429-ac71e09242b2" }',
|
|
'8e3e9f17-820a-488b-b9da-c21284886a32': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/9d649d2a-2018-40ea-a960-67c3addfa717"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_index()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "18", "uuid": "8e3e9f17-820a-488b-b9da-c21284886a32" }',
|
|
'92a6ea51-f4e1-4616-9265-2097f31fc315': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/e432e548-4c1d-4952-bb55-42ec129134ed"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_set_size ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "19", "uuid": "92a6ea51-f4e1-4616-9265-2097f31fc315" }',
|
|
'e29d7b37-3cd5-411c-bf14-e3b969d00648': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/7189f0b6-d25c-478e-b571-8884fed147d3"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_new ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "2", "uuid": "e29d7b37-3cd5-411c-bf14-e3b969d00648" }',
|
|
'ea87f6b1-8a4d-4f9f-ba6f-6a7fbb5d0185': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/64f696f7-d82d-4661-b47b-986fea878de5"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_free ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "20", "uuid": "ea87f6b1-8a4d-4f9f-ba6f-6a7fbb5d0185" }',
|
|
'ebd9589e-db88-4650-a86f-1bbdad43afe5': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/e9fbcfac-f9a9-43e4-b115-d25c3d295c39"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_prepend_vals ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "21", "uuid": "ebd9589e-db88-4650-a86f-1bbdad43afe5" }',
|
|
'11e3062a-22ca-4c9e-878c-b86b3bbebb94': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/3ea8bb92-1176-4f0b-a470-2a1c63eff2dc"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_sized_new ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "3", "uuid": "11e3062a-22ca-4c9e-878c-b86b3bbebb94" }',
|
|
'8aab3e88-ee47-4ebd-bc5f-32773bdd808b': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/f6ffd1db-fa39-45c7-a59f-54370bbdc7f8"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_append_val()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": ["43015a6b-5496-4d87-8631-c8d68c4c1b73"], "id": "4", "uuid": "8aab3e88-ee47-4ebd-bc5f-32773bdd808b" }',
|
|
'43015a6b-5496-4d87-8631-c8d68c4c1b73': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/aad27208-103e-4ee5-a52f-b6f44dda27be"] }, "_name": { "key": "_name", "type": "STRING", "value": "Note" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "5", "uuid": "43015a6b-5496-4d87-8631-c8d68c4c1b73" }',
|
|
'e7a50436-59c3-4049-b89a-b62e9b402d67': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/52220d06-e232-4cdc-b517-d828084a3633"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_append_vals ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "6", "uuid": "e7a50436-59c3-4049-b89a-b62e9b402d67" }',
|
|
'150fb6e1-6db6-4175-8470-92fff817550e': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/3d34a515-5348-41b3-8b4c-5aaedc4cce99"] }, "_name": { "key": "_name", "type": "STRING", "value": "g_array_prepend_val()" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": ["db1e9c85-b939-455b-a0e3-9f824bb57edb"], "id": "7", "uuid": "150fb6e1-6db6-4175-8470-92fff817550e" }',
|
|
'db1e9c85-b939-455b-a0e3-9f824bb57edb': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/b13c559f-1bd5-4227-9b50-b0f431acc545"] }, "_name": { "key": "_name", "type": "STRING", "value": "Note" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [], "id": "8", "uuid": "db1e9c85-b939-455b-a0e3-9f824bb57edb" }',
|
|
'450d5815-da17-404d-af93-0e75976ef961': '{ "attributes": { "_locations": { "key": "_locations", "type": "LIST", "value": ["/Documents/glib-Arrays-utf8.xhtml/b58bdbe1-5fbd-4dd2-a05c-cdfb077cd65a"] }, "_name": { "key": "_name", "type": "STRING", "value": "Synopsis" }, "_type": { "key": "_type", "type": "STRING", "value": "Requirement" } }, "children": [ "35dafc37-921c-4335-a872-b85d75313238", "ee5f4b87-97a3-4ca6-83ce-4e71d2deb02e", "c33b01af-c5fc-421d-8511-7ddfba16f0b3" ], "id": "Synopsis", "uuid": "450d5815-da17-404d-af93-0e75976ef961" }',
|
|
'35dafc37-921c-4335-a872-b85d75313238': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "asdf" }, "_type": { "key": "_type", "type": "STRING", "value": "TestPurpose" }, "_author": { "key": "_author", "type": "STRING", "value": "Flint" }, "_expectedResults": { "key": "_expectedResults", "type": "STRING", "value": "sdf" }, "_status": { "key": "_status", "type": "STRING", "value": "complete" }, "_testLocation": { "key": "_testLocation", "type": "STRING", "value": "" }, "_testMethod": { "key": "_testMethod", "type": "STRING", "value": "" } }, "children": [], "id": "01", "uuid": "35dafc37-921c-4335-a872-b85d75313238" }',
|
|
'ee5f4b87-97a3-4ca6-83ce-4e71d2deb02e': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "fda" }, "_type": { "key": "_type", "type": "STRING", "value": "TestPurpose" }, "_author": { "key": "_author", "type": "STRING", "value": "Flint" }, "_expectedResults": { "key": "_expectedResults", "type": "STRING", "value": "" }, "_status": { "key": "_status", "type": "STRING", "value": "verified" }, "_testLocation": { "key": "_testLocation", "type": "STRING", "value": "" }, "_testMethod": { "key": "_testMethod", "type": "STRING", "value": "" } }, "children": [], "id": "02", "uuid": "ee5f4b87-97a3-4ca6-83ce-4e71d2deb02e" }',
|
|
'c33b01af-c5fc-421d-8511-7ddfba16f0b3': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "asd " }, "_type": { "key": "_type", "type": "STRING", "value": "TestPurpose" }, "_author": { "key": "_author", "type": "STRING", "value": "Flint" }, "_expectedResults": { "key": "_expectedResults", "type": "STRING", "value": "" }, "_status": { "key": "_status", "type": "STRING", "value": "in process" }, "_testLocation": { "key": "_testLocation", "type": "STRING", "value": "" }, "_testMethod": { "key": "_testMethod", "type": "STRING", "value": "" } }, "children": [], "id": "04", "uuid": "c33b01af-c5fc-421d-8511-7ddfba16f0b3" }'
|
|
};
|
|
return elems[uuid];
|
|
};
|
|
|
|
if (typeof(getNodeByQID) == 'undefined')
|
|
getNodeByQID = function (uuid) {
|
|
// EMULATION
|
|
var elems = {
|
|
'/Documents/glib-Arrays-utf8.xhtml/90d7c8a0-d6c1-4917-818f-ff3adbd22ac9': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "Description" }, "_hidden": { "key": "_hidden", "type": "BOOL", "value": true }, "_type": { "key": "_type", "type": "STRING", "value": "Location" } }, "children": [], "id": "90d7c8a0-d6c1-4917-818f-ff3adbd22ac9", "uuid": "f8cbc0ce-a2f0-44a8-bd9f-2455d7991508" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/632dd13b-53d0-4dee-8657-c0e9c5379cf1': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "Details" }, "_hidden": { "key": "_hidden", "type": "BOOL", "value": true }, "_type": { "key": "_type", "type": "STRING", "value": "Location" } }, "children": [], "id": "632dd13b-53d0-4dee-8657-c0e9c5379cf1", "uuid": "71b08651-2008-4c5a-8a47-99b796674a93" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/c8f6e1b8-3705-4f37-9a54-4439b0dae732': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "GArray" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "c8f6e1b8-3705-4f37-9a54-4439b0dae732", "uuid": "99e8cc27-8c61-4607-9e20-0300a0841d0a" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/aa70f1bb-b107-42b1-855e-ba2fb25e43b8': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_insert_val()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "aa70f1bb-b107-42b1-855e-ba2fb25e43b8", "uuid": "f66d3aef-d895-4f2f-9b6d-603f3785c4dd" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/894685ce-1118-4c74-a234-3db81902a388': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "Note" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "894685ce-1118-4c74-a234-3db81902a388", "uuid": "022bfd5c-41fa-488d-a842-e731b1e4a369" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/d463ead6-cb30-4f1e-b113-d839809f8ba8': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_insert_vals ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "d463ead6-cb30-4f1e-b113-d839809f8ba8", "uuid": "633c1583-7507-4677-8334-01046c5c5d06" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/0b2ba0a2-0100-4aea-bc1f-a609077001e9': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_remove_index ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "0b2ba0a2-0100-4aea-bc1f-a609077001e9", "uuid": "4ab9ac5f-fe12-49a6-8d49-c9c444082b66" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/c9391045-19bf-4e93-aa52-c9cb4d6ac720': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_remove_index_fast ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "c9391045-19bf-4e93-aa52-c9cb4d6ac720", "uuid": "2b13b58c-3a67-4bd2-8f1d-c1bc98b7b6b9" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/f9e63e83-2ffb-4da9-9338-72993bc04e9b': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_remove_range ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "f9e63e83-2ffb-4da9-9338-72993bc04e9b", "uuid": "9760f68b-4282-4579-9a64-b9f294e2b4f9" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/249eb7f6-7382-4b64-bdb4-e58bb3657b26': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_sort ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "249eb7f6-7382-4b64-bdb4-e58bb3657b26", "uuid": "4b53589b-9d90-4764-bc71-c22b59424e67" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/349098eb-7929-4982-a9e1-335ad676c67e': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_sort_with_data ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "349098eb-7929-4982-a9e1-335ad676c67e", "uuid": "98ce19f5-764a-44a6-b33e-790fde65a9a0" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/9d649d2a-2018-40ea-a960-67c3addfa717': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_index()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "9d649d2a-2018-40ea-a960-67c3addfa717", "uuid": "05c41aee-6982-4240-96c2-b4b5a4653b48" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/e432e548-4c1d-4952-bb55-42ec129134ed': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_set_size ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "e432e548-4c1d-4952-bb55-42ec129134ed", "uuid": "5cbe8a96-66f5-47ac-97a4-a803ac21c33b" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/7189f0b6-d25c-478e-b571-8884fed147d3': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_new ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "7189f0b6-d25c-478e-b571-8884fed147d3", "uuid": "b29195cd-4694-43c0-a088-7339f1c5bda7" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/64f696f7-d82d-4661-b47b-986fea878de5': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_free ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "64f696f7-d82d-4661-b47b-986fea878de5", "uuid": "2b7c272d-3797-4dd9-b129-389d82986cb3" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/e9fbcfac-f9a9-43e4-b115-d25c3d295c39': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_prepend_vals ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "e9fbcfac-f9a9-43e4-b115-d25c3d295c39", "uuid": "b3e61603-8a56-4376-b0e5-c426af4464c5" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/3ea8bb92-1176-4f0b-a470-2a1c63eff2dc': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_sized_new ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "3ea8bb92-1176-4f0b-a470-2a1c63eff2dc", "uuid": "c7a8d363-2f4e-49a4-8ad2-01b8e4073750" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/f6ffd1db-fa39-45c7-a59f-54370bbdc7f8': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_append_val()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "f6ffd1db-fa39-45c7-a59f-54370bbdc7f8", "uuid": "448bdcb0-f343-4944-9d78-f54df659409e" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/aad27208-103e-4ee5-a52f-b6f44dda27be': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "Note" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "aad27208-103e-4ee5-a52f-b6f44dda27be", "uuid": "eda43058-9842-47d5-9a00-ce62889f6da9" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/52220d06-e232-4cdc-b517-d828084a3633': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_append_vals ()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "52220d06-e232-4cdc-b517-d828084a3633", "uuid": "e73ce2d1-1f34-49cf-bce6-b0417b56cb16" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/3d34a515-5348-41b3-8b4c-5aaedc4cce99': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "g_array_prepend_val()" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "3d34a515-5348-41b3-8b4c-5aaedc4cce99", "uuid": "7e25ca6a-949b-4047-9b53-080f44f31542" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/b13c559f-1bd5-4227-9b50-b0f431acc545': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "Note" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "b13c559f-1bd5-4227-9b50-b0f431acc545", "uuid": "f069153b-1e1f-4502-bf41-918f053765bd" }',
|
|
'/Documents/glib-Arrays-utf8.xhtml/b58bdbe1-5fbd-4dd2-a05c-cdfb077cd65a': '{ "attributes": { "_description": { "key": "_description", "type": "STRING", "value": "Synopsis" }, "_type": { "key": "_type", "type": "STRING", "value": "Location" }, "hidden": { "key": "hidden", "type": "BOOL", "value": true } }, "children": [], "id": "b58bdbe1-5fbd-4dd2-a05c-cdfb077cd65a", "uuid": "c7553030-abf0-4a11-b31a-b4669917d57c" }'
|
|
};
|
|
return elems[uuid];
|
|
};
|
|
|
|
// Request for the root element of the selected subtree
|
|
// Input parameters:
|
|
// none
|
|
// Return value:
|
|
// String value containing uuid of the subtree root node
|
|
if (typeof(getStartNode) == 'undefined')
|
|
getStartNode = function () {
|
|
// EMULATION
|
|
return '7547c386-6c11-43ce-843f-42a39642cd1e';
|
|
};
|
|
|
|
// Request to change the node ID
|
|
// Input parameters:
|
|
// uuid - (String) uuid of the updated node
|
|
// new_id - (String) new ID to be set
|
|
// Return value:
|
|
// Boolean value: true if operation was successful, false otherwise
|
|
if (typeof(changeNodeId) == 'undefined')
|
|
changeNodeId = function (uuid, new_id) {
|
|
// EMULATION
|
|
return true;
|
|
};
|
|
|
|
// Request to change the value of one of the node attributes
|
|
// Input parameters:
|
|
// uuid - (String) uuid of the updated node
|
|
// attr_name - (String) name of the changed attribute
|
|
// new_val - (String) new attribute value to be set
|
|
// Return value:
|
|
// Boolean value: true if operation was successful, false otherwise
|
|
if (typeof(changeNodeAttr) == 'undefined')
|
|
changeNodeAttr = function (uuid, attr_name, new_val) {
|
|
// EMULATION
|
|
return true;
|
|
};
|
|
|
|
// Request to move the node into different subtree
|
|
// Input parameters:
|
|
// uuid - (String) uuid of the moved node
|
|
// new_parent_uuid - (String) uuid of the new parent node
|
|
// Return value:
|
|
// Boolean value: true if operation was successful, false otherwise
|
|
if (typeof(changeNodeParent) == 'undefined')
|
|
changeNodeParent = function (uuid, new_parent_uuid) {
|
|
// EMULATION
|
|
return true;
|
|
};
|
|
|
|
// Request to copy the node into different subtree
|
|
// Input parameters:
|
|
// uuid - (String) uuid of the moved node
|
|
// new_parent_uuid - (String) uuid of the new parent node
|
|
// deep - (Boolean) Whether copy with children or only the node itself
|
|
// Return value:
|
|
// Boolean value: true if operation was successful, false otherwise
|
|
if (typeof(copyNode) == 'undefined')
|
|
copyNode = function (uuid, new_parent_uuid, deep) {
|
|
// EMULATION
|
|
return true;
|
|
};
|
|
|
|
// Request to insert a new node
|
|
// Input parameters:
|
|
// parent_uuid - (String) uuid of the parent node
|
|
// node_name - (String) name of the new node
|
|
// node_type - (String) type of the new node
|
|
// Return value:
|
|
// Boolean value: true if operation was successful, false otherwise
|
|
if (typeof(addNode) == 'undefined')
|
|
addNode = function (parent_uuid, node_name, node_type) {
|
|
// EMULATION
|
|
return true;
|
|
};
|
|
|
|
// Request to remove a node with all its decendants
|
|
// Input parameters:
|
|
// uuid - (String) uuid of the removed node
|
|
// Return value:
|
|
// Boolean value: true if operation was successful, false otherwise
|
|
if (typeof(removeNode) == 'undefined')
|
|
removeNode = function (uuid) {
|
|
// EMULATION
|
|
return true;
|
|
};
|
|
|
|
// Request to set focus in Requality window(s)
|
|
// Input parameters:
|
|
// uuid - (String) uuid of the newly focused node
|
|
// Return value:
|
|
// Boolean value: true if operation was successful, false otherwise
|
|
if (typeof(setRequalityFocus) == 'undefined')
|
|
setRequalityFocus = function (uuid) {
|
|
// EMULATION
|
|
return true;
|
|
};
|
|
|
|
// Request for the current read-only mode
|
|
// Input parameters:
|
|
// none
|
|
// Return value:
|
|
// Integer value: bit mask with zero or more possible values:
|
|
// EDIT_MODE_REQ_RO - requirements are disallowed to edit
|
|
// Editing includes changing ID/name, description and adding/removing nodes
|
|
// of the corresponding type. Changing status and adding/removing nodes of
|
|
// other types (e.g. comments) is always allowed.
|
|
if (typeof(getReadOnlyMode) == 'undefined')
|
|
getReadOnlyMode = function () {
|
|
// EMULATION
|
|
return 0;
|
|
};
|
|
|
|
// EMULATION END
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Callback functions that can be called by Requality
|
|
|
|
// Callback function called by Requality when node or some of its children change outside of UniEditor
|
|
// Input parameters:
|
|
// uuid - (String) uuid of the updated node
|
|
// Return value:
|
|
// none
|
|
function onChangeNode(uuid) {
|
|
updateTree(uuid);
|
|
}
|
|
|
|
// Callback function called by Requality when it requests UniEditor to change focus
|
|
// Input parameters:
|
|
// uuid - (String) uuid of the node to set focus to
|
|
// Return value:
|
|
// none
|
|
function onChangeFocus(uuid) {
|
|
// If this is a callback because of setting focus from UniEditor, ignore it
|
|
if (focusOperations.isOperationStored(uuid))
|
|
return;
|
|
// Check whether the focus is already on the requested element
|
|
if (uuid == extractUUID(all_active_elems[keyboard_focus].id))
|
|
return;
|
|
// Search for the requested element
|
|
var new_elem = $('#node-' + uuid);
|
|
if (new_elem.length == 0)
|
|
return;
|
|
if (new_elem.is(':hidden')) {
|
|
// Expand all subtrees from the current element up to the root
|
|
new_elem.parent().parents('blockquote.collapsable').each(function () {
|
|
var node_uuid = extractUUID(this.id);
|
|
if ($('#reqchildren-' + node_uuid).is(':hidden'))
|
|
toggleChildren(node_uuid);
|
|
});
|
|
// Wait for all trees to complete expanding, then set focus
|
|
// (otherwise the element will have wrong coordinates and cannot be scrolled to view)
|
|
setTimeout(function () {
|
|
setFocus(new_elem, true);
|
|
}, animationPeriod);
|
|
}
|
|
else {
|
|
// The desired element is already visible, set the focus immediately
|
|
setFocus(new_elem, true);
|
|
}
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// UniEditor functions
|
|
|
|
// Object for managing self-inflicted focus changes and preventing Requality callbacks
|
|
// from setting the focus on the same items again.
|
|
var focusOperations = (function () {
|
|
this.operations = [];
|
|
|
|
// Registers the setFocus operation
|
|
// Input parameters:
|
|
// uuid - identifier of the node to which the focus is set
|
|
// Return value:
|
|
// none
|
|
this.addOperation = function (uuid) {
|
|
this.operations.push(uuid);
|
|
}
|
|
|
|
// Checks whether the setFocus operation with UUID specified was registered
|
|
// and removes it from the store
|
|
// Input parameters:
|
|
// uuid - identifier of the node to check
|
|
// Return value:
|
|
// true if uuid was found; false otherwise
|
|
this.isOperationStored = function (uuid) {
|
|
for (var i = 0; i < this.operations.length; ++i) {
|
|
if (this.operations[i] == uuid) {
|
|
this.operations.splice(i, 1);
|
|
return true;
|
|
}
|
|
}
|
|
return false;
|
|
}
|
|
|
|
return this;
|
|
})();
|
|
|
|
var readOnlyClasses = {};
|
|
readOnlyClasses[EDIT_MODE_REQ_RO] = 'requirement';
|
|
|
|
// Checks whether the specified element is allowed to edit
|
|
// Input parameters:
|
|
// elem - jQuery object with the element to check
|
|
// Return value:
|
|
// true if element is editable; false otherwise
|
|
function isEditable(elem) {
|
|
for (var flag in readOnlyClasses) {
|
|
if (((readOnlyMode & flag) != 0) && elem.hasClass(readOnlyClasses[flag]))
|
|
return false;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
// Extracts the UUID from DOM element ID
|
|
// Input parameters:
|
|
// id - identifier in the form 'smth-XXXXXXXX-XXXX-XXXX-XXXX-XXXXXXXXXXXX'
|
|
// (UUID with some prefix)
|
|
// Return value:
|
|
// UUID extracted from the ID (prefix removed)
|
|
function extractUUID(id) {
|
|
return id.substr(id.indexOf('-') + 1);
|
|
}
|
|
|
|
// Changes the focus to the new element
|
|
// Input parameters:
|
|
// elem - jQuery object with the element to be focused
|
|
// silently - [optional] if true, do not notify Requality about changes
|
|
// Return value:
|
|
// none
|
|
function setFocus(elem, silently) {
|
|
$(all_active_elems[keyboard_focus]).removeClass('focused');
|
|
keyboard_focus = all_active_elems.index(elem);
|
|
elem.addClass('focused').scrollToView();
|
|
if (!silently) {
|
|
var uuid = extractUUID(elem[0].id);
|
|
focusOperations.addOperation(uuid);
|
|
setRequalityFocus(uuid);
|
|
}
|
|
}
|
|
|
|
// Changes the focus to the new element specified by the index
|
|
// Input parameters:
|
|
// idx - index of the element to be focused
|
|
// silently - [optional] if true, do not notify Requality about changes
|
|
// Return value:
|
|
// none
|
|
function setFocusByIndex(idx, silently) {
|
|
var new_elem = $(all_active_elems[idx]);
|
|
$(all_active_elems[keyboard_focus]).removeClass('focused');
|
|
keyboard_focus = idx;
|
|
$(all_active_elems[keyboard_focus]).addClass('focused').scrollToView();
|
|
if (!silently) {
|
|
var uuid = extractUUID(all_active_elems[keyboard_focus].id);
|
|
focusOperations.addOperation(uuid);
|
|
setRequalityFocus(uuid);
|
|
}
|
|
}
|
|
|
|
// Changes the focus to the new element specified by the UUID
|
|
// Input parameters:
|
|
// uuid - UUID of the element to be focused
|
|
// silently - [optional] if true, do not notify Requality about changes
|
|
// Return value:
|
|
// none
|
|
function setFocusByUUID(uuid, silently) {
|
|
var new_elem = $('#node-' + uuid);
|
|
$(all_active_elems[keyboard_focus]).removeClass('focused');
|
|
keyboard_focus = all_active_elems.index(new_elem);
|
|
$(all_active_elems[keyboard_focus]).addClass('focused').scrollToView();
|
|
if (!silently) {
|
|
focusOperations.addOperation(uuid);
|
|
setRequalityFocus(uuid);
|
|
}
|
|
}
|
|
|
|
// List of available commands for all node types
|
|
var node_commands = {
|
|
'Requirement': {
|
|
'delreq': {
|
|
menu: true,
|
|
name: 'Delete requirement',
|
|
image: 'delete-node.png',
|
|
imageAlt: '[−]',
|
|
readOnlyMode: EDIT_MODE_REQ_RO,
|
|
handler: deleteNodeConfirm
|
|
},
|
|
// 'editattr': {
|
|
// menu: true,
|
|
// name: 'Edit attributes',
|
|
// image: 'edit-attrs.png',
|
|
// imageAlt: '[≡]',
|
|
// readOnlyMode: 0,
|
|
// handler: function (uuid) {}
|
|
// },
|
|
'addreqsib': {
|
|
menu: true,
|
|
name: 'Add sibling requirement',
|
|
image: 'add-req.png',
|
|
imageAlt: '[+]',
|
|
readOnlyMode: EDIT_MODE_REQ_RO,
|
|
handler: addSiblingRequirementConfirm
|
|
},
|
|
'addreqchld': {
|
|
menu: true,
|
|
name: 'Add child requirement',
|
|
image: 'add-req.png',
|
|
imageAlt: '[+]',
|
|
readOnlyMode: EDIT_MODE_REQ_RO,
|
|
handler: addChildRequirementConfirm
|
|
},
|
|
'addcmt': {
|
|
menu: true,
|
|
name: 'Add new comment',
|
|
image: 'add-cmt.png',
|
|
imageAlt: '[+]',
|
|
readOnlyMode: 0,
|
|
handler: addComment
|
|
},
|
|
'chstatus': {
|
|
menu: false,
|
|
name: 'Change status',
|
|
readOnlyMode: 0,
|
|
handler: changeStatus
|
|
}
|
|
},
|
|
'Comment': {
|
|
'delcmt': {
|
|
menu: true,
|
|
name: 'Delete comment',
|
|
image: 'delete-node.png',
|
|
imageAlt: '[−]',
|
|
readOnlyMode: 0,
|
|
handler: deleteNodeConfirm
|
|
},
|
|
'addcmt': {
|
|
menu: true,
|
|
name: 'Add new comment',
|
|
image: 'add-cmt.png',
|
|
imageAlt: '[+]',
|
|
readOnlyMode: 0,
|
|
handler: addComment
|
|
}
|
|
}
|
|
};
|
|
|
|
// Executes the menu command for the specific node
|
|
// Input parameters:
|
|
// node_type - type of the target node
|
|
// uuid - UUID of the node
|
|
// cmdId - command to execute
|
|
// Return value:
|
|
// none
|
|
function execNodeCommand(node_type, uuid, cmdId) {
|
|
var cmd = node_commands[node_type][cmdId];
|
|
if (cmd && ((cmd.readOnlyMode & readOnlyMode) == 0)) {
|
|
cmd.handler.call($('#node-' + uuid)[0], uuid);
|
|
}
|
|
}
|
|
|
|
// List of possible statuses for different node types
|
|
var node_statuses = {
|
|
'Requirement': {
|
|
'in process': {
|
|
icon: 'req-status-incomplete.png',
|
|
className: 'status-normal'
|
|
},
|
|
'complete': {
|
|
icon: 'req-status-complete.png',
|
|
className: 'status-complete'
|
|
},
|
|
'verified': {
|
|
icon: 'req-status-verified.png',
|
|
className: 'status-verified'
|
|
}
|
|
}
|
|
};
|
|
|
|
// Constructs the HTML block for drop-down menu of the specific node
|
|
// Input parameters:
|
|
// node_type - type of the target node
|
|
// uuid - UUID of the node
|
|
// Return value:
|
|
// String value containing the HTML code for the drop-down menu block
|
|
function constructMenu(node_type, uuid) {
|
|
var menu = '';
|
|
var menu_commands = node_commands[node_type];
|
|
if (!menu_commands)
|
|
return '';
|
|
for (var cmdId in menu_commands) {
|
|
if (menu_commands[cmdId].menu) {
|
|
var cmdName = menu_commands[cmdId].handler.name;
|
|
var hotkey = '';
|
|
if (hotkeyManager.command_hotkeys['handlerGlobal'][cmdName])
|
|
hotkey = '<span style="color: #606060;">[' + hotkeyManager.command_hotkeys['handlerGlobal'][cmdName].join(', ') + ']</span>';
|
|
var className = 'menu-item';
|
|
if ((menu_commands[cmdId].readOnlyMode & readOnlyMode) != 0)
|
|
className = 'menu-item-disabled';
|
|
menu += '<div class="' + className + ' menu-item-' + cmdId + '" onclick="javascript:execNodeCommand(\'' + node_type + '\', \'' + uuid + '\', \'' + cmdId + '\');"><table><tr><td width="20"><img src="images/' + menu_commands[cmdId].image + '" alt="' + menu_commands[cmdId].imageAlt + '" /></td><td>' + menu_commands[cmdId].name + '</td><td align="right"><img src="images/empty.png" alt="" width="10" height="1" />' + hotkey + '</td></tr></table></div>';
|
|
}
|
|
}
|
|
return menu;
|
|
}
|
|
|
|
// Order in which the children node of different types are appended
|
|
var childrenNodesOrder = [ 'Comment', 'Undefined', 'Requirement' ];
|
|
|
|
// List of HTML block wrapper constructors for different types of nodes
|
|
var constructNodeWrapperProcessor = {
|
|
'Comment': function (uuid) {
|
|
return $('<div class="comments" />');
|
|
},
|
|
'Requirement': function (uuid) {
|
|
return $('<div id="reqchildren-' + uuid + '" class="requirement-children" />');
|
|
}
|
|
};
|
|
|
|
// List of HTML block constructors for different types of nodes
|
|
var constructNodeProcessor = {
|
|
'Comment': function (nodeData, uuid) {
|
|
// Fill in default values for missing attributes
|
|
if (!nodeData.attributes._description || !nodeData.attributes._description.value)
|
|
nodeData.attributes._description = { 'value': ' ' };
|
|
// Construct HTML block
|
|
return $(
|
|
'<div class="cmtwrapper" id="block-' + uuid + '">' +
|
|
'<div class="comment supported-node" id="node-' + uuid + '">' +
|
|
'<div class="cmtctrls nodectrls" style="float: right;">' +
|
|
'<div style="text-align: right;">' +
|
|
'<img src="images/menu.png" alt="[v]" />' +
|
|
'</div>' +
|
|
'<div class="menu" style="display: none;">' +
|
|
constructMenu('Comment', uuid) +
|
|
'</div>' +
|
|
'</div>' +
|
|
'<div class="cmtdesc nodedesc editable" id="cmtdesc-' + uuid + '">' +
|
|
nodeData.attributes._description.value +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</div>'
|
|
);
|
|
},
|
|
'Requirement': function (nodeData, uuid) {
|
|
if (!nodeData.attributes._description || !nodeData.attributes._description.value) {
|
|
// Description is empty, request all the locations assigned to this requirement
|
|
// and construct description by combining them together
|
|
if (nodeData.attributes._locations) {
|
|
var loc_text = '';
|
|
for (var i in nodeData.attributes._locations.value) {
|
|
try {
|
|
var locJSON = getNodeByQID(nodeData.attributes._locations.value[i]);
|
|
}
|
|
catch (ex) {
|
|
continue;
|
|
}
|
|
if (!locJSON)
|
|
continue;
|
|
var locData = $.parseJSON(locJSON);
|
|
if (loc_text != '')
|
|
loc_text += '<br />';
|
|
if (locData.attributes._description && locData.attributes._description.value)
|
|
loc_text += locData.attributes._description.value;
|
|
}
|
|
nodeData.attributes._description = { 'value': (loc_text == '') ? ' ' : loc_text };
|
|
}
|
|
else
|
|
nodeData.attributes._description = { 'value': ' ' };
|
|
}
|
|
// Fill in default values for missing attributes
|
|
if (!nodeData.attributes._name)
|
|
nodeData.attributes._name = { 'value': nodeData.id };
|
|
if (!nodeData.attributes.coverageStatus || !nodeData.attributes.coverageStatus.value)
|
|
nodeData.attributes.coverageStatus = { 'value': 'in process' };
|
|
// Create the block for requirement
|
|
var editable_prefix = (((readOnlyMode & EDIT_MODE_REQ_RO) == 0) ? '' : 'non');
|
|
var newNode = $(
|
|
'<blockquote class="indent nodewrapper" id="block-' + uuid + '">' +
|
|
'<div class="requirement supported-node" id="node-' + uuid + '">' +
|
|
'<table cellpadding="0" cellspacing="0" border="0" width="100%" class="reqname_wrap">' +
|
|
'<tr>' +
|
|
'<td>' +
|
|
'<img src="images/' + node_statuses['Requirement'][nodeData.attributes.coverageStatus.value].icon + '" alt="' + nodeData.attributes.coverageStatus.value + '" title="' + nodeData.attributes.coverageStatus.value + '" class="imgstatus" id="status-' + uuid + '" class="imgstatus" onclick="javascript:execNodeCommand(\'Requirement\', \'' + uuid + '\', \'chstatus\');" />' +
|
|
'</td>' +
|
|
'<td width="100%">' +
|
|
'<div class="reqname nodetitle ' + editable_prefix + 'renamable ' + node_statuses['Requirement'][nodeData.attributes.coverageStatus.value].className + '" id="reqname-' + uuid + '">' +
|
|
nodeData.attributes._name.value +
|
|
'</div>' +
|
|
'</td>' +
|
|
'<td>' +
|
|
'<div class="reqctrls nodectrls">' +
|
|
'<div style="text-align: right;">' +
|
|
'<img src="images/menu.png" alt="[v]" />' +
|
|
'</div>' +
|
|
'<div class="menu" style="display: none;">' +
|
|
constructMenu('Requirement', uuid) +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</td>' +
|
|
'</tr>' +
|
|
'</table>' +
|
|
'<div class="reqdesc nodedesc ' + editable_prefix + 'editable" id="reqdesc-' + uuid + '">' +
|
|
nodeData.attributes._description.value +
|
|
'</div>' +
|
|
'</div>' +
|
|
'</blockquote>'
|
|
);
|
|
|
|
// Enumerate all children objects and recursively construct the rest of the tree
|
|
var childrenNodes = {};
|
|
for (var i in nodeData.children) {
|
|
// Construct the next child subtree (for requirements) or table (for test purposes)
|
|
var chldNode = constructTree(nodeData.children[i]);
|
|
var chldType = chldNode.type;
|
|
if (!childrenNodes[chldType]) {
|
|
var wrapperConstructor = constructNodeWrapperProcessor[chldType];
|
|
if (wrapperConstructor)
|
|
childrenNodes[chldType] = wrapperConstructor(uuid);
|
|
else
|
|
childrenNodes[chldType] = $('<div />');
|
|
}
|
|
childrenNodes[chldType].append(chldNode);
|
|
}
|
|
// Now append children nodes blocks to the current requirement node
|
|
for (var i = 0; i < childrenNodesOrder.length; ++i) {
|
|
var chldType = childrenNodesOrder[i];
|
|
if (childrenNodes[chldType]) {
|
|
newNode.append(childrenNodes[chldType]);
|
|
if (chldType == 'Requirement') {
|
|
newNode.addClass('collapsable');
|
|
newNode.prepend($('<img src="images/collapse.png" alt="[−]" class="plusminus" onclick="javascript:toggleChildren(\'' + uuid + '\');" />'));
|
|
}
|
|
}
|
|
}
|
|
|
|
return newNode;
|
|
}
|
|
};
|
|
|
|
// Reads the tree contents starting from UUID specified and updates the document
|
|
// Input parameters:
|
|
// uuid - UUID of the root element of the updated subtree
|
|
// Return value:
|
|
// none
|
|
function constructTree(uuid) {
|
|
// Obtain the node data (parse output as JSON string)
|
|
var nodeData = $.parseJSON(getNodeByUUID(uuid));
|
|
var constructor = constructNodeProcessor[nodeData.attributes._type.value];
|
|
var newNode;
|
|
if (constructor) {
|
|
newNode = constructor(nodeData, uuid);
|
|
newNode.type = nodeData.attributes._type.value;
|
|
}
|
|
else {
|
|
newNode = $(
|
|
'<div class="nodewrapper" id="block-' + uuid + '">' +
|
|
'<div class="unsupported-node" id="node-' + uuid + '">' +
|
|
'Unsupported node <ID: ' + nodeData.id + '; type: ' + nodeData.attributes._type.value + '>' +
|
|
'</div>' +
|
|
'</div>'
|
|
);
|
|
newNode.type = 'Undefined';
|
|
}
|
|
return newNode;
|
|
}
|
|
|
|
// Reads the tree contents starting from UUID specified and updates the document
|
|
// Input parameters:
|
|
// uuid - UUID of the root element of the updated subtree
|
|
// Return value:
|
|
// none
|
|
function updateTree(uuid) {
|
|
// Remember the focused item and its nearest neighbour
|
|
var focused_id;
|
|
var prev_id;
|
|
if (all_active_elems) {
|
|
focused_id = all_active_elems[keyboard_focus].id;
|
|
if (keyboard_focus > 0)
|
|
prev_id = all_active_elems[keyboard_focus - 1].id;
|
|
}
|
|
// Create the updated tree contents
|
|
var newNode = constructTree(uuid);
|
|
// Insert the new tree into the document
|
|
var currentNode = $('#block-' + uuid);
|
|
if (!currentNode.length) {
|
|
// Node does not exist, append it into the contents block
|
|
newNode.appendTo('#contents');
|
|
}
|
|
else {
|
|
// Node exists, replace it with the new data
|
|
currentNode.replaceWith(newNode);
|
|
}
|
|
// Update the lists of elements
|
|
all_active_elems = $('.supported-node');
|
|
all_editable_elems = $('.supported-node .editable');
|
|
// Search for the element that was focused before updating
|
|
var keyboard_focus_new = 0;
|
|
if (focused_id) {
|
|
// Trying to find the focused element
|
|
keyboard_focus_new = all_active_elems.index($('#' + focused_id));
|
|
if ((keyboard_focus_new == -1) && prev_id) {
|
|
// Not found (maybe, removed?), searching for the neighbour
|
|
keyboard_focus_new = all_active_elems.index($('#' + prev_id));
|
|
}
|
|
if (keyboard_focus_new == -1) {
|
|
// Not found either, go to the root
|
|
// TODO: Set focus at the first existing parent
|
|
keyboard_focus_new = 0;
|
|
}
|
|
}
|
|
setFocusByIndex(keyboard_focus_new);
|
|
}
|
|
|
|
// New jQuery objects method: dimensions()
|
|
// Combines all the dimensions of the node into single object
|
|
// Input parameters:
|
|
// none
|
|
// Return value:
|
|
// Object with element dimensions (left, right, top, bottom - position; width, height - size)
|
|
$.fn.dimensions = function () {
|
|
var off = this.offset();
|
|
if (!off)
|
|
off = {left: 0, top: 0};
|
|
off.width = this.outerWidth() || this.width();
|
|
off.height = this.outerHeight() || this.height();
|
|
off.right = off.left + off.width;
|
|
off.bottom = off.top + off.height;
|
|
return off;
|
|
};
|
|
|
|
// New jQuery objects method: scrollToView()
|
|
// Scrolls the window so that the element became visible
|
|
// Input parameters:
|
|
// none
|
|
// Return value:
|
|
// this (allowing for chained calls)
|
|
$.fn.scrollToView = function () {
|
|
var elemOff = this.dimensions();
|
|
var docOff = $(document).dimensions();
|
|
var wndOff = $(window).dimensions();
|
|
var oldScrollPos = $(document).scrollTop();
|
|
var newScrollPos;
|
|
if (elemOff.height > wndOff.height) {
|
|
// Element is higher than window. If it is partially hidden below the window,
|
|
// scroll to top; if it is partially hidden above the window, scroll to bottom.
|
|
if (elemOff.top > oldScrollPos)
|
|
newScrollPos = elemOff.top;
|
|
else if (elemOff.bottom < oldScrollPos + wndOff.height)
|
|
newScrollPos = elemOff.bottom - wndOff.height;
|
|
}
|
|
else if (elemOff.top < oldScrollPos) {
|
|
// Element is above the window viewport
|
|
newScrollPos = elemOff.top;
|
|
}
|
|
else if (elemOff.bottom > oldScrollPos + wndOff.height) {
|
|
// Element is below the window viewport
|
|
newScrollPos = elemOff.bottom - wndOff.height;
|
|
}
|
|
if (newScrollPos)
|
|
window.scrollBy(0, newScrollPos - oldScrollPos);
|
|
return this;
|
|
};
|
|
|
|
// Mapping of HTML class names to Requality node types
|
|
var nodeClassToType = {
|
|
'requirement': 'Requirement',
|
|
'comment': 'Comment'
|
|
};
|
|
|
|
// Converts HTML class name of the node into Requality node type
|
|
// Input parameters:
|
|
// elem - jQuery object with the element to check
|
|
// Return value:
|
|
// name of the node type, or null if type is unknown
|
|
function getNodeType(elem) {
|
|
for (var className in nodeClassToType)
|
|
if (elem.hasClass(className))
|
|
return nodeClassToType[className];
|
|
return null;
|
|
}
|
|
|
|
// pasteAllowedMatrix[type1][type2] == true if it is allowed to paste
|
|
// node of type1 into node of type2 as child
|
|
var pasteAllowedMatrix = {
|
|
'Requirement': [ 'Requirement' ],
|
|
'Comment': [ 'Requirement' ]
|
|
};
|
|
|
|
// Checks whether it is allowed to make one node another node's child
|
|
// Input parameters:
|
|
// src - UUID of the source element to be inserted
|
|
// dst - UUID of the destination element that should become a parent for src
|
|
// Return value:
|
|
// true if such placement is allowed; false otherwise
|
|
function isPasteAllowed(src, dst) {
|
|
var srcType = getNodeType($('#node-' + src));
|
|
var dstType = getNodeType($('#node-' + dst));
|
|
if (!srcType || !dstType)
|
|
return false;
|
|
|
|
for (var i in pasteAllowedMatrix[srcType]) {
|
|
if (pasteAllowedMatrix[srcType][i] == dstType)
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Commands that can be used for hotkey assignments
|
|
|
|
/*
|
|
Calling conventions:
|
|
Each function has the following signature:
|
|
|
|
function myCommand(uuid) {
|
|
do_something();
|
|
}
|
|
|
|
The input argument uuid contains the UUID of the target node. Target node is the focused
|
|
element (if the command was called from keyboard), or the active element (if the command
|
|
was called from the drop-down element's menu).
|
|
Inside the function you can also use 'this' which points to the target DOM element itself.
|
|
*/
|
|
|
|
// Command function: Switch to the previous editable item
|
|
function editPrevious(/* uuid */) {
|
|
if (!editor || !editor.element || (editor.config.bodyClass == 'miniCKE'))
|
|
return;
|
|
var pos = all_editable_elems.index(editor.element.$);
|
|
if (pos == 0)
|
|
pos = all_editable_elems.length - 1;
|
|
else
|
|
--pos;
|
|
saveEditor();
|
|
setFocus($(all_editable_elems[pos]).parent());
|
|
putEditor(all_editable_elems[pos], false);
|
|
}
|
|
|
|
// Command function: Switch to the next editable item
|
|
function editNext(/* uuid */) {
|
|
if (!editor || !editor.element || (editor.config.bodyClass == 'miniCKE'))
|
|
return;
|
|
var pos = all_editable_elems.index(editor.element.$);
|
|
if (pos == all_editable_elems.length - 1)
|
|
pos = 0;
|
|
else
|
|
++pos;
|
|
saveEditor();
|
|
setFocus($(all_editable_elems[pos]).parent());
|
|
putEditor(all_editable_elems[pos], false);
|
|
}
|
|
|
|
// Command function: Close editor discarding the changes
|
|
function closeEditor(/* uuid */) {
|
|
// TODO: Calling requalitySave/requalityExit causes errors!
|
|
// Temporarily wrapped into try-catch block to allow script to continue executing.
|
|
for (var e in CKEDITOR.instances)
|
|
try {
|
|
CKEDITOR.instances[e].execCommand('requalityExit');
|
|
}
|
|
catch (ex) {}
|
|
editor = null;
|
|
}
|
|
|
|
// Command function: Close editor saving all the changes
|
|
function saveEditor(/* uuid */) {
|
|
// TODO: Calling requalitySave/requalityExit causes errors!
|
|
// Temporarily wrapped into try-catch block to allow script to continue executing.
|
|
for (var e in CKEDITOR.instances)
|
|
try {
|
|
CKEDITOR.instances[e].execCommand('requalitySave');
|
|
}
|
|
catch (ex) {}
|
|
editor = null;
|
|
}
|
|
|
|
// Command function: Move focus to the previous focusable node
|
|
function focusPrevious(/* uuid */) {
|
|
var keyboard_focus_new = keyboard_focus;
|
|
while (--keyboard_focus_new >= 0) {
|
|
if ($(all_active_elems[keyboard_focus_new]).is(':visible')) {
|
|
setFocusByIndex(keyboard_focus_new);
|
|
return;
|
|
}
|
|
}
|
|
// If failed to go to change active element, scroll to the current one
|
|
$(this).scrollToView();
|
|
}
|
|
|
|
// Command function: Move focus to the next focusable node
|
|
function focusNext(/* uuid */) {
|
|
var keyboard_focus_new = keyboard_focus;
|
|
while (++keyboard_focus_new <= all_active_elems.length - 1) {
|
|
if ($(all_active_elems[keyboard_focus_new]).is(':visible')) {
|
|
setFocusByIndex(keyboard_focus_new);
|
|
return;
|
|
}
|
|
}
|
|
// If failed to go to change active element, scroll to the current one
|
|
$(this).scrollToView();
|
|
}
|
|
|
|
// Command function: Collapse node or move to the parent node
|
|
function navigateLeft(uuid) {
|
|
if ($(this).parent().hasClass('collapsable')) {
|
|
if ($(this).parent().children('.requirement-children').is(':visible')) {
|
|
toggleChildren(uuid);
|
|
}
|
|
else {
|
|
setFocus($($(this).closest('.collapsable').parent().closest('.collapsable').children('.requirement')[0]));
|
|
return;
|
|
}
|
|
}
|
|
else {
|
|
setFocus($($(this).closest('.collapsable').children('.requirement')[0]));
|
|
return;
|
|
}
|
|
$(this).scrollToView();
|
|
}
|
|
|
|
// Command function: Expand node or move to the next focusable node
|
|
function navigateRight(uuid) {
|
|
if ($(this).parent().hasClass('collapsable') && $(this).parent().children('.requirement-children').is(':hidden')) {
|
|
toggleChildren(uuid);
|
|
}
|
|
else {
|
|
var keyboard_focus_new = keyboard_focus;
|
|
while (++keyboard_focus_new <= all_active_elems.length - 1) {
|
|
if ($(all_active_elems[keyboard_focus_new]).is(':visible')) {
|
|
setFocusByIndex(keyboard_focus_new);
|
|
return;
|
|
}
|
|
}
|
|
}
|
|
$(this).scrollToView();
|
|
}
|
|
|
|
// Command function: Expand the current node
|
|
function expandNode(uuid) {
|
|
if ($(this).parent().hasClass('collapsable') && $(this).parent().children('.requirement-children').is(':hidden')) {
|
|
toggleChildren(uuid);
|
|
}
|
|
$(this).scrollToView();
|
|
}
|
|
|
|
// Command function: Collapse the current node
|
|
function collapseNode(uuid) {
|
|
if ($(this).parent().hasClass('collapsable') && $(this).parent().children('.requirement-children').is(':visible')) {
|
|
toggleChildren(uuid);
|
|
}
|
|
$(this).scrollToView();
|
|
}
|
|
|
|
// Command function: Move focus to the element located one page above the current one
|
|
function pageUp(/* uuid */) {
|
|
var keyboard_focus_new = keyboard_focus;
|
|
var keyboard_focus_tmp = keyboard_focus;
|
|
var new_pos = $(this).offset().top - $(window).height();
|
|
while (--keyboard_focus_tmp >= 0) {
|
|
var elem_tmp = $(all_active_elems[keyboard_focus_tmp]);
|
|
if (elem_tmp.is(':visible')) {
|
|
keyboard_focus_new = keyboard_focus_tmp;
|
|
if (elem_tmp.offset().top <= new_pos)
|
|
break;
|
|
}
|
|
}
|
|
if (keyboard_focus_new != keyboard_focus) {
|
|
setFocusByIndex(keyboard_focus_new);
|
|
return;
|
|
}
|
|
$(this).scrollToView();
|
|
}
|
|
|
|
// Command function: Move focus to the element located one page below the current one
|
|
function pageDown(/* uuid */) {
|
|
var keyboard_focus_new = keyboard_focus;
|
|
var keyboard_focus_tmp = keyboard_focus;
|
|
var new_pos = $(this).offset().top + $(window).height();
|
|
while (++keyboard_focus_tmp <= all_active_elems.length - 1) {
|
|
var elem_tmp = $(all_active_elems[keyboard_focus_tmp]);
|
|
if (elem_tmp.is(':visible')) {
|
|
keyboard_focus_new = keyboard_focus_tmp;
|
|
if (elem_tmp.offset().top >= new_pos)
|
|
break;
|
|
}
|
|
}
|
|
if (keyboard_focus_new != keyboard_focus) {
|
|
setFocusByIndex(keyboard_focus_new);
|
|
return;
|
|
}
|
|
$(this).scrollToView();
|
|
}
|
|
|
|
// Command function: Move focus to the first focusable node
|
|
function focusFirst(/* uuid */) {
|
|
var keyboard_focus_new = -1;
|
|
while (++keyboard_focus_new <= all_active_elems.length - 1) {
|
|
if ($(all_active_elems[keyboard_focus_new]).is(':visible')) {
|
|
setFocusByIndex(keyboard_focus_new);
|
|
return;
|
|
}
|
|
}
|
|
$(this).scrollToView();
|
|
}
|
|
|
|
// Command function: Move focus to the last focusable node
|
|
function focusLast(/* uuid */) {
|
|
var keyboard_focus_new = all_active_elems.length;
|
|
while (--keyboard_focus_new >= 0) {
|
|
if ($(all_active_elems[keyboard_focus_new]).is(':visible')) {
|
|
setFocusByIndex(keyboard_focus_new);
|
|
return;
|
|
}
|
|
}
|
|
$(this).scrollToView();
|
|
}
|
|
|
|
// Command function: Edit requirement/test purpose description
|
|
function editDescription(/* uuid */) {
|
|
if (!isEditable($(this)))
|
|
return;
|
|
if (editor && editor.element) {
|
|
if (editor.config.bodyClass == 'normalCKE')
|
|
return;
|
|
saveEditor();
|
|
}
|
|
$($(all_active_elems[keyboard_focus]).find('.nodedesc')[0]).click();
|
|
}
|
|
|
|
// Command function: Edit requirement name/test purpose ID (if description editor is opened
|
|
// it is closed with saving)
|
|
function editNameId(/* uuid */) {
|
|
if (!isEditable($(this)))
|
|
return;
|
|
if (editor && editor.element) {
|
|
if (editor.config.bodyClass == 'miniCKE')
|
|
return;
|
|
saveEditor();
|
|
}
|
|
$($(all_active_elems[keyboard_focus]).find('.nodetitle')[0]).click();
|
|
}
|
|
|
|
// Command function: Save & close editor if requirement name/test purpose ID is being edited
|
|
function saveNameId(/* uuid */) {
|
|
if (editor && editor.element) {
|
|
if (editor.config.bodyClass == 'miniCKE')
|
|
saveEditor();
|
|
}
|
|
}
|
|
|
|
// Names of the Requality attribute responsible for storing node status
|
|
var statusAttr = {
|
|
'Requirement': 'coverageStatus'
|
|
};
|
|
|
|
// Command function: Switch status of the requirement or test purpose
|
|
function changeStatus(uuid) {
|
|
var img = $('#status-' + uuid);
|
|
var current_status = img.attr('alt');
|
|
var new_status;
|
|
if (isEditable($(this))) {
|
|
// In normal mode 'verified' is unavailable
|
|
if (current_status == 'in process')
|
|
new_status = 'complete';
|
|
else
|
|
new_status = 'in process';
|
|
}
|
|
else {
|
|
// In read-only (review) mode all statuses are allowed to be set
|
|
if (current_status == 'in process')
|
|
new_status = 'complete';
|
|
else if (current_status == 'complete')
|
|
new_status = 'verified';
|
|
else
|
|
new_status = 'in process';
|
|
}
|
|
var nodeType = getNodeType($(this));
|
|
img.attr('alt', new_status).attr('title', new_status);
|
|
img.attr('src', 'images/' + node_statuses[nodeType][new_status].icon);
|
|
$(this).find('.nodetitle').removeClass(node_statuses[nodeType][current_status].className).addClass(node_statuses[nodeType][new_status].className);
|
|
changeNodeAttr(uuid, statusAttr[nodeType], new_status);
|
|
}
|
|
|
|
// Command function: Delete the node after confirming the decision
|
|
function deleteNodeConfirm(uuid) {
|
|
if (!isEditable($(this)))
|
|
return;
|
|
var type = getNodeType($(this));
|
|
if (confirm('Are you sure you wish to delete the ' + (type ? type + ' ' : '') + 'node with all its children (if any)?'))
|
|
removeNode(uuid);
|
|
}
|
|
|
|
// Command function: Add new child requirement (name is requested)
|
|
function addChildRequirementConfirm(uuid) {
|
|
if ((readOnlyMode & EDIT_MODE_REQ_RO) != 0)
|
|
return;
|
|
if (!$(this).hasClass('requirement'))
|
|
return;
|
|
var new_name = prompt('Requirement name:');
|
|
if ((new_name != null) && (new_name != '')) {
|
|
var new_req_uuid = addNode(uuid, null, 'Requirement');
|
|
changeNodeAttr(new_req_uuid, '_name', new_name);
|
|
}
|
|
}
|
|
|
|
// Command function: Add new sibling requirement (name is requested)
|
|
function addSiblingRequirementConfirm(uuid) {
|
|
if ((readOnlyMode & EDIT_MODE_REQ_RO) != 0)
|
|
return;
|
|
if (!$(this).hasClass('requirement'))
|
|
return;
|
|
var new_name = prompt('Requirement name:');
|
|
if ((new_name != null) && (new_name != '')) {
|
|
var new_req_uuid = addNode(extractUUID($('#block-' + uuid).parent().closest('.collapsable')[0].id), null, 'Requirement');
|
|
changeNodeAttr(new_req_uuid, '_name', new_name);
|
|
}
|
|
}
|
|
|
|
// Command function: Add new comment as requirement's or test purpose's child or another comment's sibling
|
|
function addComment(uuid) {
|
|
// Get the wrapping block of the target requirement/test purpose
|
|
// or of the target comment's parent requirement (if it is a comment)
|
|
var req_elem = $(this).closest('.nodewrapper');
|
|
// Create the child test purpose if there are no children requirements
|
|
addNode(extractUUID(req_elem[0].id), null, 'Comment');
|
|
}
|
|
|
|
var internalClipboard;
|
|
var internalClipboardCopyMode;
|
|
|
|
// Command function: Copy node to the internal clipboard (store the uuid)
|
|
function copyNodeToClipboard(uuid) {
|
|
if (!isEditable($(this)))
|
|
return;
|
|
internalClipboard = uuid;
|
|
internalClipboardCopyMode = true;
|
|
}
|
|
|
|
// Command function: Cut node to the internal clipboard (store the uuid)
|
|
function cutNodeToClipboard(uuid) {
|
|
if (!isEditable($(this)))
|
|
return;
|
|
internalClipboard = uuid;
|
|
internalClipboardCopyMode = false;
|
|
}
|
|
|
|
// Command function: Paste the copied node as the current node's sibling
|
|
function pasteNodeAsSibling(uuid) {
|
|
if (internalClipboard) {
|
|
var target_uuid = extractUUID($('#block-' + uuid).parent().closest('.nodewrapper')[0].id);
|
|
if (isPasteAllowed(internalClipboard, target_uuid)) {
|
|
if (internalClipboardCopyMode)
|
|
copyNode(internalClipboard, target_uuid, false);
|
|
else {
|
|
changeNodeParent(internalClipboard, target_uuid);
|
|
internalClipboard = null;
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
// Command function: Paste the copied node with all its children as the current node's sibling
|
|
function pasteSubtreeAsSibling(uuid) {
|
|
if (internalClipboard) {
|
|
var target_uuid = extractUUID($('#block-' + uuid).parent().closest('.nodewrapper')[0].id);
|
|
if (isPasteAllowed(internalClipboard, target_uuid))
|
|
if (internalClipboardCopyMode)
|
|
copyNode(internalClipboard, target_uuid, true);
|
|
else {
|
|
changeNodeParent(internalClipboard, target_uuid);
|
|
internalClipboard = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Command function: Paste the copied node as the current node's child
|
|
function pasteNodeAsChild(uuid) {
|
|
if (internalClipboard) {
|
|
if (isPasteAllowed(internalClipboard, uuid))
|
|
if (internalClipboardCopyMode)
|
|
copyNode(internalClipboard, uuid, false);
|
|
else {
|
|
changeNodeParent(internalClipboard, uuid);
|
|
internalClipboard = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
// Command function: Paste the copied node with all its children as the current node's child
|
|
function pasteSubtreeAsChild(uuid) {
|
|
if (internalClipboard) {
|
|
if (isPasteAllowed(internalClipboard, uuid))
|
|
if (internalClipboardCopyMode)
|
|
copyNode(internalClipboard, uuid, true);
|
|
else {
|
|
changeNodeParent(internalClipboard, uuid);
|
|
internalClipboard = null;
|
|
}
|
|
}
|
|
}
|
|
|
|
////////////////////////////////////////////////////////////////////////////////
|
|
// Startup actions
|
|
|
|
// Additional styles that should be applied into CKEditor when editing elements of specific class
|
|
var CKEditorStyles = {
|
|
'reqname': 'body { margin: 1px; font-size: 125%; font-weight: bold; }'
|
|
};
|
|
|
|
// Processors for starting to drag different types of elements: determines the starting position
|
|
// for drag&drop highlighting and sets the appropriate classes to allow/disallow drop targets
|
|
// Input parameters:
|
|
// dragging_uuid - UUID of the element being dragged
|
|
// Return value:
|
|
// Initial value for the node indices to follow the mouse cursor
|
|
var draggingInitHandler = {
|
|
'reqname': function (dragging_uuid, req_elems) {
|
|
var underlying_req_idx = req_elems.index($('#node-' + dragging_uuid)) - 1;
|
|
if (underlying_req_idx < 0) {
|
|
underlying_req_idx = null;
|
|
}
|
|
// Disallow dragging onto itself and children
|
|
$('#block-' + dragging_uuid + ' .requirement').addClass('undroppable');
|
|
// Make the whole node (including children) look disabled
|
|
$('#block-' + dragging_uuid).addClass('disabled');
|
|
return underlying_req_idx;
|
|
}
|
|
};
|
|
|
|
$(function () {
|
|
// Request for the current read-only mode
|
|
readOnlyMode = getReadOnlyMode();
|
|
|
|
// On startup, request the nodes and create the HTML contents
|
|
updateTree(getStartNode());
|
|
|
|
// When simplified editor is opened, update its internal styles
|
|
// addCss() must be called before editor is loaded, so put it into 'instanceCreated'
|
|
CKEDITOR.on('instanceCreated', function (e) {
|
|
var elem = e.editor.element.$;
|
|
for (var className in CKEditorStyles) {
|
|
if ($(elem).hasClass(className)) {
|
|
e.editor.addCss(CKEditorStyles[className]);
|
|
}
|
|
}
|
|
});
|
|
|
|
// Assign drag&drop action to the element titles (those allowed to be edited)
|
|
// Mousedown is initial event for dragging, but real dragging actions will be performed
|
|
// only on first moving, so that we could rename element by simply clicking it
|
|
$('.renamable').live('mousedown', function (e) {
|
|
e.preventDefault();
|
|
var dragging_init = this;
|
|
var dragging;
|
|
var dragging_uuid = extractUUID(dragging_init.id);
|
|
var dims = $(dragging_init).dimensions();
|
|
var mouseDX = e.pageX - dims.left; // Remember position of the mouse relative to the dragged element
|
|
var mouseDY = e.pageY - dims.top;
|
|
var scroll_speed = 0; // Speed of automatic scrolling
|
|
var scroll_timer; // Timer for performing automatic scrolling
|
|
var doc_height = $(document).height(); // Protect from heigth increasing when moving dragged element below bottom
|
|
var wnd_height = $(window).height();
|
|
|
|
// Data needed for requirement highlighting during drag&drop
|
|
// They will be initialized later (to avoid delays in processing clicks without drag&drop)
|
|
var req_elems; // List of all requirement nodes available for highlighting
|
|
var underlying_req_idx1; // Indices of the requirement nodes between which the mouse cursor is
|
|
var underlying_req_idx2; // node1 is the higher node, node2 is the lower one (they can be equal)
|
|
|
|
// Updates highlighting of the target requirement (under mouse cursor)
|
|
// Input parameters:
|
|
// (mx, my) - mouse cursor position
|
|
// Return value:
|
|
// none
|
|
var reqHighlight = function (mx, my) {
|
|
if ((underlying_req_idx1 == null) || (underlying_req_idx2 == null))
|
|
return;
|
|
|
|
var elem1_current = $(req_elems[underlying_req_idx1]);
|
|
var dims1_current = elem1_current.dimensions();
|
|
var elem2_current = $(req_elems[underlying_req_idx2]);
|
|
var dims2_current = elem2_current.dimensions();
|
|
|
|
if (my < dims1_current.top) {
|
|
// Above the node1
|
|
elem1_current.removeClass('droppable'); // Unhighlight the node1 if it was highlighted
|
|
underlying_req_idx2 = underlying_req_idx1; // node1 becomes the new node2
|
|
// Search for the new nodes where the mouse cursor is located now
|
|
// (either on a node, or between two nodes)
|
|
var tmp_idx1 = underlying_req_idx1;
|
|
while (tmp_idx1 > 0) {
|
|
--tmp_idx1;
|
|
var elem_prev = $(req_elems[tmp_idx1]);
|
|
if (elem_prev.is(':hidden')) {
|
|
// Skip collapsed requirements
|
|
continue;
|
|
}
|
|
underlying_req_idx1 = tmp_idx1;
|
|
var dims_prev = elem_prev.dimensions();
|
|
if (my > dims_prev.bottom) {
|
|
// Cursor is between two nodes
|
|
return;
|
|
}
|
|
else if ((my >= dims_prev.top) && (my <= dims_prev.bottom)) {
|
|
// Cursor is vertically aligned with the node
|
|
underlying_req_idx2 = underlying_req_idx1;
|
|
if ((mx >= dims_prev.left) && (mx <= dims_prev.right)) {
|
|
// Cursor is inside the node, set highlighting if necessary
|
|
if (!elem_prev.hasClass('undroppable') && !elem_prev.hasClass('droppable'))
|
|
elem_prev.addClass('droppable');
|
|
}
|
|
return;
|
|
}
|
|
else /* if (my < dims_prev.top) */ {
|
|
// Cursor is even higher, shift the indices and continue searching upwards
|
|
underlying_req_idx2 = underlying_req_idx1;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
else if ((my >= dims1_current.top) && (my <= dims1_current.bottom)) {
|
|
// Aligned with the node1
|
|
underlying_req_idx2 = underlying_req_idx1;
|
|
if ((mx >= dims1_current.left) && (mx <= dims1_current.right)) {
|
|
// Cursor is inside the node1, set highlighting if necessary
|
|
if (!elem1_current.hasClass('undroppable') && !elem1_current.hasClass('droppable'))
|
|
elem1_current.addClass('droppable');
|
|
}
|
|
else {
|
|
// node1 is not under the cursor - unhighlight it
|
|
elem1_current.removeClass('droppable');
|
|
}
|
|
return;
|
|
}
|
|
else if ((my > dims1_current.bottom) && (my < dims2_current.top)) {
|
|
// Between node1 and node2 (can happen only when the nodes are not the same)
|
|
elem1_current.removeClass('droppable');
|
|
elem2_current.removeClass('droppable');
|
|
}
|
|
else if ((my >= dims2_current.top) && (my <= dims2_current.bottom)) {
|
|
// Aligned with the node2
|
|
underlying_req_idx1 = underlying_req_idx2;
|
|
if ((mx >= dims2_current.left) && (mx <= dims2_current.right)) {
|
|
// Cursor is inside the node2, set highlighting if necessary
|
|
if (!elem2_current.hasClass('undroppable') && !elem2_current.hasClass('droppable'))
|
|
elem2_current.addClass('droppable');
|
|
}
|
|
else {
|
|
// node2 is not under the cursor - unhighlight it
|
|
elem2_current.removeClass('droppable');
|
|
}
|
|
return;
|
|
}
|
|
else /* if (my > dims2_current.bottom) */ {
|
|
// Below the node2
|
|
elem2_current.removeClass('droppable'); // Unhighlight the node1 if it was highlighted
|
|
underlying_req_idx1 = underlying_req_idx2; // node2 becomes the new node1
|
|
// Search for the new nodes where the mouse cursor is located now
|
|
// (either on a node, or between two nodes)
|
|
var tmp_idx2 = underlying_req_idx2;
|
|
while (tmp_idx2 < req_elems.length - 1) {
|
|
++tmp_idx2;
|
|
var elem_next = $(req_elems[tmp_idx2]);
|
|
if (elem_next.is(':hidden')) {
|
|
// Skip collapsed requirements
|
|
continue;
|
|
}
|
|
underlying_req_idx2 = tmp_idx2;
|
|
var dims_next = elem_next.dimensions();
|
|
if (my < dims_next.top) {
|
|
// Cursor is between two nodes
|
|
return;
|
|
}
|
|
else if ((my >= dims_next.top) && (my <= dims_next.bottom)) {
|
|
// Cursor is vertically aligned with the node
|
|
underlying_req_idx1 = underlying_req_idx2;
|
|
if ((mx >= dims_next.left) && (mx <= dims_next.right)) {
|
|
// Cursor is inside the node, set highlighting if necessary
|
|
if (!elem_next.hasClass('undroppable') && !elem_next.hasClass('droppable'))
|
|
elem_next.addClass('droppable');
|
|
}
|
|
return;
|
|
}
|
|
else /* if (my > dims_next.bottom) */ {
|
|
// Cursor is even lower, shift the indices and continue searching downwards
|
|
underlying_req_idx1 = underlying_req_idx2;
|
|
}
|
|
}
|
|
return;
|
|
}
|
|
};
|
|
|
|
// Automatic scrolling handler
|
|
var scrollWatcher = function () {
|
|
if ((scroll_speed > 0) && ($(document).scrollTop() + wnd_height < doc_height) ||
|
|
(scroll_speed < 0) && ($(document).scrollTop() > 0)) {
|
|
// Perform scrolling only if not at the very top/bottom of the document
|
|
window.scrollBy(0, Math.round(scroll_speed / 90));
|
|
// Calculate the updated position of the mouse (can do it since dragged element is 'display: fixed')
|
|
var dragging_off = dragging.offset();
|
|
// Update the target node highliting
|
|
reqHighlight(dragging_off.left + mouseDX, dragging_off.top + mouseDY);
|
|
}
|
|
};
|
|
|
|
var dnd_overlay;
|
|
var dnd_keys = { ctrlKey: false, shiftKey: false };
|
|
$(document).bind('mousemove.drag', function (e) {
|
|
e.preventDefault();
|
|
if (!dragging) {
|
|
// First mouse move after pressing the button - initialize dragging
|
|
// Create a duplicate of the requirement name (it will be dragged
|
|
// while the original one remains on its place)
|
|
dragging = $(dragging_init).clone().removeAttr('id').css({
|
|
opacity: 0.7,
|
|
position: 'fixed',
|
|
left: dims.left + 'px',
|
|
top: dims.top + 'px',
|
|
zIndex: 1010,
|
|
cursor: 'move',
|
|
backgroundColor: '#f7f7ff',
|
|
borderColor: '#c0c0c0'
|
|
}).appendTo(document.body);
|
|
// Initialize highlighting data and assign special styles to some nodes
|
|
// to indicate impossibility of dropping the element there:
|
|
// 'undroppable' is set to requirement nodes to disallow highlighting;
|
|
// 'disabled' is set to visualize unavailability of nodes by paleness
|
|
req_elems = $('.requirement');
|
|
for (var className in draggingInitHandler) {
|
|
if ($(dragging_init).hasClass(className)) {
|
|
underlying_req_idx2 = underlying_req_idx1 = draggingInitHandler[className].call(null, dragging_uuid, req_elems);
|
|
}
|
|
}
|
|
|
|
// Create the transparent overlay over the document so that text could not be selected
|
|
// (in addition prevents triggering hover events of the underlying elements)
|
|
if ($('#dnd-overlay').length == 0) {
|
|
// If overlay is missing create it
|
|
$('<div id="dnd-overlay"></div>').css({
|
|
display: 'none',
|
|
position: 'absolute',
|
|
top: '0px',
|
|
left: '0px',
|
|
cursor: 'move',
|
|
zIndex: 1000
|
|
}).appendTo(document.body);
|
|
}
|
|
// Update the size (in case document sizes changed) and display
|
|
$('#dnd-overlay').css({
|
|
width: $(document).width() + 'px',
|
|
height: $(document).height() + 'px'
|
|
}).show();
|
|
|
|
// Initialize autoscrolling watcher
|
|
scroll_timer = setInterval(scrollWatcher, 20);
|
|
|
|
// Create the "plus-sheet" overlay to indicate copying
|
|
dnd_overlay = $('<img src="images/dnd-copy.png" alt="" id="dnd-cursor-overlay" />').css({
|
|
position: 'absolute',
|
|
display: 'none',
|
|
opacity: 0.6,
|
|
zIndex: 1020
|
|
}).appendTo(document.body);
|
|
|
|
// Listen to keypresses to handle Ctrl and Shift
|
|
$(document).bind('keydown.drag keyup.drag', function (e) {
|
|
var dnd_keys_changed = false;
|
|
if (e.type == 'keydown') {
|
|
if (e.keyCode == 17) {
|
|
// Ctrl is pressed
|
|
if (!dnd_keys.ctrlKey) {
|
|
dnd_keys.ctrlKey = true;
|
|
dnd_keys_changed = true;
|
|
}
|
|
}
|
|
else if (e.keyCode == 16) {
|
|
// Shift is pressed
|
|
if (!dnd_keys.shiftKey) {
|
|
dnd_keys.shiftKey = true;
|
|
dnd_keys_changed = true;
|
|
}
|
|
}
|
|
}
|
|
else if (e.type == 'keyup') {
|
|
if (e.keyCode == 17) {
|
|
// Ctrl is released
|
|
if (dnd_keys.ctrlKey) {
|
|
dnd_keys.ctrlKey = false;
|
|
dnd_keys_changed = true;
|
|
}
|
|
}
|
|
else if (e.keyCode == 16) {
|
|
// Shift is released
|
|
if (dnd_keys.shiftKey) {
|
|
dnd_keys.shiftKey = false;
|
|
dnd_keys_changed = true;
|
|
}
|
|
}
|
|
}
|
|
if (dnd_keys_changed) {
|
|
// Drag&Drop type changed, updating the overlay
|
|
if (dnd_keys.ctrlKey) {
|
|
// Ctrl or Ctrl+Shift is pressed, update the overlay and show it
|
|
if (dnd_keys.shiftKey)
|
|
dnd_overlay.attr('src', 'images/dnd-copy-all.png');
|
|
else
|
|
dnd_overlay.attr('src', 'images/dnd-copy.png');
|
|
var dragging_dims = dragging.dimensions();
|
|
dnd_overlay.show().offset({
|
|
top: dragging_dims.bottom - 10,
|
|
left: dragging_dims.right - 10
|
|
});
|
|
}
|
|
else {
|
|
// Ctrl is not pressed, hide the overlay
|
|
dnd_overlay.hide();
|
|
}
|
|
}
|
|
});
|
|
}
|
|
|
|
// Update the position of the dragged element and drag&drop overlay (if it's visible)
|
|
dragging.offset({left: e.pageX - mouseDX, top: e.pageY - mouseDY});
|
|
if (dnd_overlay.is(':visible')) {
|
|
var dragging_dims = dragging.dimensions();
|
|
dnd_overlay.offset({
|
|
top: dragging_dims.bottom - 10,
|
|
left: dragging_dims.right - 10
|
|
});
|
|
}
|
|
// Highlight the requirement the mouse is passing by
|
|
reqHighlight(e.pageX, e.pageY);
|
|
|
|
// Calculate auto-scrolling speed (non-zero when mouse is at the top/bottom of the window)
|
|
var scrollTop = $(document).scrollTop();
|
|
if (e.pageY - scrollTop < 30) {
|
|
// Top of the window, scroll up (negative speed)
|
|
// Max speed is 1800 px/sec
|
|
var diff = e.pageY - scrollTop;
|
|
if (diff < 0)
|
|
diff = 0;
|
|
scroll_speed = -60 * (30 - diff);
|
|
}
|
|
else if (scrollTop + $(window).height() - e.pageY < 30) {
|
|
// Bottom of the window, scroll down (positive speed)
|
|
var diff = scrollTop + $(window).height() - e.pageY;
|
|
if (diff < 0)
|
|
diff = 0;
|
|
scroll_speed = 60 * (30 - diff);
|
|
}
|
|
else {
|
|
scroll_speed = 0;
|
|
}
|
|
}).bind('mouseup.drag', function (e) {
|
|
// The mouse button is released: either normal click, or end of drag&drop
|
|
e.preventDefault();
|
|
// In any case unbind the additional event handlers
|
|
$(document).unbind('mouseup.drag').unbind('mousemove.drag').unbind('keydown.drag').unbind('keyup.drag');
|
|
if (dragging) {
|
|
// Drag&drop was used - restore normal functioning by removing the dragged element,
|
|
// hiding the overlays, unhighlighting the requirement and turning autoscroll off
|
|
scroll_speed = 0;
|
|
clearInterval(scroll_timer);
|
|
dragging.remove();
|
|
dragging = null;
|
|
dnd_overlay.remove();
|
|
dnd_overlay = null;
|
|
var target = $('.droppable').removeClass('droppable');
|
|
$('.undroppable').removeClass('undroppable');
|
|
$('.disabled').removeClass('disabled');
|
|
$('#dnd-overlay').hide();
|
|
if (target.length > 0) {
|
|
// If we released the element over a node, complete the drag&drop action
|
|
var target_uuid = extractUUID(target[0].id);
|
|
setFocus(target);
|
|
if (e.ctrlKey) {
|
|
// Ctrl was pressed, so making a copy instead of moving
|
|
if (e.shiftKey) {
|
|
// Ctrl+Shift was pressed, make a copy of the subtree
|
|
copyNode(dragging_uuid, target_uuid, true);
|
|
}
|
|
else {
|
|
// Only Ctrl was pressed, make a copy of the element itself
|
|
copyNode(dragging_uuid, target_uuid, false);
|
|
}
|
|
}
|
|
else {
|
|
// No keyboard modifiers were pressed, move the element
|
|
changeNodeParent(dragging_uuid, target_uuid);
|
|
}
|
|
}
|
|
}
|
|
});
|
|
});
|
|
|
|
// Make editable elements replaced with editor by clicking on them
|
|
$('.focused .editable').live('click', function () {
|
|
if (!editor)
|
|
putEditor(this, false);
|
|
});
|
|
// Make renamable elements updated by clicking on them
|
|
$('.focused .renamable').live('click', function () {
|
|
if (!editor)
|
|
putEditorWithHtmlClean(this, true, true);
|
|
});
|
|
$('.supported-node').live('click', function () {
|
|
if ($(this).hasClass('focused'))
|
|
return;
|
|
closeEditor();
|
|
setFocus($(this));
|
|
});
|
|
|
|
// Expand menu for requirements and test purposes on hovering
|
|
$('.nodectrls').live('mouseenter', function () {
|
|
var menu_caller = $(this);
|
|
var menu_caller_dims = menu_caller.dimensions();
|
|
var container;
|
|
// If we expand the existing element it will stretch the table cell with
|
|
// the test purpose ID or requirement name. To avoid this we create a copy of the
|
|
// drop-down menu, position it as "absolute" above the old one and expand.
|
|
var new_menu = menu_caller.clone().hide();
|
|
// Change class so that the new menu did not react to 'mouseenter' second time
|
|
new_menu.removeClass('nodectrls').addClass('nodectrls-virtual');
|
|
if (menu_caller.hasClass('reqctrls')) {
|
|
// The new menu is hovered, so the border around the current item disappears.
|
|
// Set new class to keep the border.
|
|
// Remove node-specific styles
|
|
new_menu.removeClass('reqctrls');
|
|
}
|
|
else if (menu_caller.hasClass('cmtctrls')) {
|
|
new_menu.removeClass('cmtctrls');
|
|
}
|
|
container = menu_caller.closest('.supported-node');
|
|
container.addClass('supported-node-hovered');
|
|
// Calculate how much the menu should be stretched.
|
|
// jQuery Actual Plugin is used for getting size of a hidden element.
|
|
var delta_width = menu_caller.find('.menu').actual('outerWidth') - menu_caller_dims.width + 15;
|
|
var delta_height = menu_caller.find('.menu').actual('outerHeight');
|
|
// Set mousemove listener to manually watch for mouse cursor going out of the menu
|
|
// (mouseleave for unknown reasons is not always triggered, and menu remains on screen)
|
|
var inside_menu = true;
|
|
$(document).bind('mousemove.menu', function (e) {
|
|
var menu_sz = new_menu.dimensions();
|
|
if ((e.pageX < menu_sz.left) || (e.pageX > menu_sz.right) || (e.pageY < menu_sz.top) || (e.pageY > menu_sz.bottom)) {
|
|
new_menu.mouseleave();
|
|
}
|
|
});
|
|
// Chaining:
|
|
// 1) setting initial position and size set to the original menu's;
|
|
// 2) inserting the element into document;
|
|
// 3) displaying the internal menu contents;
|
|
// 4) animate expanding the menu;
|
|
// 5) assigning menu collapse to moving mouse out of the menu.
|
|
new_menu.css({
|
|
position: 'absolute',
|
|
top: menu_caller_dims.top + 'px',
|
|
left: menu_caller_dims.left + 'px',
|
|
width: menu_caller.width() + 'px',
|
|
height: menu_caller.height() + 'px',
|
|
zIndex: 1000
|
|
}).appendTo(container).show().find('.menu').show().end()./*stop(true, false).*/animate({
|
|
width: '+=' + delta_width,
|
|
left: '-=' + delta_width,
|
|
height: '+=' + delta_height
|
|
}, animationPeriod).mouseleave(function () {
|
|
// Protect from double-entering
|
|
if (inside_menu) {
|
|
inside_menu = false;
|
|
// Unbind mousemove listener
|
|
$(document).unbind('mousemove.menu');
|
|
// When mouse goes away restore normal classes for "item-under-cursor" highlighting
|
|
container.removeClass('supported-node-hovered');
|
|
// ...and animate collapsing the menu
|
|
$(this)./*stop(true, false).*/animate({
|
|
width: '-=' + delta_width,
|
|
left: '+=' + delta_width,
|
|
height: '-=' + delta_height
|
|
}, animationPeriod, function () {
|
|
// Collapsing is finished - remove the absolute-position menu-duplicate
|
|
$(this).remove();
|
|
});
|
|
}
|
|
});
|
|
})
|
|
|
|
// Hotkey handlers
|
|
$(document).keydown(function (e) {
|
|
var elem = all_active_elems[keyboard_focus];
|
|
hotkeyManager.execHotkeyAction(e, (editor ? 'handlerCKEditor' : 'handlerGlobal'), elem, extractUUID(elem.id));
|
|
});
|
|
});
|
|
// ]]>
|
|
</script>
|
|
</head>
|
|
<body>
|
|
<div id="contents"></div>
|
|
<div style="height: 6em;"></div>
|
|
</body>
|
|
</html>
|