www rc2-final

This commit is contained in:
Max 2021-07-25 20:43:04 -04:00
parent aec5a8012c
commit 180a4dec97
27 changed files with 20570 additions and 1496 deletions

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.4 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 16 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 18 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 22 KiB

0
op25/gr-op25_repeater/www/images/favicon.ico Executable file → Normal file
View File

Before

Width:  |  Height:  |  Size: 1.1 KiB

After

Width:  |  Height:  |  Size: 1.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 53 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 160 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 148 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 201 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 158 B

Binary file not shown.

After

Width:  |  Height:  |  Size: 146 B

View File

@ -0,0 +1,116 @@
<!--
Copyright 2017, 2018 Max H. Parke KA1RBI
Copyright 2021 Michael Rose
This file is part of OP25
OP25 is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
OP25 is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with OP25; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Boston, MA
02110-1301, USA.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OP25 - Edit System Site Alias</title>
<script src="jquery.js"></script>
<script src="editor.js"></script>
<script src="main.js"></script>
<script src="config.js"></script>
<script src="jquery.alerts.js"></script>
<link rel="stylesheet" type="text/css" id="style" href="main.css">
</head>
<body onload="javascript:tsv_onload();">
<a href="#" name="top"></a>
<div class="tsv-controls">
<!-- <table style="width: 705px; border-collapse: collapse; border: 0px solid var(~~bg-color);"> -->
<table class="tsv">
<tr colspan="2">
<td>
<div id="title" class="nac" style="font-weight: normal;">Editor - OP25</div>
</td>
<td>
<p align="right"><a href="#" onclick="window.close();" style="text-decoration: none;" title="Close">&#x274C;</a></p>
</td>
</tr>
<tr>
<td>
<button onclick="this.blur(); beginAlias();" id="btnLoad" title="Load from Server">Load</button>&nbsp;&nbsp;
<button onclick="this.blur(); saveAliasTable();"id="btnSave1" class="saveButton" title="Save to Server">Save</button>&nbsp;&nbsp;
<!--
<button onclick="this.blur(); dispImport();" title="Import TSV or CSV">Import TODO</button>&nbsp;&nbsp;
<button onclick="tsv_csv();" title="Export as CSV">Export TODO</button>
-->
</td>
<td align='right'>
<span class="label">Status: </span>
<span id="message" class="value">Ready</span>
<img src="loading.gif" style="height: 15px;" id="loading">
</td>
</tr>
</table>
<br>
<input type="text" id="searchInput" style="width: 643px;" onkeyup="searchTsvTable()" placeholder="Filter" title="Search">
<div id="csv-upload" style="display: none;">
<table class=editor><th colspan="2">Import Data</th>
<tr><td>
<span class="label"> Select a CSV or TSV file to import. <br><br>
<input type="file" id="csvfile" name="filename">&nbsp;&nbsp;
<!-- <button id="importnow" onclick="this.blur(); importNow();">Import Now</button> -->
</td>
<td style="width: 100px; text-align: center;">
<button onclick="document.getElementById('csvfile').value='';" style="width: 80px;"> Reset </button><br>
<button onclick="this.blur(); hideImport();" style="width: 80px;"> Cancel </button>
</td>
</tr>
</table>
<br><br>
</div>
</div>
<div id="save-div">
<br>&nbsp;&nbsp;
<!-- <button onclick="saveTable();"id="btnSave" class="saveButton">Save Talkgroups</button>&nbsp;&nbsp;<br>&nbsp;&nbsp; -->
<!-- <button onclick="window.location.href='#top;'"id="btnSave" class="saveButton">Top</button>&nbsp;&nbsp;<br>&nbsp; -->
</div>
<div id="main"></div>
<!-- Main Content Area -->
<div class="footer">
&nbsp;<br><button onclick="saveAliasTable();"id="btnSave2" class="saveButton">Save Talkgroups</button>
&nbsp;
&nbsp;
<button onclick="deleteSys()">Delete System</button>
&nbsp;
&nbsp;
<button onclick="up();">Go to Top</button>&nbsp;&nbsp;&nbsp;
<!-- <button onclick="tsv_csv();">Export as CSV</button>&nbsp;&nbsp;&nbsp; -->
<button onclick="this.blur(); help();" class="btnHelp">Help</button>&nbsp;&nbsp;
<button onclick="window.close();">Close</button>
<br>
</div>
<div style="display: none;"> <!-- placeholder for the color values -->
<span id="loadSettings"></span>
<input type="color" class="accColor" id="acc1"></input>
<input type="color" class="accColor" id="acc2"></input>
<input type="color" class="valColor" id="valColor">
<input type="color" class="sysColor" id="sysColor"></input>
<input type="color" class="btnColor" id="btnColor"></input>
</div>
</body>
</html>

View File

