diff options
-rw-r--r-- | cobbler.spec | 1 | ||||
-rw-r--r-- | setup.py | 1 | ||||
-rw-r--r-- | webui_content/showhide.js | 191 | ||||
-rw-r--r-- | webui_templates/system_edit.tmpl | 205 | ||||
-rw-r--r-- | webui_templates/system_list.tmpl | 12 |
5 files changed, 351 insertions, 59 deletions
diff --git a/cobbler.spec b/cobbler.spec index 2e68bed..d24acd8 100644 --- a/cobbler.spec +++ b/cobbler.spec @@ -102,6 +102,7 @@ test "x$RPM_BUILD_ROOT" != "x" && rm -rf $RPM_BUILD_ROOT %dir /var/www/cobbler/webui %defattr(444,apache,apache) /var/www/cobbler/webui/*.css +/var/www/cobbler/webui/*.js /var/www/cobbler/webui/*.png /var/www/cobbler/webui/*.html %defattr(-,root,root) @@ -155,6 +155,7 @@ if __name__ == "__main__": (wwwgfx, ['docs/cobbler.html']), (wwwgfx, []), (wwwgfx, ['webui_content/icon_16_sync.png']), + (wwwgfx, ['webui_content/showhide.js']), (wwwgfx, ['webui_content/style.css']), (wwwgfx, ['webui_content/logo-cobbler.png']), (wwwgfx, ['webui_content/cobblerweb.css']), diff --git a/webui_content/showhide.js b/webui_content/showhide.js new file mode 100644 index 0000000..d2f39e1 --- /dev/null +++ b/webui_content/showhide.js @@ -0,0 +1,191 @@ +// Javascript code by Máirín Duffy <duffy@redhat.com> + + +IMAGE_COLLAPSED_PATH = '/img/list-expand.gif'; +IMAGE_EXPANDED_PATH = '/img/list-collapse.gif'; +IMAGE_CHILDLESS_PATH = '/img/rhn-bullet-parentchannel.gif'; + +var rowHash = new Array(); +var browserType; +var columnsPerRow; + +// tip of the Red Hat to Mar Orlygsson for this little IE detection script +var is_ie/*@cc_on = { + quirksmode : (document.compatMode=="BackCompat"), + version : parseFloat(navigator.appVersion.match(/MSIE (.+?);/)[1]) +}@*/; +browserType = is_ie; + +function onLoadStuff(columns) { + columnsPerRow = columns; + var channelTable = document.getElementById('channel-list'); + createParentRows(channelTable, rowHash); + reuniteChildrenWithParents(channelTable, rowHash); + iconifyChildlessParents(rowHash); +} + +function iconifyChildlessParents(rowHash) { + for (var i in rowHash) { + if (!rowHash[i].hasChildren && rowHash[i].image) { rowHash[i].image.src = IMAGE_CHILDLESS_PATH; } + } +} + +// called from clicking the show/hide button on individual rows in the page +function toggleRowVisibility(id) { + if (!rowHash[id]) { return; } + if (!rowHash[id].hasChildren) { return; } + rowHash[id].toggleVisibility(); + return; +} + +function showAllRows() { + var row; + for (var i in rowHash) { + row = rowHash[i]; + if (!row) { continue; } + if (!row.hasChildren) { continue; } + row.show(); + } + return; +} + +function hideAllRows() { + var row; + for (var i in rowHash) { + row = rowHash[i]; + if (!row) { continue; } + if (!row.hasChildren) { continue; } + row.hide(); + } + return; +} + +function Row(cells, image) { + this.cells = new Array(); + for (var i = 0; i < cells.length; i++) { this.cells[i] = cells[i]; } + this.image = image; + this.hasChildren = 0; + this.isHidden = 1; // 1 = hidden; 0 = visible. all rows are hidden by default + +// Row object methods below! + this.toggleVisibility = function() { + if (this.isHidden == 1) { this.show(); } + else if (this.isHidden == 0) { this.hide(); } + return; + } + + this.hide = function hide() { + this.image.src = IMAGE_COLLAPSED_PATH; +// we start with columnsPerRow, because we want to skip the td cells of the parent tr. + for (var i = columnsPerRow; i < this.cells.length; i++) { + this.cells[i].parentNode.style.display = 'none'; + this.cells[i].style.display = 'none'; + } + this.isHidden = 1; + return; + } + + this.show = function() { + displayType = ''; + this.image.src = IMAGE_EXPANDED_PATH; + + for (var i = 0; i < this.cells.length; i++) { + this.cells[i].style.display = displayType; + this.cells[i].parentNode.style.display = displayType; + } + this.isHidden = 0; + return; + } +} + +function createParentRows(channelTable, rowHash) { + for (var i = 0; i < channelTable.rows.length; i++) { + tableRowNode = channelTable.rows[i]; + if (isParentRowNode(tableRowNode)) { + if (!tableRowNode.id) { continue; } + id = tableRowNode.id; + var cells = tableRowNode.cells; + var image = findRowImageFromCells(cells, id) + if (!image) { continue; } + rowHash[id] = new Row(cells, image); + } + } + return; +} + +function reuniteChildrenWithParents(channelTable, rowHash) { + var parentNode; + var childId; + var tableChildRowNode; + for (var i = 0; i < channelTable.rows.length; i++) { + tableChildRowNode = channelTable.rows[i]; +// when we find a parent, set it as parent for the children after it + if (isParentRowNode(tableChildRowNode) && tableChildRowNode.id) { + parentNode = tableChildRowNode; + continue; + } + if (!parentNode) { continue; } + + // it its not a child node we bail here + if (!isChildRowNode(tableChildRowNode)) { continue; } + // FIXME: chceck child id against parent id + if (!rowHash[parentNode.id]) { /*alert('bailing, cant find parent in hash');*/ continue; } + for (var j = 0; j < tableChildRowNode.cells.length; j++) { + rowHash[parentNode.id].cells.push(tableChildRowNode.cells[j]); + rowHash[parentNode.id].hasChildren = 1; + } + } + return; +} + + +function getNodeTagName(node) { + var tagName; + var nodeId; + tagName = new String(node.tagName); + return tagName.toLowerCase(); +} + +function isParentRowNode(node) { + var nodeInLowercase = getNodeTagName(node); + if (nodeInLowercase != 'tr') { return 0; } + nodeId = node.id; + if ((nodeId.indexOf('id')) && !(nodeId.indexOf('child'))) { return 0; } + return 1; +} + +function isChildRowNode(node) { + var nodeInLowercase = getNodeTagName(node); + var nodeId; + if (nodeInLowercase != 'tr') { return 0; } + nodeId = node.id; + if (nodeId.indexOf('child')) { return 0; } + return 1; +} + + +function findRowImageFromCells(cells, id) { + var imageId = id + '-image'; + var childNodes; // first level child + var grandchildNodes; // second level child + for (var i = 0; i < cells.length; i++) { + childNodes = null; + grandchildNodes = null; + + if (!cells[i].hasChildNodes()) { continue; } + + childNodes = cells[i].childNodes; + + for (var j = 0; j < childNodes.length; j++) { + if (!childNodes[j].hasChildNodes()) { continue; } + if (getNodeTagName(childNodes[j]) != 'a') { continue; } + grandchildNodes = childNodes[j].childNodes; + + for (var k = 0; k < grandchildNodes.length; k++) { + if (grandchildNodes[k].name != imageId) { continue; } + if (grandchildNodes[k].nodeName == 'IMG' || grandchildNodes[k].nodeName == 'img') { return grandchildNodes[k]; } + } + } + } + return null; +} diff --git a/webui_templates/system_edit.tmpl b/webui_templates/system_edit.tmpl index d3a763c..65310ae 100644 --- a/webui_templates/system_edit.tmpl +++ b/webui_templates/system_edit.tmpl @@ -3,7 +3,10 @@ #block body +<script language=javascript" src="/cobbler/webui/showhide.js"/> + <script language="javascript"> + #if $system function disablename(value) { @@ -31,6 +34,25 @@ function get_random_mac() #end if </script> +## +## determine a bit about what interfaces should be shown and which should not. +## + +#set $all_interfaces = [ "intf0", "intf1", "intf2", "intf3", "intf4", "intf5", "intf6", "intf7" ] +#if $system + #set $interfaces = $system.interfaces.keys() + #set $defined_interfaces = [] + #for $potential in $all_interfaces + #if $potential in $interfaces + #set $rc = $defined_interfaces.append($potential) + #end if + #end for +#else + #set $interfaces = [ "intf0", "intf1", "intf2", "intf3", "intf4", "intf5", "intf6", "intf7" ] + #set $defined_interfaces = [ "intf0" ] +#end if + + <form method="post" action="$base_url/system_save"> <fieldset id="cform"> @@ -95,50 +117,139 @@ function get_random_mac() </td> </tr> - <tr> - <td> - <label for="mac">MAC</label> - </td> - <td> - <input type="text" size="64" style="width: 150px;" name="mac" id="mac" - #if $system - value="$system.mac_address" + ## ====================================== start of looping through interfaces + + #for $interface in $all_interfaces + + ## ---------------------------------- + ## calculate some initial CSS visibility + ## ---------------------------------- + + #if $interface in $defined_interfaces + #set $toggler_visibile = "hidden" + #set $panel_visibile = "visible" + #else + #set $toggler_visibile = "visible" + #set $panel_visibile = "hidden" #end if - /> - #if not $system - <a href="javascript: get_random_mac()" style="font-size: 0.8em;">random</a> - #end if - <p class="context-tip">Example: AA:BB:CC:DD:EE:FF</p> - </td> - </tr> - <tr> - <td> - <label for="ip">IP</label> - </td> - <td> - <input type="text" size="64" style="width: 150px;" name="ip" id="ip" - #if $system - value="$system.ip_address" + ## ---------------------------------- + ## load up initial variable values + ## ---------------------------------- + + #if $system and $interface in $defined_interfaces + #set $macaddress = $system.interfaces[$interface]["mac_address"] + #set $ipaddress = $system.interfaces[$interface]["ip_address"] + #set $hostname = $system.interfaces[$interface]["hostname"] + #set $dhcptag = $system.interfaces[$interface]["dhcp_tag"] + #set $virtbridge = $system.interfaces[$interface]["virt_bridge"] + #set $subnet = $system.interfaces[$interface]["subnet"] + #set $gateway = $system.interfaces[$interface]["gateway"] + #else + #set $macaddress = "" + #set $ipaddress = "" + #set $hostname = "" + #set $dhcptag = "" + #set $virtbridge = "" + #set $subnet = "" + #set $gateway = "" #end if - /> - <p class="context-tip">Optional. Example: 192.168.10.15</p> - </td> - </tr> - <tr> - <td> - <label for="hostname">Hostname</label> - </td> - <td> - <input type="text" size="255" style="width: 150px;" name="hostname" id="hostname" - #if $system - value="$system.hostname" + ## ---------------------------------------- + ## render the toggle link to hide the interfaces not yet defined + ## ---------------------------------------- + + ## FIXME: these tables need CSS classes, don't they? + <tr class="listrow" id="$interface"> + <td> + <label>Interface ($interface) + </td> + <td> + <hr width="95%"> + </td> + </tr> + + <tr class="listrow" id="toggle_$interface"> + <td> + <label>Expand</label> + </td> + <td> + <A href="javascript:void('')" onclick="show_interface('$interface');">Click to expand $interface</A> + </td> + </tr> + + + ## ---------------------------------------- + ## now show all of the interface fields which may or may not + ## be hidden but are always there + ## ---------------------------------------- + + <tr class="listrow" id="panel_${interface}_mac"> + <td> + <label for="mac-$interface">MAC</label> + </td> + <td> + <input type="text" size="64" style="width: 150px;" name="mac-$interface" id="mac-$interface" + value="$macaddress" + /> + #if not $system + <a href="javascript: get_random_mac()" style="font-size: 0.8em;">random</a> #end if - /> - <p class="context-tip">Optional. Example: vanhalen.example.org</p> - </td> - </tr> + <p class="context-tip">Example: AA:BB:CC:DD:EE:FF</p> + </td> + </tr> + + <tr class="listrow" id="panel_${interface}_ip"> + <td> + <label for="ip-$interface">IP</label> + </td> + <td> + <input type="text" size="64" style="width: 150px;" name="ip-$interface" id="ip-$interface" + value="$ipaddress" + /> + <p class="context-tip">Optional. Example: 192.168.10.15</p> + </td> + </tr> + + <tr class="listrow" id="panel_${interface}_hostname"> + <td> + <label for="hostname-$interface">Hostname</label> + </td> + <td> + <input type="text" size="255" style="width: 150px;" name="hostname-$interface" id="hostname-$interface" + value="$hostname" + /> + <p class="context-tip">Optional. Example: vanhalen.example.org</p> + </td> + </tr> + + <tr class="listrow" id="panel_${interface}_dhcptag"> + <td> + <label for="dhcptag-$interface">DHCP Tag</label> + </td> + <td> + <input type="text" size="128" style="width: 150px;" name="dhcptag-$interface" id="dhcptag-$interface" + value="$dhcptag" + /> + <p class="context-tip">Selects alternative subnets, see manpage or leave blank</p> + </td> + </tr> + + ## FIXME: add virt_bridge editing (like above) + ## FIXME: add subnet editing (like above) + ## FIXME: add gateway editing (like above) + ## FIXME: make the save function understand the new fieldname-$interface variables + ## only enable an interface for saving if one of it's fields is non-empty + ## FIXME: delete checkboxes and accompanying API method. No delete for intf0. + + #end for + ## ====================================== end of looping through interfaces + + ## now we're back to doing regular fields + ## FIXME: should all of these be moved up before the interface section? + ## FIXME: make entire interface block seperately collapseable? + + ## restart the table that we un-started for the DIVs <tr> <td> @@ -182,20 +293,6 @@ function get_random_mac() </td> </tr> - <tr> - <td> - <label for="dhcp_tag">DHCP Tag</label> - </td> - <td> - <input type="text" size="128" style="width: 150px;" name="dhcp_tag" id="dhcp_tag" - #if $system - value="$system.dhcp_tag" - #end if - /> - <p class="context-tip">Selects alternative subnets, see manpage or leave blank</p> - </td> - </tr> - #if $system <tr> <td> @@ -218,6 +315,8 @@ function get_random_mac() </td> </tr> + </table> + </fieldset> </form> diff --git a/webui_templates/system_list.tmpl b/webui_templates/system_list.tmpl index 246ac6b..e74f313 100644 --- a/webui_templates/system_list.tmpl +++ b/webui_templates/system_list.tmpl @@ -7,9 +7,9 @@ <tr> <th class="text">Name</th> <th class="text">Profile</th> - <th class="text">MAC</th> - <th class="text">IP</th> - <th class="text">Hostname</th> + ## FIXME: how to handle for multiple interface listing? <th class="text">MAC</th> + ## <th class="text">IP</th> + ## <th class="text">Hostname</th> </tr> </thead> <tbody> @@ -29,9 +29,9 @@ <td> <a href="$base_url/profile_edit?name=${system.profile}">${system.profile}</a> </td> - <td> ${system.mac_address} </td> - <td> ${system.ip_address} </td> - <td> ${system.hostname} </td> + ## <td> ${system.mac_address} </td> + ## <td> ${system.ip_address} </td> + ## <td> ${system.hostname} </td> </tr> #end for </tbody> |