blob: be7e260491c00dae3abbfdde479bff68fe9e6cc1 [file] [log] [blame]
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +00001/*
2 * Licensed to the Apache Software Foundation (ASF) under one or more
3 * contributor license agreements. See the NOTICE file distributed with
4 * this work for additional information regarding copyright ownership.
5 * The ASF licenses this file to You under the Apache License, Version 2.0
6 * (the "License"); you may not use this file except in compliance with
7 * the License. You may obtain a copy of the License at
8 *
9 * http://www.apache.org/licenses/LICENSE-2.0
10 *
11 * Unless required by applicable law or agreed to in writing, software
12 * distributed under the License is distributed on an "AS IS" BASIS,
13 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 * See the License for the specific language governing permissions and
15 * limitations under the License.
16 */
17// device selection
18var deviceData = false;
19var deviceTableBody = false;
20
21// service selection
22var serviceData = false;
23var serviceDataVars = false;
24var serviceDataInfoID = false;
25var serviceDataInfoType = false;
26
27// actions
28var actionsContainer = false;
29var actionsSelect = false;
30var actionsInvoke = false;
31var actionsTable = false;
32var actionsTableBody = false;
33var actionsTableRow = false;
34
35// tree browser, buttons, error dialog
36var browser = false;
37var searching = false;
38var reloadVars = false;
39
40/* BEGIN HELPERS */
41
42/* helper functions for tree node */
43function _id(dn) { return dn.replace(/[:-\\.\\$]/g,'_') }
44/* creates a node in the device tree */
45function treeNode(id, name, icon, span) {
46 var li = createElement('li', null, { 'id' : _id(id) }, [
47 createElement('span', null, null, [
48 icon ?
49 createElement('img', 'icon', { 'src' : icon }) :
50 createElement('span', 'ui-icon ui-icon-' + span) ,
51 text(name)
52 ])
53 ]);
54 return $(li);
55}
56/* creates a service node in the devices tree, and associates the click action */
57function servNode(udn, urn) {
58 return treeNode(udn+urn, urn, null, 'extlink').click(function() {
59 if (selectServiceTime) {
60 clearTimeout(selectServiceTime);
61 selectServiceTime = false;
62 }
63 $.post(pluginRoot, {
64 'action': 'serviceDetails',
65 'udn' : udn,
66 'urn' : urn
67 }, function(data) {
68 renderService(udn, urn, data)
69 }, 'json');
70 return false;
71 });
72}
73/* a helper function to format device properties values - specially
74 * converts arrays and strings, if the last are links */
75function _val(val) {
76 var ret = '';
77 if ($.isArray(val)) {
78 for (i in val) ret += _val(val[i]) + '<br/>';
79 } else {
80 ret = (typeof val == 'string' && val.indexOf('http://') != -1) ?
81 '<a target="blank" href="' + val + '">' + val + '</a>' : val;
82 }
83 return ret;
84}
85
86
87/* BEGIN UI-ELEMENTS CREATION */
88
89/* add element to the tree, just creates the node */
90function addDevice(device) {
91 var udn = device.props['UPnP.device.UDN'];
92 var name = device.props['UPnP.device.friendlyName'];
93 var icon = null;
94 if (device.icon) icon = pluginRoot + '?icon=' + udn;
95
96 var node = treeNode(udn, name, icon, 'lightbulb').click(function() {
97 renderDevice(device);
Valentin Pavlov Valchev2e894ad2010-03-22 14:42:02 +000098 return false;
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +000099 });
100
101 var ul, hasChildren;
102
103 // services
104 hasChildren = false;
105 ul = $(createElement('ul', 'ui-helper-clearfix'));
106 for(var i in device.services) {
107 hasChildren = true;
108 ul.append( servNode(udn, device.services[i]) );
109 }
110 if (hasChildren) node.append(ul);
111
112 // child devices
113 hasChildren = false;
114 ul = $(createElement('ul'));
115 for(var i in device.children) {
116 hasChildren = true;
Valentin Pavlov Valchev2e894ad2010-03-22 14:42:02 +0000117 ul.append( addDevice(device.children[i]) );
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +0000118 }
119 if (hasChildren) node.append(ul);
120
121 return node;
122}
123/* fills in the list of state variables */
Valentin Pavlov Valchevf1bbf9c2012-04-04 14:18:29 +0000124function sortVarNm(a) { return typeof a != 'undefined' && typeof a.name != undefined ? a.name.toLowerCase() : '' }
125function namedObjectSorter(a,b) { return sortVarNm(a) > sortVarNm(b) ? 1 : -1 }
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +0000126function renderVars(data) {
127 serviceDataVars.empty();
Valentin Pavlov Valchevf1bbf9c2012-04-04 14:18:29 +0000128 data.variables.sort(namedObjectSorter);
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +0000129 for(i in data.variables) {
130 var _var = data.variables[i];
131 var _tr = tr(null, null, [
132 td(null, null, [ text(_var.name) ]),
133 td(null, null, [ text(_var.value) ]),
134 td(null, null, [ text(_var.sendsEvents) ])
135 ]);
136 serviceDataVars.append(_tr);
137 }
138 initStaticWidgets();
139}
140
141/* BEGIN ACTION HANDLERS */
142
143var selectedDevice = false; // the LI element of the selected device, reset on load
144function renderDevice(device) {
145 // generate content
146 var table = '';
Valentin Pavlov Valchevf1bbf9c2012-04-04 14:18:29 +0000147 var sortedKeys = [];
148 for(var key in device.props) sortedKeys.push(key);
149 sortedKeys.sort();
150 for(var x in sortedKeys) {
151 var key = sortedKeys[x];
152 var xvalue = _val(device.props[key]);
153 if ('objectClass' == key) continue;
154 if ('service.id' == key) {
155 xvalue = '<a href="' + appRoot + '/services/' + key + '">' + xvalue + '</a>';
156 }
157 table += '<tr><td class="ui-priority-primary">' + key + '</td><td>' + xvalue + '</td></tr>';
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +0000158 }
159
160 // update the UI
161 deviceTableBody.html(table);
162 reloadVars.addClass('ui-state-disabled');
163 deviceData.removeClass('ui-helper-hidden');
164 serviceData.addClass('ui-helper-hidden')
165
166 // reset selected items
167 if (selectedDevice) selectedDevice.css('font-weight', 'normal');
168 selectedDevice = $('#' + _id(device.props['UPnP.device.UDN']) + ' span').css('font-weight', 'bold');
169}
170
171var selectedUdn = false;
172var selectedUrn = false;
173var selectServiceTime = false;
174function renderService(udn, urn, data) {
175 // save selection
176 selectedUdn = udn;
177 selectedUrn = urn;
178
179 // append service info
180 serviceDataInfoID.text(data.id);
181 serviceDataInfoType.text(data.type);
182
183 // append state variables
184 renderVars(data);
185
186 // append actions
187 if (data.actions) {
188 var html = '';
189 var x = data.actions;
Valentin Pavlov Valchevf1bbf9c2012-04-04 14:18:29 +0000190 x.sort(namedObjectSorter);
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +0000191 for (var a in x) html += '<option value="' + a + '">' + x[a].name + '</option>';
192 actionsSelect.html(html).unbind('change').change(function() {
193 var index = $(this).val();
194 actionSelected(udn, urn, x[index]);
195 }).trigger('change');
196 actionsContainer.removeClass('ui-helper-hidden');
197 } else {
198 actionsContainer.addClass('ui-helper-hidden');
199 }
200
201 // update UI
202 deviceData.addClass('ui-helper-hidden');
203 serviceData.removeClass('ui-helper-hidden');
204 reloadVars.removeClass('ui-state-disabled');
205 initStaticWidgets();
206
207 // refresh once - to get updates asynchronously
208 selectServiceTime = setTimeout('reloadVars.click()', 3000);
209}
210
211function actionSelected(udn, urn, action) {
212 // add input arguments
213 if (action.inVars) {
214 actionsTableBody.empty();
215 for (var i in action.inVars) {
216 var _arg = action.inVars[i];
217 var _tr = actionsTableRow.clone().appendTo(actionsTableBody);
218 _tr.find('td:eq(0)').text(_arg.name);
219 _tr.find('td:eq(1)').text(_arg.type);
220 var _el = _tr.find('input').attr('id', 'arg'+i);
221 _arg['element'] = _el;
222 }
223 actionsTable.removeClass('ui-helper-hidden');
224 } else {
225 actionsTable.addClass('ui-helper-hidden');
226 }
227
228 actionsInvoke.unbind('click').click(function() {
229 invokeAction(udn, urn, action);
230 });
231
232 initStaticWidgets(actionsTableBody);
233}
234
235function invokeAction(udn, urn, action) {
236 // prepare arguments
237 var names = new Array();
238 var vals = new Array();
239 for (var i in action.inVars) {
240 var x = action.inVars[i];
241 names.push(x['name']);
242 vals.push(x['element'].val());
243 }
244 // invoke action
245 $.post(pluginRoot, {
246 'udn' : udn,
247 'urn' : urn,
248 'action': 'invokeAction',
249 'actionID' : action.name,
250 'names' : names,
251 'vals' : vals
252 }, function(data) {
253 var html = i18n.no_params_out;
254 if (data.output) {
255 html = '<table class="nicetable"><tr><th>'+i18n.args_name+'</th><th>'+i18n.args_type+'</th><th>' + i18n.args_value + '</th></tr>';
256 for(var i in data.output) {
257 var arg = data.output[i];
258 html += '<tr><td>' + arg['name'] + '</td><td>' + arg['type'] + '</td><td>' + arg['value'] + '</td></tr>';
259 }
260 html += '</table>';
261 }
262 Xalert(html, i18n.dl_title_ok);
263 }, 'json');
264}
265
Valentin Pavlov Valchev97828d32012-04-03 16:16:05 +0000266function sortNm(a) {
267 if (typeof a != 'undefined' && typeof a.props != undefined) {
268 var nm = a.props['UPnP.device.friendlyName'];
269 if (typeof nm != 'undefined') return nm.toLowerCase();
270 }
271 return '';
272}
273
274function sortFn(a,b) {
275 return sortNm(a) > sortNm(b) ? 1 : -1;
276}
277
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +0000278function listDevices() {
279 browser.empty().addClass('ui-helper-hidden');
280 searching.removeClass('ui-helper-hidden');
Valentin Pavlov Valchev97828d32012-04-03 16:16:05 +0000281
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +0000282 $.post(pluginRoot, { 'action': 'listDevices' }, function(data) {
283 if (data && data.devices) {
Valentin Pavlov Valchev97828d32012-04-03 16:16:05 +0000284 data.devices.sort(sortFn);
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +0000285 $.each(data.devices, function(index) {
286 var html = addDevice(this);
287 browser.treeview( { add: html.appendTo(browser) } );
288 });
Valentin Pavlov Valcheve5060f32012-04-04 11:52:14 +0000289 $('.statline').text(i18n.status_devs.msgFormat(data.devices.length));
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +0000290 } else {
Valentin Pavlov Valcheve5060f32012-04-04 11:52:14 +0000291 $('.statline').text(i18n.status_none);
292 browser.append('', i18n.status_none, '');
Valentin Pavlov Valchevec448422010-03-22 06:52:06 +0000293 }
294
295 // update selected items
296 selectedDevice = false;
297 selectedUdn = false;
298 selectedUrn = false;
299
300 // update IU elements
301 browser.removeClass('ui-helper-hidden');
302 searching.addClass('ui-helper-hidden');
303 deviceData.addClass('ui-helper-hidden');
304 serviceData.addClass('ui-helper-hidden');
305 }, 'json');
306
307 return false;
308}
309
310
311
312$(document).ready( function() {
313 // init elements of style
314 searching = $('#searching');
315 deviceData = $('#deviceData');
316 deviceTableBody = $('#deviceTable tbody');
317
318 // services
319 serviceData = $('#serviceData');
320 serviceDataInfoID = $('#serviceDataInfoID');
321 serviceDataInfoType= $('#serviceDataInfoType');
322 serviceDataVars = $('#serviceDataVars tbody');
323
324 // actions
325 actionsContainer = $('#actionsContainer');
326 actionsSelect = actionsContainer.find('select');
327 actionsInvoke = actionsContainer.find('button');
328 actionsTable = actionsContainer.find('table');
329 actionsTableBody = actionsTable.find('tbody');
330 actionsTableRow = actionsTableBody.find('tr').clone();
331 actionsTableBody.empty();
332
333 // init navigation tree
334 browser = $('#browser').treeview({
335 animated: 'fast',
336 collapsed: true,
337 unique: true
338 });
339
340 // reload button
341 reloadVars = $('#reloadVars').click(function() {
342 if (selectedUdn && selectedUrn) {
343 $.post(pluginRoot, {
344 'action': 'serviceDetails',
345 'udn' : selectedUdn,
346 'urn' : selectedUrn
347 }, renderVars, 'json');
348 }
349 })
350
351 $('#reloadDevices').click(listDevices);
352
353 listDevices();
354});
355