@ -0,0 +1,616 @@
// Copyright 2017, 2018, 2019, 2020, 2021 Max H. Parke KA1RBI
//
// This file is part of OP25
//
// OP25 is free software; you can redistribute it and/or modify it
// under the terms of the GNU General Public License as published by
// the Free Software Foundation; either version 3, or (at your option)
// any later version.
//
// OP25 is distributed in the hope that it will be useful, but WITHOUT
// ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
// or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
// License for more details.
//
// You should have received a copy of the GNU General Public License
// along with OP25; see the file COPYING. If not, write to the Free
// Software Foundation, Inc., 51 Franklin Street, Boston, MA
// 02110-1301, USA.
// Functions related to Online Config
function find_parent(ele, tagname) {
while (ele) {
if (ele.nodeName == tagname)
return ele;
else if (ele.nodeName == 'HTML')
return null;
ele = ele.parentNode;
}
return null;
}
function f_command(ele, command) {
var myrow = find_parent(ele, 'TR');
var mytbl = find_parent(ele, 'TABLE');
amend_d(myrow, mytbl, command);
}
function edit_freq(freq, to_ui) {
var MHZ = 1000000;
if (to_ui) {
var f = freq / MHZ + '';
if (f.indexOf('.') == -1)
f += '.0';
return f;
} else {
var f = parseFloat(freq);
if (freq.indexOf('.'))
f *= MHZ;
return Math.round(f);
}
}
function edit_d(d, to_ui) {
var new_d = {};
var hexints = {
'nac': 1
};
var ints = {
'if_rate': 1,
'ppm': 1,
'rate': 1,
'offset': 1,
'nac': 1,
'logfile-workers': 1,
'decim-amt': 1,
'seek': 1,
'hamlib-model': 1
};
var bools = {
'active': 1,
'trunked': 1,
'rate': 1,
'offset': 1,
'phase2_tdma': 1,
'phase2-tdma': 1,
'wireshark': 1,
'udp-player': 1,
'audio-if': 1,
'tone-detect': 1,
'vocoder': 1,
'audio': 1,
'pause': 1
};
var floats = {
'costas-alpha': 1,
'gain-mu': 1,
'calibration': 1,
'fine-tune': 1,
'gain': 1,
'excess-bw': 1,
'offset': 1,
'excess_bw': 1
};
var lists = {
'blacklist': 1,
'whitelist': 1,
'cclist': 1
};
var freqs = {
'frequency': 1,
'cclist': 1
};
for (var k in d) {
if (!to_ui) {
if (d[k] == 'None')
new_d[k] = '';
else
new_d[k] = d[k];
if (k == 'plot' && !d[k].length)
new_d[k] = null;
if (k in ints) {
new_d[k] = parseInt(new_d[k]);
} else if (k in floats) {
new_d[k] = parseFloat(new_d[k]);
} else if (k in lists) {
var l = [];
if (new_d[k].length)
l = new_d[k].split(',');
if (k in freqs && new_d[k].length) {
var new_l = [];
for (var i in l)
new_l.push(edit_freq(l[i], to_ui));
new_d[k] = new_l;
} else {
new_d[k] = l;
}
} else if (k in freqs) {
new_d[k] = edit_freq(new_d[k], to_ui);
}
} else {
if (k in hexints) {
if (d[k] == null)
new_d[k] = '0x0';
else
new_d[k] = '0x' + d[k].toString(16);
} else if (k in ints) {
if (d[k] == null)
new_d[k] = '';
else
new_d[k] = d[k].toString(10);
} else if (k in lists) {
if (k in freqs) {
var new_l = [];
for (var i in d[k]) {
new_l.push(edit_freq(d[k][i], to_ui));
}
new_d[k] = new_l.join(',');
} else {
if (!d[k] || !d[k].length)
new_d[k] = [];
else
new_d[k] = d[k].join(',');
}
} else if (k in freqs) {
new_d[k] = edit_freq(d[k], to_ui);
} else {
new_d[k] = d[k];
}
}
}
return new_d;
}
function edit_l(cfg, to_ui) {
var new_d = {
'devices': [],
'channels': []
};
for (var device in cfg['devices'])
new_d['devices'].push(edit_d(cfg['devices'][device], to_ui));
for (var channel in cfg['channels'])
new_d['channels'].push(edit_d(cfg['channels'][channel], to_ui));
new_d['backend-rx'] = edit_d(cfg['backend-rx'], to_ui);
return new_d;
}
function amend_d(myrow, mytbl, command) {
var trunk_row = null;
if (mytbl.id == 'chtable')
trunk_row = find_next(myrow, 'TR');
if (command == 'delete') {
var ok = confirm('Confirm delete');
if (ok) {
myrow.parentNode.removeChild(myrow);
if (mytbl.id == 'chtable')
trunk_row.parentNode.removeChild(trunk_row);
}
} else if (command == 'clone') {
var newrow = myrow.cloneNode(true);
newrow.id = find_free_id('id_');
if (mytbl.id == 'chtable') {
var newrow2 = trunk_row.cloneNode(true);
newrow2.id = 'tr_' + newrow.id.substring(3);
if (trunk_row.nextSibling) {
myrow.parentNode.insertBefore(newrow2, trunk_row.nextSibling);
myrow.parentNode.insertBefore(newrow, trunk_row.nextSibling);
} else {
myrow.parentNode.appendChild(newrow);
myrow.parentNode.appendChild(newrow2);
}
} else {
if (myrow.nextSibling)
myrow.parentNode.insertBefore(newrow, myrow.nextSibling);
else
myrow.parentNode.appendChild(newrow);
}
} else if (command == 'new') {
var newrow = null;
var parent = null;
var pfx = 'id_';
if (mytbl.id == 'chtable') {
newrow = document.getElementById('chrow').cloneNode(true);
parent = document.getElementById('chrow').parentNode;
} else if (mytbl.id == 'devtable') {
newrow = document.getElementById('devrow').cloneNode(true);
parent = document.getElementById('devrow').parentNode;
} else if (mytbl.className == 'tgtable') {
newrow = mytbl.querySelector('.tgrow').cloneNode(true);
parent = mytbl.querySelector('.tgrow').parentNode;
pfx = 'tg_';
} else {
return null;
}
newrow.style['display'] = '';
newrow.id = find_free_id(pfx);
parent.appendChild(newrow);
if (mytbl.id == 'chtable') {
var newrow2 = document.getElementById('trrow').cloneNode(true);
newrow2.id = 'tr_' + newrow.id.substring(3);
parent.appendChild(newrow2);
}
return newrow;
}
}
function f_save_list(ele) {
var flist = [];
for (var nac in enable_status) {
if (enable_status[nac])
flist.push(nac.toString(10));
}
if (flist.length == 0) {
jAlert('Cannot disable all NACs - request ignored.', 'Warning');
}
document.getElementById('save_list_row').style['display'] = 'none';
enable_changed = false;
send_command('settings-enable', flist.join(','));
}
function f_enable_changed(ele, nac) {
enable_status[nac] = ele.checked;
enable_changed = true;
document.getElementById('save_list_row').style['display'] = '';
}
function config_list(d) {
var html = '';
html += '<select id="config_select" name="cfg-list">';
for (var file in d['data']) {
html += '<option value="' + d['data'][file] + '">' + d['data'][file] + '</option>';
}
html += '<option value="New Configuration">New Configuration</option>';
html += '</select>';
document.getElementById('cfg_list_area').innerHTML = html;
}
function config_data(d) {
var cfg = edit_l(d['data'], true);
open_editor();
var chtable = document.getElementById('chtable');
var devtable = document.getElementById('devtable');
var chrow = document.getElementById('chrow');
var devrow = document.getElementById('devrow');
for (var device in cfg['devices'])
rollup_row('dev', amend_d(devrow, devtable, 'new'), cfg['devices'][device]);
for (var channel in cfg['channels'])
rollup_row('ch', amend_d(chrow, chtable, 'new'), cfg['channels'][channel]);
rollup_rx_rows(cfg['backend-rx']);
}
function open_editor() {
document.getElementById('edit_settings').style['display'] = '';
var rows = document.querySelectorAll('.dynrow');
var ct = 0;
for (var r in rows) {
var row = rows[r];
ct += 1;
if (row.id && (row.id.substring(0, 3) == 'id_' || row.id.substring(0, 3) == 'tr_')) {
row.parentNode.removeChild(row);
}
}
var oldtbl = document.getElementById('rt_1');
if (oldtbl)
oldtbl.parentNode.removeChild(oldtbl);
var tbl = document.getElementById('rxopt-table');
var newtbl = tbl.cloneNode(true);
newtbl.id = 'rt_1';
newtbl.style['display'] = '';
var rxrow = newtbl.querySelector('.rxrow');
var advrow = newtbl.querySelector('.advrow');
rxrow.id = 'rx_1';
advrow.id = 'rx_2';
if (tbl.nextSibling)
tbl.parentNode.insertBefore(newtbl, tbl.nextSibling);
else
tbl.parentNode.appendChild(newtbl);
}
function find_next(e, tag) {
var n = e.nextSibling;
for (var i = 0; i < 25; i++) {
if (n == null)
return null;
if (n.nodeName == tag)
return n;
n = n.nextSibling;
}
return null;
}
function find_free_id(pfx) {
for (var seq = 1; seq < 5000; seq++) {
var test_id = pfx + seq;
var ele = document.getElementById(test_id);
if (!ele)
return test_id;
}
return null;
}
function f_trunked(e) {
var row = find_parent(e, 'TR');
var trrow = document.getElementById('tr_' + row.id.substring(3));
trrow['style']['display'] = e.checked ? '' : 'none';
}
function read_write_sel(sel_node, def) {
var result = [];
var elist = sel_node.querySelectorAll('option');
for (var e in elist) {
var ele = elist[e];
if (def) {
if (!def[sel_node.name])
return;
var options = def[sel_node.name].split(',');
var opts = {};
for (var o in options)
opts[options[o]] = 1;
if (ele.value in opts)
ele.selected = true;
else
ele.selected = false;
} else {
if (ele.selected)
result.push(ele.value);
}
}
if (!def)
return result.join();
}
function read_write(elist, def) {
var result = {};
for (var e in elist) {
var ele = elist[e];
if (ele.nodeName == 'INPUT') {
if (ele.type == 'text')
if (def)
ele.value = def[ele.name];
else
result[ele.name] = ele.value;
else if (ele.type == 'checkbox')
if (def)
ele.checked = def[ele.name];
else
result[ele.name] = ele.checked;
} else if (ele.nodeName == 'SELECT') {
if (def)
read_write_sel(ele, def);
else
result[ele.name] = read_write_sel(ele, def);
}
}
if (!def)
return result;
}
function rollup_row(which, row, def) {
var elements = Array.from(row.querySelectorAll('input,select'));
if (which == 'ch') {
var trrow = document.getElementById('tr_' + row.id.substring(3));
var trtable = trrow.querySelector('table.trtable');
elements = elements.concat(Array.from(trtable.querySelectorAll('input,select')));
if (def)
trrow.style['display'] = def['trunked'] ? '' : 'none';
} else if (which == 'rx') {
var advrow = document.getElementById('rx_2');
elements = elements.concat(Array.from(advrow.querySelectorAll('input,select')));
}
var result = read_write(elements, def);
if (which == 'ch') {
var tgtable = trrow.querySelector('table.tgtable');
var tgrow = trrow.querySelector('tr.tgrow');
if (def) {
for (var k in def['tgids']) {
var val = def['tgids'][k];
var newrow = amend_d(tgrow, tgtable, 'new');
var inputs = newrow.querySelectorAll('input');
read_write(inputs, {
'tg_id': k,
'tg_tag': val
});
}
} else {
var tgids = {};
var rows = tgtable.querySelectorAll('tr.tgrow');
for (var i = 0; i < rows.length; i++) {
if (rows[i].id == null || rows[i].id.substring(0, 3) != 'tg_')
continue;
var inputs = rows[i].querySelectorAll('input');
var vals = read_write(inputs, null);
tgids[vals['tg_id']] = vals['tg_tag'];
}
result['tgids'] = tgids;
}
}
if (!def)
return result;
}
function rollup(which, def) {
var result = [];
var mytbl = document.getElementById(which + 'table');
var elements = mytbl.querySelectorAll('.dynrow');
for (var e in elements) {
var row = elements[e];
if (row.id != null && row.id.substring(0, 3) == 'id_')
result.push(rollup_row(which, row, def));
}
if (!def)
return result;
}
function rollup_rx_rows(def) {
return rollup_row('rx', document.getElementById('rx_1'), def);
}
function f_save() {
var name = document.getElementById('config_name');
if (!name.value) {
alert('Name is required');
name.focus();
return;
}
if (name.value == 'New Configuration') {
alert("'" + name.value + "' is a reserved name, please retry");
name.value = '';
name.focus();
return;
}
var cfg = {
'devices': rollup('dev', null),
'channels': rollup('ch', null),
'backend-rx': rollup_rx_rows(null)
};
cfg = edit_l(cfg, false);
var request = {
'name': name.value,
'value': cfg
};
send_command('config-save', request);
f_list();
}
function f_list() {
var inp = document.getElementById('include_tsv');
send_command('config-list', inp.checked ? 'tsv' : '');
}
function f_start() {
var sel = document.getElementById('config_select');
if (!sel)
return;
var val = read_write_sel(sel, null);
if (!val || val == 'New Configuration') {
alert('You must select a valid configuration to start');
return;
}
if (val.indexOf('[TSV]') >= 0) {
alert('TSV files not supported. First, invoke "Edit"; inspect the resulting configuration; then click "Save".');
return;
}
send_command('rx-start', val);
}
function f_stop() {
send_command('rx-stop', '');
}
function f_load() {
var sel = document.getElementById('config_select');
if (!sel)
return;
var val = read_write_sel(sel, null);
if (!val) {
alert('You must select a configuration to edit');
return;
}
if (val == 'New Configuration') {
open_editor();
} else {
send_command('config-load', val);
var ele = document.getElementById('config_name');
ele.value = val;
}
}
function show_advanced(o) {
var tbl = find_parent(o, 'TABLE');
var row = tbl.querySelector('.advrow');
toggle_show_hide(o, row);
}
function toggle_show_hide(o, ele) {
if (o.value == 'Show') {
o.value = 'Hide';
ele.style['display'] = '';
} else {
o.value = 'Show';
ele.style['display'] = 'none';
}
}
function f_tags(o) {
var mydiv = find_parent(o, 'DIV');
var tbl = mydiv.querySelector('.tgtable');
toggle_show_hide(o, tbl);
}
// communicate w/ HTTP server functions
function http_req_cb() {
req_cb_count += 1;
s = http_req.readyState;
if (s != 4) {
nfinal_count += 1;
return;
}
if (http_req.status != 200) {
n200_count += 1;
return;
}
r200_count += 1;
dispatch_commands(http_req.responseText);
}
function send_command(command, data) {
var d = {
'command': command,
'data': data
};
send(d);
}
function send(d) {
request_count += 1;
if (send_queue.length >= SEND_QLIMIT) {
send_qfull += 1;
send_queue.unshift();
}
send_queue.push(d);
send_process();
}
function send_process() {
s = http_req.readyState;
if (s != 0 && s != 4) {
send_busy += 1;
return;
}
http_req.open('POST', '/');
http_req.onreadystatechange = http_req_cb;
http_req.setRequestHeader('Content-type', 'application/json');
cmd = JSON.stringify(send_queue);
send_queue = [];
http_req.send(cmd);
}
function save_tsv(command, data, file) {
var d = {
'command': command,
'data': data,
'file': file
};
send(d);
}
// command, data
function reload_tsv(data) { // commands OP25 to reload the tsv talkgroup/source tag data
console.log('sending reload command...');
var command = "reload_tags";
var d = {
'command': command,
'data': data
};
send(d);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,125 @@
<h2 class='nac'>Keyboard Shortcuts</h2>
<p>These keyboard shortcuts are used throughout the UI on any tab and allow available information to be displayed in a variety of ways.</p>
G - Go To<br>
L - Lockout<br>
H - Hold<br>
S - Skip/Scan<br>
V - View (light/dark toggle)<br>
R - RX Screen<br>
J - Home Screen<br>
M - Minify<br>
P - Show / Hide Plots<br>
A - Show / Hide Adjacent Sites<br>
B - Set display text BOLD<br>
N - Set display text NORMAL<br>
1 - Show / Hide Call History<br>
2 - Show / Hide Events<br>
3 - Show / Hide Logs Block<br>
4 - Show / Hide Channel ID Band Plan<br>
0 - Show / Hide Main Display<br><br>
<div align="center"><h2 class='nac'>Home Tab</h2></div>
The Home tab contains:
<h3>Main Display</h3>
<p>
<b>List of systems included in the trunk.tsv file.</b> Each of these may be enabled or disabled. The last time a
TSBK was received and total TSBKs received since OP25 was started is also displayed. Under the Alias column
there can be as many as 3 links shown, TA, SRC, SA, for Talkgroup Alias, Source ID Alias, and Site Alias,
respectively. See the Editors section below.
</p>
<p><b>Plots</b> - Plots are displayed if defined in the config files.</p>
<p>Blocks from the RX Tab may be added to this display using the keyboard shortcuts.</p>
<div align="center"><h2 class='nac'>Config Tab</h2></div>
<p><span class="value">UI Display Mode Toggle:</span> Set the theme to light or dark. Default is dark.</p>
<p><span class="value">System Font Size: </span> The front size of the System Name in the Main Display.</p>
<p><span class="value">Talkgroup Font Size: </span> The font size of the Talkgroup Name in the Main Display.</p>
<p><span class="value">Main Display Font Style (Normal / Bold): </span> System and Talkgroup Name normal or bold selection in the Main Display.</p>
<p><span class="value">Animation Speed:</span> UI animation of transitions between tabs. Set to 0 to turn off.</p>
<p><span class="value">Color Code for Unknown Talkgroups:</span> Talkgroups which do not appear in the talkgroup tag id list will be assigned this color code.</p>
<p><span class="value">Max Display String Length:</span> Talkgroup names will be truncated beyond this number of characters.</p>
<p><span class="value">Show Adjacent Sites on RX Tab:</span> Adjacent Sites will be shown on the RX tab.</p>
<p><span class="value">Show Trailing Zeros on Frequencies:</span> Zeros will be appended so all frequencies appear with 5 characters after the decimal.</p>
<p><span class="value">Use TG Colors on Main Display - System / Talkgroup:</span> When selected, the color code for the talkgroup will be applied to the system and/or talkgroup elements in the Main Display.</p>
<p><span class="value">Show Band Plan on RX Screen: </span> The band plan advertised by the control channel will be displayed on the RX tab for each active system.</p>
<p><span class="value">Exclude Encrypted Calls from Call History: </span> Encrypted calls will be excluded from the Call History log.</p>
<p><span class="value">Show Timeslots in Call History Log: </span> When selected TDMA timeslots will be shown in the Call History Log, “Svc” column. See RX Tab, below.</p>
<p><span class="value">Use SmartColors: </span> SmartColors searches the Talkgroup Tag string for each item in the list and applies the color on a match. Colors defined in the Talkgroup tag config file take priority over SmartColors. Entries in these fields are case-insensitive.</p>
<p><span class="value">UI Colors:</span> colors of the UI elements may be changed as follows:</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Tag Colors Editor - Access the Tag Colors Editor</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Accent 1 and 2 - the “fade” effect behind the Main Display</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Values - Values presented in the Main Display, System Information Table, and elsewhere</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;System / Talkgroup - The color of the System Name text and Talkgroup Tag text when “Use TG in Main Display” options are unchecked.</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Buttons - Button text color (all)</p>
<p><span class="value">Log Events in Browser:</span> Selected events will be logged in the browser. These options do not affect server-side logging. The available options are:</p>
<p><span class="value">Control Channel Events (CC)</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Joins - subscriber joins the talkgroup</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Login / Logout - subscriber logs into or out of the system</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Calls - a voice chanel grant</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Denials - a voice channel request was denied</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Change Frequency (CF) - these events are used to update the Main Display</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;Trunk Update (TU) - these events are used to update Active Frequencies table and system information displays</p>
<p>&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;RX Update (RX) - these events update the plot images, fine tune, and error data (if present, rx.py only)</p>
<p>Some Control Channel Event opcodes are received and displayed by the UI but cannot be logged (e.g. Adjacent Sites or Identifier Update). The last three of these are mostly useful for debugging and troubleshooting and typically should remain off.</p>
<p><span class="value">Number of Rows in Log Tables</span> - The maximum number of rows allowed for each of the Call History, Events, and Error Tracking (if enabled) tables. Default is 2,500. This setting does not apply to the server-side OP25 SQL logging -- only the browser logs.</p>
<p><span class="value">Save and Load Display Settings</span> - Changes made on the Config tab should be saved by clicking Save Display Settings. These saved settings will be applied next time OP25 Web UI is started. Load Display Settings will reload the settings on the server, overwriting the current contents of the Config tab. Changes made with keyboard shortcuts will not persist beyond the session.</p>
<h2 class='nac'>RX Tab</h2>
<p><span class="value">Main Display</span>Display showing active system, talkgroup, frequency, source ID, encryption status.</p>
<p><span class="value">Site Information</span> - Each active system</p>
<p><span class="value">Active Frequency Table</span> - Double click elements in these tables to access the editors.</p>
<p><span class="value">Call History</span> - Logs channel grants as seen on the control channel. Click the Call History Magnifying Glass to pop open a searchable table. FIlter by any column. Export the table as CSV by clicking the CSV icon. The “Svc” column displays timeslot, encrypted status, and the priority when that information is pertinent. Example: “S1 Ø 4” = Slot 1, Encrypted, Pri 4. “XP” in this column means patched talkgroup, or crosspatch.</p>
Events - Logs Control Channel events, and application events as selected in the Config tab. Click the Events Magnifying Glass to pop open a searchable table. FIlter by any column. Export the table as CSV by clicking the CSV icon.</p>
Error Tracking (if enabled in command line option -X): Logs the error tracking data when enabled in the command line used to start OP25. The same filter and export options are available.</p>
Click the triangles to the right of each table to expand, retract and hide that table.</p>
<div align="center"><h2 class='nac'>View tab</h2></div>
<p>Toggle Dark / Light Display</p>
<div align="center"><h2 class='nac'>Popout</h2></div>
<p>Pops open the app in a new window with minimal browser UI.</p>
<div align="center"><h2 class='nac'>About</h2></div>
<p>Well, information about the app is here.</p>
<div align="center"><h2 class='nac'>Talkgroup Editor, Source ID Editor, Site Alias Editor <br> and Colors Editor</h2></div>
<h3>Talkgroup and Source ID Editors</h3>
<p>These editors allow changes and additions to the talkgroup tags tsv file and the source ID tags tsv files. These files are specified in the trunk.tsv configuration file in the “TGID Tags File” field. Both files are supplied in the same field, separated by a comma. For example: “talkgroups.tsv,sources.tsv”</p>
<p>To access the Talkgroup Editor or Source ID Editor, double click on the talkgroup ID, talkgroup tag, source ID, or source ID tag in the Active Frequency Table or the Call History Table. Alternatively, click the TG or SRC link on the Home tab for the desired active system.</p>
<p>The talkgroup and source ID editors have an import and export as CSV or TSV function. The import function accepts a 3 column comma-separated values or tab separated values file:</p>
<p>ID&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;TAG&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;PRI/COLOR</p>
<p>Any columns beyond the third are ignored.</p>
<p>ID is a decimal value.</p>
<p>TAG is an alphanumeric tag.</p>
<p>PRI/COLOR is:</p>
<p>For Talkgroups IDs: a 3 digit decimal value 0 through 999 where the first digit represents the priority and the last two represent the color code (see Colors Editor, below).</p>
<p>For Source IDs: a 2 digit decimal value 0-99 matching the color map (see Color Editor).</p>
<p>The Export function may be used to bring the file out to a text or spreadsheet editor, save, and import back into OP25.</p>
<p>Use the Filter box to search/filter the data.</p>
<p>To create a new entry, complete the required 3 fields and click Add New. The new entry will appear in the table. Click Save to commit or the Red X to Delete.</p>
<p>To Delete an entry, click the red X to the right. Confirm the delete. Click Save to commit.</p>
<p>Click on Help in the editors for information on using wildcard matching.</p>
<h3>Site Alias Editor</h3>
<p>The Site Alias editor allows a friendly name to be supplied for each site in a system. This is currently used in the System Information table on the RX Tab and in the Adjacent Sites table. The Site Alias editor is accessed by clicking on the SA link on the Home tab. The Site Alias editor allows editing of the site names for the active system, or any other system in the file. New lists can be created by clicking Change > Add New…</p>
<h3>Color Editor</h3>
<p>Talkgroups Tags and Source IDs can be assigned a color value 0-99 in the Talkgorup Editor and Source ID Editor. The Colors Editor allows you to change/modify those 100 colors. The Colors Editor is accessed on the Config tab, Tag Colors Editor. The “blink” function can be squarely blamed on Max.</p>
---
<p>Changes made in the editors take a few seconds to apply in the UI. Click Save when finished or the changes will be abandoned. Click Load to reload the saved values and overwrite all edits in the table. Additional information for the editors is available by clicking Help in the editor.</p>

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,70 @@
/* Custom dialog styles */
#popup_title {
font-size: 14px;
font-weight: bold;
text-align: center;
line-height: 1.75em;
color: #FFFFFF;
background: #006699;
border: solid 1px #006699;
border-bottom: solid 1px #006699;
cursor: default;
padding: 0em;
margin: 0em;
}
#popup_container {
font-family: AntipastoRegular, sans-serif;
font-size: 14px;
min-width: 300px; /* Dialog will be no smaller than this */
max-width: 600px; /* Dialog will wrap after this width */
background: #FFFFFF;
border: solid 5px #006699;
color: #000000;
-moz-border-radius: 5px;
-webkit-border-radius: 5px;
border-radius: 5px;
}
#popup_content {
/*background: 16px 16px no-repeat url(images/info.gif);*/
padding: 1em 1.75em;
margin: 0em;
}
/*
#popup_content.alert {
background-image: url(images/info.gif);
}
#popup_content.confirm {
background-image: url(images/important.gif);
}
#popup_content.prompt {
background-image: url(images/help.gif);
}
*/
#popup_message {
/*padding-left: 10px;*/
margin:0px auto;
}
#popup_panel {
text-align: center;
margin: 1em 0em 0em 1em;
}
#popup_prompt {
margin: .5em 0em;
}
#popup_container INPUT[type='button'] {
width: 100px;
height: 30px;
border: outset 2px #006699;
color: #FFFFFF;
background: #006699;
}

