Project

General

Profile

Bug #3008 » unieditor_пустой.html

Viktoria Kopach, 06/13/2012 03:53 PM

 
<!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('&nbsp;');
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', '[&minus;]');
}
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 &mdash; 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&nbsp;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: '[&minus;]',
readOnlyMode: EDIT_MODE_REQ_RO,
handler: deleteNodeConfirm
},
// 'editattr': {
// menu: true,
// name: 'Edit attributes',
// image: 'edit-attrs.png',
// imageAlt: '[&equiv;]',
// 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: '[&minus;]',
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': '&nbsp;' };
// 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 == '') ? '&nbsp;' : loc_text };
}
else
nodeData.attributes._description = { 'value': '&nbsp;' };
}
// 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="[&minus;]" 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 &lt;ID: ' + nodeData.id + '; type: ' + nodeData.attributes._type.value + '&gt;' +
'</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>
(2-2/2)