summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--cobbler.spec1
-rw-r--r--setup.py1
-rw-r--r--webui_content/showhide.js191
-rw-r--r--webui_templates/system_edit.tmpl205
-rw-r--r--webui_templates/system_list.tmpl12
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)
diff --git a/setup.py b/setup.py
index 9533127..4e2a7e3 100644
--- a/setup.py
+++ b/setup.py
@@ -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>