View File

@ -0,0 +1,268 @@
// jQuery Alert Dialogs Plugin
//
// Version 2.0
//
// Cory S.N. LaViska
// A Beautiful Site (http://abeautifulsite.net/)
// 14 May 2009
//
// Visit http://abeautifulsite.net/notebook/87 for more information
//
// Usage:
// jLoad( message, [title, callback] )
// jAlert( message, [title, callback] )
// jConfirm( message, [title, callback] )
// jPrompt( message, [value, title, callback] )
//
// History:
//
// 1.00 - Released (29 December 2008)
// 1.01 - Fixed bug where unbinding would destroy all resize events
// 2.0 - Released (01 April 2015)
//
// License:
//
// This plugin is dual-licensed under the GNU General Public License and the MIT License and
// is copyright 2008 A Beautiful Site, LLC.
//
(function($) {
$.alerts = {
// These properties can be read/written by accessing $.alerts.propertyName from your scripts at any time
verticalOffset: -75, // vertical offset of the dialog from center screen, in pixels
horizontalOffset: 0, // horizontal offset of the dialog from center screen, in pixels/
repositionOnResize: true, // re-centers the dialog on window resize
overlayOpacity: .01, // transparency level of overlay
overlayColor: '#FFF', // base color of overlay
draggable: true, // make the dialogs draggable (requires UI Draggables plugin)
okButton: '&nbsp;OK&nbsp;', // text for the OK button
cancelButton: '&nbsp;Cancel&nbsp;', // text for the Cancel button
dialogClass: null, // if specified, this class will be applied to all dialogs
// Public methods
alert: function(message, title, callback) {
if( title == null ) title = 'Alert';
$.alerts._show(title, message, null, 'alert', function(result) {
if( callback ) callback(result);
});
},
confirm: function(message, title, callback) {
if( title == null ) title = 'Confirm';
$.alerts._show(title, message, null, 'confirm', function(result) {
if( callback ) callback(result);
});
},
prompt: function(message, value, title, callback) {
if( title == null ) title = 'Prompt';
$.alerts._show(title, message, value, 'prompt', function(result) {
if( callback ) callback(result);
});
},
load: function(message, title, callback) {
if( title == null ) title = 'Load';
$.alerts._show(title, message, null, 'load', function(result) {
if( callback ) callback(result);
});
},
// Private methods
_show: function(title, msg, value, type, callback) {
$.alerts._hide();
$.alerts._overlay('show');
$("BODY").append(
'<div id="popup_container">' +
'<h1 id="popup_title"></h1>' +
'<div id="popup_content">' +
'<div id="popup_message"></div>' +
'</div>' +
'</div>');
if( $.alerts.dialogClass ) $("#popup_container").addClass($.alerts.dialogClass);
// IE6 Fix
//var pos = ($.browser.msie && parseInt($.browser.version) <= 6 ) ? 'absolute' : 'fixed';
var pos = 'fixed';
$("#popup_container").css({
position: pos,
zIndex: 99999,
padding: 0,
margin: 0
});
$("#popup_title").text(title);
$("#popup_content").addClass(type);
$("#popup_message").text(msg);
$("#popup_message").html( $("#popup_message").text().replace(/\n/g, '<br />') );
$("#popup_container").css({
minWidth: $("#popup_container").outerWidth(),
maxWidth: $("#popup_container").outerWidth()
});
$.alerts._reposition();
$.alerts._maintainPosition(true);
switch( type ) {
case 'alert':
$("#popup_message").after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /></div>');
$("#popup_ok").click( function() {
$.alerts._hide();
callback(true);
});
$("#popup_ok").focus().keypress( function(e) {
if( e.keyCode == 13 || e.keyCode == 27 ) $("#popup_ok").trigger('click');
});
break;
case 'confirm':
$("#popup_message").after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /> <input type="button" value="' + $.alerts.cancelButton + '" id="popup_cancel" /></div>');
$("#popup_ok").click( function() {
$.alerts._hide();
if( callback ) callback(true);
});
$("#popup_cancel").click( function() {
$.alerts._hide();
if( callback ) callback(false);
});
$("#popup_ok").focus();
$("#popup_ok, #popup_cancel").keypress( function(e) {
if( e.keyCode == 13 ) $("#popup_ok").trigger('click');
if( e.keyCode == 27 ) $("#popup_cancel").trigger('click');
});
break;
case 'prompt':
$("#popup_message").append('<br /><input type="text" size="30" id="popup_prompt" />').after('<div id="popup_panel"><input type="button" value="' + $.alerts.okButton + '" id="popup_ok" /> <input type="button" value="' + $.alerts.cancelButton + '" id="popup_cancel" /></div>');
$("#popup_prompt").width( $("#popup_message").width() );
$("#popup_ok").click( function() {
var val = $("#popup_prompt").val();
$.alerts._hide();
if( callback ) callback( val );
});
$("#popup_cancel").click( function() {
$.alerts._hide();
if( callback ) callback( null );
});
$("#popup_prompt, #popup_ok, #popup_cancel").keypress( function(e) {
if( e.keyCode == 13 ) $("#popup_ok").trigger('click');
if( e.keyCode == 27 ) $("#popup_cancel").trigger('click');
});
if( value ) $("#popup_prompt").val(value);
$("#popup_prompt").focus().select();
break;
case 'load':
$("#popup_message").after('<div id="popup_panel"></div>');
$("#popup_ok").click( function() {
$.alerts._hide();
callback(true);
});
$("#popup_ok").focus().keypress( function(e) {
if( e.keyCode == 13 || e.keyCode == 27 ) $("#popup_ok").trigger('click');
});
break;
}
/*
// Make draggable requires jQuery UI draggables
if( $.alerts.draggable ) {
try {
$("#popup_container").draggable({ handle: $("#popup_title") });
$("#popup_title").css({ cursor: 'move' });
} catch(e) { }
}
*/
},
_hide: function() {
$("#popup_container").remove();
$.alerts._overlay('hide');
$.alerts._maintainPosition(false);
},
_overlay: function(status) {
switch( status ) {
case 'show':
$.alerts._overlay('hide');
$("BODY").append('<div id="popup_overlay"></div>');
$("#popup_overlay").css({
position: 'absolute',
zIndex: 99998,
top: '0px',
left: '0px',
width: '100%',
height: $(document).height(),
background: $.alerts.overlayColor,
opacity: $.alerts.overlayOpacity
});
break;
case 'hide':
$("#popup_overlay").remove();
break;
}
},
_reposition: function() {
var top = (($(window).height() / 2) - ($("#popup_container").outerHeight() / 2)) + $.alerts.verticalOffset;
var left = (($(window).width() / 2) - ($("#popup_container").outerWidth() / 2)) + $.alerts.horizontalOffset;
if( top < 0 ) top = 0;
if( left < 0 ) left = 0;
// IE6 fix
//f( $.browser.msie && parseInt($.browser.version) <= 6 ) top = top + $(window).scrollTop();
$("#popup_container").css({
top: top + 'px',
left: left + 'px'
});
$("#popup_overlay").height( $(document).height() );
},
_maintainPosition: function(status) {
if( $.alerts.repositionOnResize ) {
switch(status) {
case true:
$(window).bind('resize', $.alerts._reposition);
break;
case false:
$(window).unbind('resize', $.alerts._reposition);
break;
}
}
}
}
// Shortuct functions
jAlert = function(message, title, callback) {
$.alerts.alert(message, title, callback);
}
jConfirm = function(message, title, callback) {
$.alerts.confirm(message, title, callback);
};
jPrompt = function(message, value, title, callback) {
$.alerts.prompt(message, value, title, callback);
};
jLoad = function(message, title, callback) {
$.alerts.load(message, title, callback);
}
})(jQuery);
var HideAlert = function() {
$.alerts._hide();
}

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,507 @@
/***
Spectrum Colorpicker v1.8.1
https://github.com/bgrins/spectrum
Author: Brian Grinstead
License: MIT
***/
.sp-container {
position:absolute;
top:0;
left:0;
display:inline-block;
*display: inline;
*zoom: 1;
/* https://github.com/bgrins/spectrum/issues/40 */
z-index: 9999994;
overflow: hidden;
}
.sp-container.sp-flat {
position: relative;
}
/* Fix for * { box-sizing: border-box; } */
.sp-container,
.sp-container * {
-webkit-box-sizing: content-box;
-moz-box-sizing: content-box;
box-sizing: content-box;
}
/* http://ansciath.tumblr.com/post/7347495869/css-aspect-ratio */
.sp-top {
position:relative;
width: 100%;
display:inline-block;
}
.sp-top-inner {
position:absolute;
top:0;
left:0;
bottom:0;
right:0;
}
.sp-color {
position: absolute;
top:0;
left:0;
bottom:0;
right:20%;
}
.sp-hue {
position: absolute;
top:0;
right:0;
bottom:0;
left:84%;
height: 100%;
}
.sp-clear-enabled .sp-hue {
top:33px;
height: 77.5%;
}
.sp-fill {
padding-top: 80%;
}
.sp-sat, .sp-val {
position: absolute;
top:0;
left:0;
right:0;
bottom:0;
}
.sp-alpha-enabled .sp-top {
margin-bottom: 18px;
}
.sp-alpha-enabled .sp-alpha {
display: block;
}
.sp-alpha-handle {
position:absolute;
top:-4px;
bottom: -4px;
width: 6px;
left: 50%;
cursor: pointer;
border: 1px solid black;
background: white;
opacity: .8;
}
.sp-alpha {
display: none;
position: absolute;
bottom: -14px;
right: 0;
left: 0;
height: 8px;
}
.sp-alpha-inner {
border: solid 1px #333;
}
.sp-clear {
display: none;
}
.sp-clear.sp-clear-display {
background-position: center;
}
.sp-clear-enabled .sp-clear {
display: block;
position:absolute;
top:0px;
right:0;
bottom:0;
left:84%;
height: 28px;
}
/* Don't allow text selection */
.sp-container, .sp-replacer, .sp-preview, .sp-dragger, .sp-slider, .sp-alpha, .sp-clear, .sp-alpha-handle, .sp-container.sp-dragging .sp-input, .sp-container button {
-webkit-user-select:none;
-moz-user-select: -moz-none;
-o-user-select:none;
user-select: none;
}
.sp-container.sp-input-disabled .sp-input-container {
display: none;
}
.sp-container.sp-buttons-disabled .sp-button-container {
display: none;
}
.sp-container.sp-palette-buttons-disabled .sp-palette-button-container {
display: none;
}
.sp-palette-only .sp-picker-container {
display: none;
}
.sp-palette-disabled .sp-palette-container {
display: none;
}
.sp-initial-disabled .sp-initial {
display: none;
}
/* Gradients for hue, saturation and value instead of images. Not pretty... but it works */
.sp-sat {
background-image: -webkit-gradient(linear, 0 0, 100% 0, from(#FFF), to(rgba(204, 154, 129, 0)));
background-image: -webkit-linear-gradient(left, #FFF, rgba(204, 154, 129, 0));
background-image: -moz-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
background-image: -o-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
background-image: -ms-linear-gradient(left, #fff, rgba(204, 154, 129, 0));
background-image: linear-gradient(to right, #fff, rgba(204, 154, 129, 0));
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr=#FFFFFFFF, endColorstr=#00CC9A81)";
filter : progid:DXImageTransform.Microsoft.gradient(GradientType = 1, startColorstr='#FFFFFFFF', endColorstr='#00CC9A81');
}
.sp-val {
background-image: -webkit-gradient(linear, 0 100%, 0 0, from(#000000), to(rgba(204, 154, 129, 0)));
background-image: -webkit-linear-gradient(bottom, #000000, rgba(204, 154, 129, 0));
background-image: -moz-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
background-image: -o-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
background-image: -ms-linear-gradient(bottom, #000, rgba(204, 154, 129, 0));
background-image: linear-gradient(to top, #000, rgba(204, 154, 129, 0));
-ms-filter: "progid:DXImageTransform.Microsoft.gradient(startColorstr=#00CC9A81, endColorstr=#FF000000)";
filter : progid:DXImageTransform.Microsoft.gradient(startColorstr='#00CC9A81', endColorstr='#FF000000');
}
.sp-hue {
background: -moz-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
background: -ms-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
background: -o-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
background: -webkit-gradient(linear, left top, left bottom, from(#ff0000), color-stop(0.17, #ffff00), color-stop(0.33, #00ff00), color-stop(0.5, #00ffff), color-stop(0.67, #0000ff), color-stop(0.83, #ff00ff), to(#ff0000));
background: -webkit-linear-gradient(top, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
background: linear-gradient(to bottom, #ff0000 0%, #ffff00 17%, #00ff00 33%, #00ffff 50%, #0000ff 67%, #ff00ff 83%, #ff0000 100%);
}
/* IE filters do not support multiple color stops.
Generate 6 divs, line them up, and do two color gradients for each.
Yes, really.
*/
.sp-1 {
height:17%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff0000', endColorstr='#ffff00');
}
.sp-2 {
height:16%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ffff00', endColorstr='#00ff00');
}
.sp-3 {
height:17%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ff00', endColorstr='#00ffff');
}
.sp-4 {
height:17%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#00ffff', endColorstr='#0000ff');
}
.sp-5 {
height:16%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#0000ff', endColorstr='#ff00ff');
}
.sp-6 {
height:17%;
filter: progid:DXImageTransform.Microsoft.gradient(startColorstr='#ff00ff', endColorstr='#ff0000');
}
.sp-hidden {
display: none !important;
}
/* Clearfix hack */
.sp-cf:before, .sp-cf:after { content: ""; display: table; }
.sp-cf:after { clear: both; }
.sp-cf { *zoom: 1; }
/* Mobile devices, make hue slider bigger so it is easier to slide */
@media (max-device-width: 480px) {
.sp-color { right: 40%; }
.sp-hue { left: 63%; }
.sp-fill { padding-top: 60%; }
}
.sp-dragger {
border-radius: 5px;
height: 5px;
width: 5px;
border: 1px solid #fff;
background: #000;
cursor: pointer;
position:absolute;
top:0;
left: 0;
}
.sp-slider {
position: absolute;
top:0;
cursor:pointer;
height: 3px;
left: -1px;
right: -1px;
border: 1px solid #000;
background: white;
opacity: .8;
}
/*
Theme authors:
Here are the basic themeable display options (colors, fonts, global widths).
See http://bgrins.github.io/spectrum/themes/ for instructions.
*/
.sp-container {
border-radius: 0;
background-color: #ECECEC;
border: solid 1px #f0c49B;
padding: 0;
}
.sp-container, .sp-container button, .sp-container input, .sp-color, .sp-hue, .sp-clear {
font: normal 12px "Lucida Grande", "Lucida Sans Unicode", "Lucida Sans", Geneva, Verdana, sans-serif;
-webkit-box-sizing: border-box;
-moz-box-sizing: border-box;
-ms-box-sizing: border-box;
box-sizing: border-box;
}
.sp-top {
margin-bottom: 3px;
}
.sp-color, .sp-hue, .sp-clear {
border: solid 1px #666;
}
/* Input */
.sp-input-container {
float:right;
width: 100px;
margin-bottom: 4px;
}
.sp-initial-disabled .sp-input-container {
width: 100%;
}
.sp-input {
font-size: 12px !important;
border: 1px inset;
padding: 4px 5px;
margin: 0;
width: 100%;
background:transparent;
border-radius: 3px;
color: #222;
}
.sp-input:focus {
border: 1px solid orange;
}
.sp-input.sp-validation-error {
border: 1px solid red;
background: #fdd;
}
.sp-picker-container , .sp-palette-container {
float:left;
position: relative;
padding: 10px;
padding-bottom: 300px;
margin-bottom: -290px;
}
.sp-picker-container {
width: 172px;
border-left: solid 1px #fff;
}
/* Palettes */
.sp-palette-container {
border-right: solid 1px #ccc;
}
.sp-palette-only .sp-palette-container {
border: 0;
}
.sp-palette .sp-thumb-el {
display: block;
position:relative;
float:left;
width: 24px;
height: 15px;
margin: 3px;
cursor: pointer;
border:solid 2px transparent;
}
.sp-palette .sp-thumb-el:hover, .sp-palette .sp-thumb-el.sp-thumb-active {
border-color: orange;
}
.sp-thumb-el {
position:relative;
}
/* Initial */
.sp-initial {
float: left;
border: solid 1px #333;
}
.sp-initial span {
width: 30px;
height: 25px;
border:none;
display:block;
float:left;
margin:0;
}
.sp-initial .sp-clear-display {
background-position: center;
}
/* Buttons */
.sp-palette-button-container,
.sp-button-container {
float: right;
}
/* Replacer (the little preview div that shows up instead of the <input>) */
.sp-replacer {
margin:0;
overflow:hidden;
cursor:pointer;
padding: 4px;
display:inline-block;
*zoom: 1;
*display: inline;
border: solid 1px #91765d;
background: #eee;
color: #333;
vertical-align: middle;
}
.sp-replacer:hover, .sp-replacer.sp-active {
border-color: #F0C49B;
color: #111;
}
.sp-replacer.sp-disabled {
cursor:default;
border-color: silver;
color: silver;
}
.sp-dd {
padding: 2px 0;
height: 16px;
line-height: 16px;
float:left;
font-size:10px;
}
.sp-preview {
position:relative;
width:25px;
height: 20px;
border: solid 1px #222;
margin-right: 5px;
float:left;
z-index: 0;
}
.sp-palette {
*width: 220px;
max-width: 220px;
}
.sp-palette .sp-thumb-el {
width:16px;
height: 16px;
margin:2px 1px;
border: solid 1px #d0d0d0;
}
.sp-container {
padding-bottom:0;
}
/* Buttons: http://hellohappy.org/css3-buttons/ */
.sp-container button {
background-color: #eeeeee;
background-image: -webkit-linear-gradient(top, #eeeeee, #cccccc);
background-image: -moz-linear-gradient(top, #eeeeee, #cccccc);
background-image: -ms-linear-gradient(top, #eeeeee, #cccccc);
background-image: -o-linear-gradient(top, #eeeeee, #cccccc);
background-image: linear-gradient(to bottom, #eeeeee, #cccccc);
border: 1px solid #ccc;
border-bottom: 1px solid #bbb;
border-radius: 3px;
color: #333;
font-size: 14px;
line-height: 1;
padding: 5px 4px;
text-align: center;
text-shadow: 0 1px 0 #eee;
vertical-align: middle;
}
.sp-container button:hover {
background-color: #dddddd;
background-image: -webkit-linear-gradient(top, #dddddd, #bbbbbb);
background-image: -moz-linear-gradient(top, #dddddd, #bbbbbb);
background-image: -ms-linear-gradient(top, #dddddd, #bbbbbb);
background-image: -o-linear-gradient(top, #dddddd, #bbbbbb);
background-image: linear-gradient(to bottom, #dddddd, #bbbbbb);
border: 1px solid #bbb;
border-bottom: 1px solid #999;
cursor: pointer;
text-shadow: 0 1px 0 #ddd;
}
.sp-container button:active {
border: 1px solid #aaa;
border-bottom: 1px solid #888;
-webkit-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-moz-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-ms-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
-o-box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
box-shadow: inset 0 0 5px 2px #aaaaaa, 0 1px 0 0 #eeeeee;
}
.sp-cancel {
font-size: 11px;
color: #d93f3f !important;
margin:0;
padding:2px;
margin-right: 5px;
vertical-align: middle;
text-decoration:none;
}
.sp-cancel:hover {
color: #d93f3f !important;
text-decoration: underline;
}
.sp-palette span:hover, .sp-palette span.sp-thumb-active {
border-color: #000;
}
.sp-preview, .sp-alpha, .sp-thumb-el {
position:relative;
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAwAAAAMCAIAAADZF8uwAAAAGUlEQVQYV2M4gwH+YwCGIasIUwhT25BVBADtzYNYrHvv4gAAAABJRU5ErkJggg==);
}
.sp-preview-inner, .sp-alpha-inner, .sp-thumb-inner {
display:block;
position:absolute;
top:0;left:0;bottom:0;right:0;
}
.sp-palette .sp-thumb-inner {
background-position: 50% 50%;
background-repeat: no-repeat;
}
.sp-palette .sp-thumb-light.sp-thumb-active .sp-thumb-inner {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAGXRFWHRTb2Z0d2FyZQBBZG9iZSBJbWFnZVJlYWR5ccllPAAAAIVJREFUeNpiYBhsgJFMffxAXABlN5JruT4Q3wfi/0DsT64h8UD8HmpIPCWG/KemIfOJCUB+Aoacx6EGBZyHBqI+WsDCwuQ9mhxeg2A210Ntfo8klk9sOMijaURm7yc1UP2RNCMbKE9ODK1HM6iegYLkfx8pligC9lCD7KmRof0ZhjQACDAAceovrtpVBRkAAAAASUVORK5CYII=);
}
.sp-palette .sp-thumb-dark.sp-thumb-active .sp-thumb-inner {
background-image: url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABIAAAASCAYAAABWzo5XAAAAAXNSR0IArs4c6QAAAARnQU1BAACxjwv8YQUAAAAJcEhZcwAADsMAAA7DAcdvqGQAAAAadEVYdFNvZnR3YXJlAFBhaW50Lk5FVCB2My41LjEwMPRyoQAAAMdJREFUOE+tkgsNwzAMRMugEAahEAahEAZhEAqlEAZhEAohEAYh81X2dIm8fKpEspLGvudPOsUYpxE2BIJCroJmEW9qJ+MKaBFhEMNabSy9oIcIPwrB+afvAUFoK4H0tMaQ3XtlrggDhOVVMuT4E5MMG0FBbCEYzjYT7OxLEvIHQLY2zWwQ3D+9luyOQTfKDiFD3iUIfPk8VqrKjgAiSfGFPecrg6HN6m/iBcwiDAo7WiBeawa+Kwh7tZoSCGLMqwlSAzVDhoK+6vH4G0P5wdkAAAAASUVORK5CYII=);
}
.sp-clear-display {
background-repeat:no-repeat;
background-position: center;
background-image: url(data:image/gif;base64,R0lGODlhFAAUAPcAAAAAAJmZmZ2dnZ6enqKioqOjo6SkpKWlpaampqenp6ioqKmpqaqqqqurq/Hx8fLy8vT09PX19ff39/j4+Pn5+fr6+vv7+wAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAAACH5BAEAAP8ALAAAAAAUABQAAAihAP9FoPCvoMGDBy08+EdhQAIJCCMybCDAAYUEARBAlFiQQoMABQhKUJBxY0SPICEYHBnggEmDKAuoPMjS5cGYMxHW3IiT478JJA8M/CjTZ0GgLRekNGpwAsYABHIypcAgQMsITDtWJYBR6NSqMico9cqR6tKfY7GeBCuVwlipDNmefAtTrkSzB1RaIAoXodsABiZAEFB06gIBWC1mLVgBa0AAOw==);
}

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,112 @@
<!--
Copyright 2017, 2018 Max H. Parke KA1RBI
Copyright 2021 Michael Rose
This file is part of OP25
OP25 is free software; you can redistribute it and/or modify it
under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 3, or (at your option)
any later version.
OP25 is distributed in the hope that it will be useful, but WITHOUT
ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public
License for more details.
You should have received a copy of the GNU General Public License
along with OP25; see the file COPYING. If not, write to the Free
Software Foundation, Inc., 51 Franklin Street, Boston, MA
02110-1301, USA.
-->
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>OP25 - Edit TSV</title>
<script src="jquery.js"></script>
<script src="editor.js"></script>
<script src="main.js"></script>
<script src="config.js"></script>
<script src='spectrum.js'></script>
<link rel='stylesheet' href='spectrum.css' />
<link rel="stylesheet" type="text/css" id="style" href="main.css">
<script src="jquery.alerts.js"></script>
</head>
<body onload="javascript:tsv_onload();">
<a href="#" name="top"></a>
<div class="tsv-controls">
<!-- <table style="width: 705px; border-collapse: collapse; border: 0px solid var(~~bg-color);"> -->
<table class="tsv">
<tr colspan="2">
<td>
<div id="title" class="nac" style="font-weight: normal;">TSV Editing - OP25</div>
</td>
<td>
<p align="right"><a href="#" onclick="window.close();" style="text-decoration: none;" title="Close">&#x274C;</a></p>
</td>
</tr>
<tr>
<td>
<button onclick="this.blur(); begin();" id="btnLoad" title="Load from Server" class="btn">Load Talkgroups</button>&nbsp;&nbsp;
<button onclick="this.blur(); saveTable();"id="btnSave1" class="saveButton btn" title="Save to Server">Save Talkgroups</button>&nbsp;&nbsp;
<button onclick="this.blur(); dispImport();" class="importExport btn" title="Import TSV or CSV">Import</button>&nbsp;&nbsp;
<button onclick="tsv_csv();" class="importExport btn" title="Export as CSV">Export</button>
</td>
<td align='right'>
<span class="label">Status: </span>
<span id="message" class="value">Ready</span>
<img src="loading.gif" style="height: 15px;" id="loading">
</td>
</tr>
</table>
<br>
<input type="text" id="searchInput" style="width: 643px;" onkeyup="searchTsvTable()" placeholder="Filter" title="Search">
<div id="csv-upload" style="display: none;">
<table class=editor><th colspan="2">Import Data</th>
<tr><td>
<span class="label"> Select a CSV or TSV file to import. <br><br>
<input type="file" id="csvfile" name="filename">&nbsp;&nbsp;
<!-- <button id="importnow" onclick="this.blur(); importNow();">Import Now</button> -->
</td>
<td style="width: 100px; text-align: center;">
<button onclick="document.getElementById('csvfile').value='';" style="width: 80px;"> Reset </button><br>
<button onclick="this.blur(); hideImport();" style="width: 80px;"> Cancel </button>
</td>
</tr>
</table>
<br><br>
</div>
</div>
<div id="save-div">
<br>&nbsp;&nbsp;
<!-- <button onclick="saveTable();"id="btnSave" class="saveButton">Save Talkgroups</button>&nbsp;&nbsp;<br>&nbsp;&nbsp; -->
<!-- <button onclick="window.location.href='#top;'"id="btnSave" class="saveButton">Top</button>&nbsp;&nbsp;<br>&nbsp; -->
</div>
<div id="main"></div>
<!-- Main Content Area -->
<div class="footer">
&nbsp;<br><button onclick="saveTable();"id="btnSave2" class="saveButton">Save Talkgroups</button>
&nbsp;
&nbsp;
<button class="btn" onclick="up();">Go to Top</button>&nbsp;&nbsp;&nbsp;
<button class="importExport btn" onclick="tsv_csv();">Export as CSV</button>&nbsp;&nbsp;&nbsp;
<a href="tsv-edit.html?mode=color&css=dark" target="_blank"><button id="btnColorEditor" class="btn" onclick="this.blur();">Colors Editor</button></a> &nbsp;&nbsp;&nbsp;
<button onclick="this.blur(); help();" class="btnHelp btn">Help</button>&nbsp;&nbsp;
<button class="btn" onclick="window.close();">Close</button>
<br>
</div>
<div style="display: none;"> <!-- placeholder for the color values -->
<span id="loadSettings"></span>
<input type="color" class="accColor" id="acc1"></input>
<input type="color" class="accColor" id="acc2"></input>
<input type="color" class="valColor" id="valColor">
<input type="color" class="sysColor" id="sysColor"></input>
<input type="color" class="btnColor" id="btnColor"></input>
</div>
</body>
</html>

View File

@ -0,0 +1,66 @@
<div id="editor-help">
<table class="tsv">
<tr colspan="2">
<td>
<div id="title" class="nac" style="font-weight: normal;">TSV Editor Help</div>
</td>
<td>
<p align="right"><a href="#" onclick="closeHelp();" style="text-decoration: none;" title="Close Help">&#x274C;</a>&nbsp;&nbsp;</p>
</td>
</tr>
</table>
Hint: Navigate to the TSV entry by double-clicking on the entry in the Call History table or the Active Frequency table. The script cannot (currently) navigate to range values.
<h3>Saving Data</h3>
After editing, click Save Talkgroups or Save Source IDs. The TSV file will be written to the server, and the Reload TSV command will be sent automatically to OP25.<br><br>
Force TSV Reload: <button onclick="this.blur(); command_reload_tsv(nac);" id="btnReload" title="Send Relaod TSV Command to Server">OP25 Reload IDs</button>
<br><br><span class="red_value">Important: </span>After creating a new entry, click Save. After deleting an entry or multiple enteries, click Save. If not, the changes will be abandoned.
<br>
<h3>Creating and Deleting Enteries</h3>
<h3>Talkgroup IDs</h3>
<b>Talkgroup ID Field</b> <br> Can be one of either 1) specific value 2) range of values 3) wildcard values:<br><br>
<b>Specific Value: 123456</b> <br> Matches ID 123456 <br><br>
<b>Range of Value: 123* </b> <br> Match any ID starting with 123 <br><br>
<b>Range of Value: 123... </b> <br> Match 123456 but not 1234567 (length is checked) (dot dot dot ) <br>
<b>Range of Value: 1234-1250 </b><br> Matches the range (inclusive of first and last)<br><br>
<h3>Priority / Color Field - Talkgroups</h3>
A three value 0 through 999 where the first digit represents priority and the last 2 digits represent the CSS color code. (See Config tab, Show Colors button in the OP25 ui.)<br>
<br>Example: 502: Priority 5, color 02 - 914:Priority 9, Color 12
Higher priority value (9) = greatest priority.<br><br>
<button onclick="this.blur(); displayColors();">Show Colors</button> &nbsp;&nbsp; Display color codes for use in TSV files.
<h3>Source IDs</h3>
<b>Source ID Field</b> <br> Can be one of either 1) specific value 2) range of values 3) wildcard values:<br><br>
<b>Specific Value: 123456</b> <br> Matches ID 123456 <br>
<b>Range of Value: 123* </b> <br> Match any ID starting with 123 <br>
<b>Range of Value: 123... </b> <br> Match 123456 but not 1234567 (length is checked) (dot dot dot ) <br>
<b>Range of Value: 1234-1250 </b> <br> Matches the range (inclusive of first and last)<br>
<h3>Priority / Color Field - Sources</h3>
A single value 0 through 99 corresponding to the CSS colors. (See Config tab, Show Colors button in the OP25 ui.)
</div>
<br><br><br><br><br><br><br>