Resolved FELIX-2121
Initial import of ProSyst donation of UPnP plugin for the web console
git-svn-id: https://svn.apache.org/repos/asf/felix/trunk@925979 13f79535-47bb-0310-9956-ffa450edef68
diff --git a/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/minus.gif b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/minus.gif
new file mode 100644
index 0000000..47fb7b7
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/minus.gif
Binary files differ
diff --git a/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/plus.gif b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/plus.gif
new file mode 100644
index 0000000..6906621
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/plus.gif
Binary files differ
diff --git a/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/treeview-default-line.gif b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/treeview-default-line.gif
new file mode 100644
index 0000000..37114d3
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/treeview-default-line.gif
Binary files differ
diff --git a/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/treeview-default.gif b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/treeview-default.gif
new file mode 100644
index 0000000..a12ac52
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/images/treeview-default.gif
Binary files differ
diff --git a/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/jquery.treeview.css b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/jquery.treeview.css
new file mode 100644
index 0000000..5ced4d4
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/jquery.treeview.css
@@ -0,0 +1,56 @@
+.treeview, .treeview ul {
+ padding: 0;
+ margin: 0;
+ list-style: none;
+}
+
+.treeview ul {
+ background-color: white;
+ margin-top: 4px;
+}
+
+.treeview .hitarea {
+ background: url(images/treeview-default.gif) -64px -25px no-repeat;
+ height: 16px;
+ width: 16px;
+ margin-left: -16px;
+ float: left;
+ cursor: pointer;
+}
+/* fix for IE6 */
+* html .hitarea {
+ display: inline;
+ float:none;
+}
+
+.treeview li {
+ margin: 0;
+ padding: 3px 0pt 3px 16px;
+}
+
+.treeview a.selected {
+ background-color: #eee;
+}
+
+#treecontrol { margin: 1em 0; display: none; }
+
+.treeview .hover { color: red; cursor: pointer; }
+
+.treeview li { background: url(images/treeview-default-line.gif) 0 0 no-repeat; }
+.treeview li.collapsable, .treeview li.expandable { background-position: 0 -176px; }
+
+.treeview .expandable-hitarea { background-position: -80px -3px; }
+
+.treeview li.last { background-position: 0 -1766px }
+.treeview li.lastCollapsable, .treeview li.lastExpandable { background-image: url(images/treeview-default.gif); }
+.treeview li.lastCollapsable { background-position: 0 -111px }
+.treeview li.lastExpandable { background-position: -32px -67px }
+
+.treeview div.lastCollapsable-hitarea, .treeview div.lastExpandable-hitarea { background-position: 0; }
+
+
+.filetree li { padding: 3px 0 2px 16px; }
+.filetree span.folder, .filetree span.file { padding: 1px 0 1px 16px; display: block; }
+.filetree span.folder { background: url(images/folder.gif) 0 0 no-repeat; }
+.filetree li.expandable span.folder { background: url(images/folder-closed.gif) 0 0 no-repeat; }
+.filetree span.file { background: url(images/file.gif) 0 0 no-repeat; }
diff --git a/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/jquery.treeview.pack.js b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/jquery.treeview.pack.js
new file mode 100644
index 0000000..eddac49
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/resources/res/jquery-treeview-1.4/jquery.treeview.pack.js
@@ -0,0 +1,16 @@
+/*
+ * Treeview 1.4 - jQuery plugin to hide and show branches of a tree
+ *
+ * http://bassistance.de/jquery-plugins/jquery-plugin-treeview/
+ * http://docs.jquery.com/Plugins/Treeview
+ *
+ * Copyright (c) 2007 Jörn Zaefferer
+ *
+ * Dual licensed under the MIT and GPL licenses:
+ * http://www.opensource.org/licenses/mit-license.php
+ * http://www.gnu.org/licenses/gpl.html
+ *
+ * Revision: $Id: jquery.treeview.js 4684 2008-02-07 19:08:06Z joern.zaefferer $
+ *
+ */
+eval(function(p,a,c,k,e,r){e=function(c){return(c<a?'':e(parseInt(c/a)))+((c=c%a)>35?String.fromCharCode(c+29):c.toString(36))};if(!''.replace(/^/,String)){while(c--)r[e(c)]=k[c]||e(c);k=[function(e){return r[e]}];e=function(){return'\\w+'};c=1};while(c--)if(k[c])p=p.replace(new RegExp('\\b'+e(c)+'\\b','g'),k[c]);return p}(';(4($){$.1l($.F,{E:4(b,c){l a=3.n(\'.\'+b);3.n(\'.\'+c).o(c).m(b);a.o(b).m(c);8 3},s:4(a,b){8 3.n(\'.\'+a).o(a).m(b).P()},1n:4(a){a=a||"1j";8 3.1j(4(){$(3).m(a)},4(){$(3).o(a)})},1h:4(b,a){b?3.1g({1e:"p"},b,a):3.x(4(){T(3)[T(3).1a(":U")?"H":"D"]();7(a)a.A(3,O)})},12:4(b,a){7(b){3.1g({1e:"D"},b,a)}1L{3.D();7(a)3.x(a)}},11:4(a){7(!a.1k){3.n(":r-1H:G(9)").m(k.r);3.n((a.1F?"":"."+k.X)+":G(."+k.W+")").6(">9").D()}8 3.n(":y(>9)")},S:4(b,c){3.n(":y(>9):G(:y(>a))").6(">1z").C(4(a){c.A($(3).19())}).w($("a",3)).1n();7(!b.1k){3.n(":y(>9:U)").m(k.q).s(k.r,k.t);3.G(":y(>9:U)").m(k.u).s(k.r,k.v);3.1r("<J 14=\\""+k.5+"\\"/>").6("J."+k.5).x(4(){l a="";$.x($(3).B().1o("14").13(" "),4(){a+=3+"-5 "});$(3).m(a)})}3.6("J."+k.5).C(c)},z:4(g){g=$.1l({N:"z"},g);7(g.w){8 3.1K("w",[g.w])}7(g.p){l d=g.p;g.p=4(){8 d.A($(3).B()[0],O)}}4 1m(b,c){4 L(a){8 4(){K.A($("J."+k.5,b).n(4(){8 a?$(3).B("."+a).1i:1I}));8 1G}}$("a:10(0)",c).C(L(k.u));$("a:10(1)",c).C(L(k.q));$("a:10(2)",c).C(L())}4 K(){$(3).B().6(">.5").E(k.Z,k.Y).E(k.I,k.M).P().E(k.u,k.q).E(k.v,k.t).6(">9").1h(g.1f,g.p);7(g.1E){$(3).B().1D().6(">.5").s(k.Z,k.Y).s(k.I,k.M).P().s(k.u,k.q).s(k.v,k.t).6(">9").12(g.1f,g.p)}}4 1d(){4 1C(a){8 a?1:0}l b=[];j.x(4(i,e){b[i]=$(e).1a(":y(>9:1B)")?1:0});$.V(g.N,b.1A(""))}4 1c(){l b=$.V(g.N);7(b){l a=b.13("");j.x(4(i,e){$(e).6(">9")[1y(a[i])?"H":"D"]()})}}3.m("z");l j=3.6("Q").11(g);1x(g.1w){18"V":l h=g.p;g.p=4(){1d();7(h){h.A(3,O)}};1c();17;18"1b":l f=3.6("a").n(4(){8 3.16.15()==1b.16.15()});7(f.1i){f.m("1v").1u("9, Q").w(f.19()).H()}17}j.S(g,K);7(g.R){1m(3,g.R);$(g.R).H()}8 3.1t("w",4(a,b){$(b).1s().o(k.r).o(k.v).o(k.t).6(">.5").o(k.I).o(k.M);$(b).6("Q").1q().11(g).S(g,K)})}});l k=$.F.z.1J={W:"W",X:"X",q:"q",Y:"q-5",M:"t-5",u:"u",Z:"u-5",I:"v-5",v:"v",t:"t",r:"r",5:"5"};$.F.1p=$.F.z})(T);',62,110,'|||this|function|hitarea|find|if|return|ul||||||||||||var|addClass|filter|removeClass|toggle|expandable|last|replaceClass|lastExpandable|collapsable|lastCollapsable|add|each|has|treeview|apply|parent|click|hide|swapClass|fn|not|show|lastCollapsableHitarea|div|toggler|handler|lastExpandableHitarea|cookieId|arguments|end|li|control|applyClasses|jQuery|hidden|cookie|open|closed|expandableHitarea|collapsableHitarea|eq|prepareBranches|heightHide|split|class|toLowerCase|href|break|case|next|is|location|deserialize|serialize|height|animated|animate|heightToggle|length|hover|prerendered|extend|treeController|hoverClass|attr|Treeview|andSelf|prepend|prev|bind|parents|selected|persist|switch|parseInt|span|join|visible|binary|siblings|unique|collapsed|false|child|true|classes|trigger|else'.split('|'),0,{}))
\ No newline at end of file
diff --git a/webconsole-plugins/upnp/src/main/resources/res/loading.gif b/webconsole-plugins/upnp/src/main/resources/res/loading.gif
new file mode 100644
index 0000000..a4242e4
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/resources/res/loading.gif
Binary files differ
diff --git a/webconsole-plugins/upnp/src/main/resources/res/upnp.css b/webconsole-plugins/upnp/src/main/resources/res/upnp.css
new file mode 100644
index 0000000..2e5d5ce
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/resources/res/upnp.css
@@ -0,0 +1,39 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#detailsBox { padding-left: .5em }
+#dialog .nicetable { font-size: .5em }
+#detailsBox h3 {
+ font-weight: bold;
+ font-size: 1.5em;
+ padding-top: 1em;
+}
+#treeBox , #treeCont {
+ width: 300px !important;
+ height: 100%;
+ min-height: 300px;
+ overflow: auto;
+}
+#browser { margin: 1em; height: 100% }
+#browser li { cursor: pointer }
+#browser span.ui-icon { display: inline-block }
+img.icon { /* force image size */
+ border: none;
+ width: 16px;
+ height: 16px;
+ margin: 0;
+ padding: 0;
+}
diff --git a/webconsole-plugins/upnp/src/main/resources/res/upnp.html b/webconsole-plugins/upnp/src/main/resources/res/upnp.html
new file mode 100644
index 0000000..67e1d5f
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/resources/res/upnp.html
@@ -0,0 +1,121 @@
+<script type="text/javascript" src="${pluginRoot}/res/jquery-treeview-1.4/jquery.treeview.pack.js"></script>
+<script type="text/javascript" src="${pluginRoot}/res/upnp.js"></script>
+<script type="text/javascript">
+// <![CDATA[
+// i18n
+var i18n = {
+ dl_title_ok : '${dialog.title.ok}',
+ args_name : '${args.name}',
+ args_type : '${args.type}',
+ args_value : '${args.value}',
+ no_actions : '${no.actions}',
+ no_params_out: '${no.params.out}'
+}
+// ]]>
+</script>
+
+<p class="statline">${status.ok}</p>
+
+<form method="post" enctype="multipart/form-data" action="" onsubmit="return false">
+ <div class="ui-widget-header ui-corner-top buttonGroup">
+ <button id="reloadDevices">${btn.search}</button>
+ <button id="reloadVars" class="ui-state-disabled">${btn.reloadVars}</button>
+ </div>
+</form>
+
+<table id="plugin_table" style="width: 100%">
+ <tr>
+ <td id="treeCont" class="ui-widget-content ui-corner-bottom">
+ <div id="searching"> <!-- search for devices -->
+ ${tree.searching}
+ <img src="${pluginRoot}/res/loading.gif" alt="${tree.loading.title}" />
+ </div>
+ <div id="treeBox"> <!-- here comes the tree -->
+ <ul id="browser">
+ <li>dummy</li>
+ </ul>
+ </div>
+ </td>
+ <td id="detailsBox">
+ <!-- opened when device is selected -->
+ <div id="deviceData" class="ui-helper-hidden">
+ <h3>${device.title}</h3>
+ <table id="deviceTable" class="nicetable">
+ <thead>
+ <tr>
+ <th>${prop.name}</th>
+ <th>${prop.value}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><td colspan="2"> </td></tr> <!-- dynamic contents -->
+ </tbody>
+ </table>
+ </div>
+ <div id="serviceData" class="ui-helper-hidden">
+ <h3>${service.title}</h3>
+ <table class="nicetable">
+ <thead>
+ <tr>
+ <th>${prop.name}</th>
+ <th>${prop.value}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr>
+ <td class="ui-priority-primary">${service.id}</td>
+ <td id="serviceDataInfoID"> </td><!-- dynamic contents -->
+ </tr>
+ <tr>
+ <td class="ui-priority-primary">${service.type}</td>
+ <td id="serviceDataInfoType"> </td><!-- dynamic contents -->
+ </tr>
+ </tbody>
+ </table>
+
+ <h3>${vars.title}</h3>
+ <table id="serviceDataVars" class="tablesorter nicetable">
+ <thead>
+ <tr>
+ <th class="col_Name">${vars.name}</th>
+ <th class="col_Value">${vars.value}</th>
+ <th class="col_SendEvents">${vars.events}</th>
+ </tr>
+ </thead>
+ <tbody><!-- dynamic contents -->
+ <tr><td> </td><td> </td><td> </td></tr>
+ </tbody>
+ </table>
+
+ <div id="actionsContainer">
+ <h3>${actions.title}</h3>
+ <div class="ui-widget-header ui-corner-top buttonGroup">
+ ${actions.select}
+ <select name="c">
+ <option value="---">---</option>
+ </select>
+ <button title="${actions.invoke.title}"><span class="ui-icon ui-icon-play"> </span></button>
+ </div>
+ <table class="nicetable">
+ <thead>
+ <tr>
+ <th>${args.name}</th>
+ <th>${args.type}</th>
+ <th>${args.value}</th>
+ </tr>
+ </thead>
+ <tbody>
+ <tr><!-- template -->
+ <td> </td>
+ <td> </td>
+ <td><input value="" /></td>
+ </tr>
+ </tbody>
+ </table>
+ </div>
+ </div> <!-- serviceData -->
+
+ </td>
+ </tr>
+</table>
+
diff --git a/webconsole-plugins/upnp/src/main/resources/res/upnp.js b/webconsole-plugins/upnp/src/main/resources/res/upnp.js
new file mode 100644
index 0000000..8899f7d
--- /dev/null
+++ b/webconsole-plugins/upnp/src/main/resources/res/upnp.js
@@ -0,0 +1,326 @@
+/*
+ * Licensed to the Apache Software Foundation (ASF) under one or more
+ * contributor license agreements. See the NOTICE file distributed with
+ * this work for additional information regarding copyright ownership.
+ * The ASF licenses this file to You under the Apache License, Version 2.0
+ * (the "License"); you may not use this file except in compliance with
+ * the License. You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+// device selection
+var deviceData = false;
+var deviceTableBody = false;
+
+// service selection
+var serviceData = false;
+var serviceDataVars = false;
+var serviceDataInfoID = false;
+var serviceDataInfoType = false;
+
+// actions
+var actionsContainer = false;
+var actionsSelect = false;
+var actionsInvoke = false;
+var actionsTable = false;
+var actionsTableBody = false;
+var actionsTableRow = false;
+
+// tree browser, buttons, error dialog
+var browser = false;
+var searching = false;
+var reloadVars = false;
+
+/* BEGIN HELPERS */
+
+/* helper functions for tree node */
+function _id(dn) { return dn.replace(/[:-\\.\\$]/g,'_') }
+/* creates a node in the device tree */
+function treeNode(id, name, icon, span) {
+ var li = createElement('li', null, { 'id' : _id(id) }, [
+ createElement('span', null, null, [
+ icon ?
+ createElement('img', 'icon', { 'src' : icon }) :
+ createElement('span', 'ui-icon ui-icon-' + span) ,
+ text(name)
+ ])
+ ]);
+ return $(li);
+}
+/* creates a service node in the devices tree, and associates the click action */
+function servNode(udn, urn) {
+ return treeNode(udn+urn, urn, null, 'extlink').click(function() {
+ if (selectServiceTime) {
+ clearTimeout(selectServiceTime);
+ selectServiceTime = false;
+ }
+ $.post(pluginRoot, {
+ 'action': 'serviceDetails',
+ 'udn' : udn,
+ 'urn' : urn
+ }, function(data) {
+ renderService(udn, urn, data)
+ }, 'json');
+ return false;
+ });
+}
+/* a helper function to format device properties values - specially
+ * converts arrays and strings, if the last are links */
+function _val(val) {
+ var ret = '';
+ if ($.isArray(val)) {
+ for (i in val) ret += _val(val[i]) + '<br/>';
+ } else {
+ ret = (typeof val == 'string' && val.indexOf('http://') != -1) ?
+ '<a target="blank" href="' + val + '">' + val + '</a>' : val;
+ }
+ return ret;
+}
+
+
+/* BEGIN UI-ELEMENTS CREATION */
+
+/* add element to the tree, just creates the node */
+function addDevice(device) {
+ var udn = device.props['UPnP.device.UDN'];
+ var name = device.props['UPnP.device.friendlyName'];
+ var icon = null;
+ if (device.icon) icon = pluginRoot + '?icon=' + udn;
+
+ var node = treeNode(udn, name, icon, 'lightbulb').click(function() {
+ renderDevice(device);
+ });
+
+ var ul, hasChildren;
+
+ // services
+ hasChildren = false;
+ ul = $(createElement('ul', 'ui-helper-clearfix'));
+ for(var i in device.services) {
+ hasChildren = true;
+ ul.append( servNode(udn, device.services[i]) );
+ }
+ if (hasChildren) node.append(ul);
+
+ // child devices
+ hasChildren = false;
+ ul = $(createElement('ul'));
+ for(var i in device.children) {
+ hasChildren = true;
+ addDevice(device.children[i]);
+ }
+ if (hasChildren) node.append(ul);
+
+ return node;
+}
+/* fills in the list of state variables */
+function renderVars(data) {
+ serviceDataVars.empty();
+ for(i in data.variables) {
+ var _var = data.variables[i];
+ var _tr = tr(null, null, [
+ td(null, null, [ text(_var.name) ]),
+ td(null, null, [ text(_var.value) ]),
+ td(null, null, [ text(_var.sendsEvents) ])
+ ]);
+ serviceDataVars.append(_tr);
+ }
+ initStaticWidgets();
+}
+
+/* BEGIN ACTION HANDLERS */
+
+var selectedDevice = false; // the LI element of the selected device, reset on load
+function renderDevice(device) {
+ // generate content
+ var table = '';
+ for(var key in device.props) {
+ table += '<tr><td class="ui-priority-primary">' + key + '</td><td>' + _val(device.props[key]) + '</td></tr>';
+ }
+
+ // update the UI
+ deviceTableBody.html(table);
+ reloadVars.addClass('ui-state-disabled');
+ deviceData.removeClass('ui-helper-hidden');
+ serviceData.addClass('ui-helper-hidden')
+
+ // reset selected items
+ if (selectedDevice) selectedDevice.css('font-weight', 'normal');
+ selectedDevice = $('#' + _id(device.props['UPnP.device.UDN']) + ' span').css('font-weight', 'bold');
+}
+
+var selectedUdn = false;
+var selectedUrn = false;
+var selectServiceTime = false;
+function renderService(udn, urn, data) {
+ // save selection
+ selectedUdn = udn;
+ selectedUrn = urn;
+
+ // append service info
+ serviceDataInfoID.text(data.id);
+ serviceDataInfoType.text(data.type);
+
+ // append state variables
+ renderVars(data);
+
+ // append actions
+ if (data.actions) {
+ var html = '';
+ var x = data.actions;
+ for (var a in x) html += '<option value="' + a + '">' + x[a].name + '</option>';
+ actionsSelect.html(html).unbind('change').change(function() {
+ var index = $(this).val();
+ actionSelected(udn, urn, x[index]);
+ }).trigger('change');
+ actionsContainer.removeClass('ui-helper-hidden');
+ } else {
+ actionsContainer.addClass('ui-helper-hidden');
+ }
+
+ // update UI
+ deviceData.addClass('ui-helper-hidden');
+ serviceData.removeClass('ui-helper-hidden');
+ reloadVars.removeClass('ui-state-disabled');
+ initStaticWidgets();
+
+ // refresh once - to get updates asynchronously
+ selectServiceTime = setTimeout('reloadVars.click()', 3000);
+}
+
+function actionSelected(udn, urn, action) {
+ // add input arguments
+ if (action.inVars) {
+ actionsTableBody.empty();
+ for (var i in action.inVars) {
+ var _arg = action.inVars[i];
+ var _tr = actionsTableRow.clone().appendTo(actionsTableBody);
+ _tr.find('td:eq(0)').text(_arg.name);
+ _tr.find('td:eq(1)').text(_arg.type);
+ var _el = _tr.find('input').attr('id', 'arg'+i);
+ _arg['element'] = _el;
+ }
+ actionsTable.removeClass('ui-helper-hidden');
+ } else {
+ actionsTable.addClass('ui-helper-hidden');
+ }
+
+ actionsInvoke.unbind('click').click(function() {
+ invokeAction(udn, urn, action);
+ });
+
+ initStaticWidgets(actionsTableBody);
+}
+
+function invokeAction(udn, urn, action) {
+ // prepare arguments
+ var names = new Array();
+ var vals = new Array();
+ for (var i in action.inVars) {
+ var x = action.inVars[i];
+ names.push(x['name']);
+ vals.push(x['element'].val());
+ }
+ // invoke action
+ $.post(pluginRoot, {
+ 'udn' : udn,
+ 'urn' : urn,
+ 'action': 'invokeAction',
+ 'actionID' : action.name,
+ 'names' : names,
+ 'vals' : vals
+ }, function(data) {
+ var html = i18n.no_params_out;
+ if (data.output) {
+ html = '<table class="nicetable"><tr><th>'+i18n.args_name+'</th><th>'+i18n.args_type+'</th><th>' + i18n.args_value + '</th></tr>';
+ for(var i in data.output) {
+ var arg = data.output[i];
+ html += '<tr><td>' + arg['name'] + '</td><td>' + arg['type'] + '</td><td>' + arg['value'] + '</td></tr>';
+ }
+ html += '</table>';
+ }
+ Xalert(html, i18n.dl_title_ok);
+ }, 'json');
+}
+
+function listDevices() {
+ browser.empty().addClass('ui-helper-hidden');
+ searching.removeClass('ui-helper-hidden');
+
+ $.post(pluginRoot, { 'action': 'listDevices' }, function(data) {
+ if (data && data.devices) {
+ $.each(data.devices, function(index) {
+ var html = addDevice(this);
+ browser.treeview( { add: html.appendTo(browser) } );
+ });
+ } else {
+ browser.append('','No devices available', '');
+ }
+
+ // update selected items
+ selectedDevice = false;
+ selectedUdn = false;
+ selectedUrn = false;
+
+ // update IU elements
+ browser.removeClass('ui-helper-hidden');
+ searching.addClass('ui-helper-hidden');
+ deviceData.addClass('ui-helper-hidden');
+ serviceData.addClass('ui-helper-hidden');
+ }, 'json');
+
+ return false;
+}
+
+
+
+$(document).ready( function() {
+ // init elements of style
+ searching = $('#searching');
+ deviceData = $('#deviceData');
+ deviceTableBody = $('#deviceTable tbody');
+
+ // services
+ serviceData = $('#serviceData');
+ serviceDataInfoID = $('#serviceDataInfoID');
+ serviceDataInfoType= $('#serviceDataInfoType');
+ serviceDataVars = $('#serviceDataVars tbody');
+
+ // actions
+ actionsContainer = $('#actionsContainer');
+ actionsSelect = actionsContainer.find('select');
+ actionsInvoke = actionsContainer.find('button');
+ actionsTable = actionsContainer.find('table');
+ actionsTableBody = actionsTable.find('tbody');
+ actionsTableRow = actionsTableBody.find('tr').clone();
+ actionsTableBody.empty();
+
+ // init navigation tree
+ browser = $('#browser').treeview({
+ animated: 'fast',
+ collapsed: true,
+ unique: true
+ });
+
+ // reload button
+ reloadVars = $('#reloadVars').click(function() {
+ if (selectedUdn && selectedUrn) {
+ $.post(pluginRoot, {
+ 'action': 'serviceDetails',
+ 'udn' : selectedUdn,
+ 'urn' : selectedUrn
+ }, renderVars, 'json');
+ }
+ })
+
+ $('#reloadDevices').click(listDevices);
+
+ listDevices();
+});
+