diff --git a/mopidy_pummeluff/__init__.py b/mopidy_pummeluff/__init__.py
index 09ce374..5dd1932 100644
--- a/mopidy_pummeluff/__init__.py
+++ b/mopidy_pummeluff/__init__.py
@@ -7,7 +7,8 @@
import mopidy
from .frontend import PummeluffFrontend
-from .web import LatestHandler, RegistryHandler, RegisterHandler, ActionClassesHandler
+from .web import LatestHandler, RegistryHandler, RegisterHandler, UnregisterHandler, \
+ ActionClassesHandler
def app_factory(config, core): # pylint: disable=unused-argument
@@ -21,10 +22,11 @@ def app_factory(config, core): # pylint: disable=unused-argument
:rtype: list
'''
return [
- ('/latest/', LatestHandler, {'core': core}),
- ('/registry/', RegistryHandler, {'core': core}),
- ('/register/', RegisterHandler, {'core': core}),
- ('/action-classes/', ActionClassesHandler, {'core': core}),
+ ('/latest/', LatestHandler),
+ ('/registry/', RegistryHandler),
+ ('/register/', RegisterHandler),
+ ('/unregister/', UnregisterHandler),
+ ('/action-classes/', ActionClassesHandler),
]
diff --git a/mopidy_pummeluff/registry.py b/mopidy_pummeluff/registry.py
index 8136666..9070e98 100644
--- a/mopidy_pummeluff/registry.py
+++ b/mopidy_pummeluff/registry.py
@@ -127,5 +127,16 @@ def register(self, action_class, uid, alias=None, parameter=None):
return action
+ def unregister(self, uid):
+ '''
+ Unregister a tag from the registry.
+
+ :param str uid: The UID
+ '''
+ LOGGER.info('Unregistering tag %s', uid)
+
+ del self[uid]
+ self.write()
+
REGISTRY = RegistryDict()
diff --git a/mopidy_pummeluff/web.py b/mopidy_pummeluff/web.py
index ef81574..e3c47d9 100644
--- a/mopidy_pummeluff/web.py
+++ b/mopidy_pummeluff/web.py
@@ -6,6 +6,7 @@
'LatestHandler',
'RegistryHandler',
'RegisterHandler',
+ 'UnregisterHandler',
'ActionClassesHandler',
)
@@ -26,14 +27,6 @@ class LatestHandler(RequestHandler): # pylint: disable=abstract-method
Request handler which returns the latest scanned tag.
'''
- def initialize(self, core): # pylint: disable=arguments-differ
- '''
- Initialize request handler with Mopidy core.
-
- :param mopidy.core.Core mopidy_core: The mopidy core instance
- '''
- self.core = core # pylint: disable=attribute-defined-outside-init
-
def get(self, *args, **kwargs): # pylint: disable=unused-argument
'''
Handle GET request.
@@ -65,14 +58,6 @@ class RegistryHandler(RequestHandler): # pylint: disable=abstract-method
Request handler which returns all registered tags.
'''
- def initialize(self, core): # pylint: disable=arguments-differ
- '''
- Initialize request handler with Mopidy core.
-
- :param mopidy.core.Core mopidy_core: The mopidy core instance
- '''
- self.core = core # pylint: disable=attribute-defined-outside-init
-
def get(self, *args, **kwargs): # pylint: disable=unused-argument
'''
Handle GET request.
@@ -97,14 +82,6 @@ class RegisterHandler(RequestHandler): # pylint: disable=abstract-method
Request handler which registers an RFID tag in the registry.
'''
- def initialize(self, core): # pylint: disable=arguments-differ
- '''
- Initialize request handler with Mopidy core.
-
- :param mopidy.core.Core mopidy_core: The mopidy core instance
- '''
- self.core = core # pylint: disable=attribute-defined-outside-init
-
def post(self, *args, **kwargs): # pylint: disable=unused-argument
'''
Handle POST request.
@@ -141,18 +118,44 @@ def put(self, *args, **kwargs): # pylint: disable=unused-argument
self.post()
-class ActionClassesHandler(RequestHandler): # pylint: disable=abstract-method
+class UnregisterHandler(RequestHandler): # pylint: disable=abstract-method
'''
- Request handler which returns all action classes.
+ Request handler which unregisters an RFID tag from the registry.
'''
- def initialize(self, core): # pylint: disable=arguments-differ
+ def post(self, *args, **kwargs): # pylint: disable=unused-argument
+ '''
+ Handle POST request.
'''
- Initialize request handler with Mopidy core.
+ try:
+ REGISTRY.unregister(uid=self.get_argument('uid'))
+
+ data = {
+ 'success': True,
+ 'message': 'Tag successfully unregistered',
+ }
+
+ except ValueError as ex:
+ self.set_status(400)
+ data = {
+ 'success': False,
+ 'message': str(ex)
+ }
+
+ self.set_header('Content-type', 'application/json')
+ self.write(dumps(data))
- :param mopidy.core.Core mopidy_core: The mopidy core instance
+ def put(self, *args, **kwargs): # pylint: disable=unused-argument
+ '''
+ Handle PUT request.
'''
- self.core = core # pylint: disable=attribute-defined-outside-init
+ self.post()
+
+
+class ActionClassesHandler(RequestHandler): # pylint: disable=abstract-method
+ '''
+ Request handler which returns all action classes.
+ '''
def get(self, *args, **kwargs): # pylint: disable=unused-argument
'''
diff --git a/mopidy_pummeluff/webui/index.html b/mopidy_pummeluff/webui/index.html
index 1f45238..a8f75af 100644
--- a/mopidy_pummeluff/webui/index.html
+++ b/mopidy_pummeluff/webui/index.html
@@ -27,6 +27,7 @@
Register New Tag
+
diff --git a/mopidy_pummeluff/webui/script.js b/mopidy_pummeluff/webui/script.js
index ea05d42..14527da 100644
--- a/mopidy_pummeluff/webui/script.js
+++ b/mopidy_pummeluff/webui/script.js
@@ -8,15 +8,13 @@ class API {
* Send AJAX request to REST API endpoint.
*/
- request(endpoint, data, callback)
- {
+ request = (endpoint, data, callback) => {
let init = {}
if(data)
init = { method: 'POST', body: data }
fetch(endpoint, init)
- .then(function(response)
- {
+ .then((response) => {
return response.json()
})
.then(callback)
@@ -27,24 +25,21 @@ class API {
* Refresh the registry.
*/
- refreshRegistry()
- {
- let callback = function(response)
- {
+ refreshRegistry = () => {
+ let callback = (response) => {
let tagsContainer = document.getElementById('tags')
- while(tagsContainer.firstChild)
+ while(tagsContainer.firstChild) {
tagsContainer.removeChild(tagsContainer.firstChild)
+ }
- for(let tag of response.tags)
- {
+ for(let tag of response.tags) {
let tagElement = document.createElement('div')
tagElement.setAttribute('class', 'tag')
let args = new Array('alias', 'uid', 'action_class', 'parameter')
- for(let arg of args)
- {
+ for(let arg of args) {
let spanElement = document.createElement('span')
- let value = tag[arg] ? tag[arg] : '-'
+ let value = tag[arg] ? tag[arg] : '-'
spanElement.setAttribute('class', arg.replace('_', '-'))
spanElement.innerHTML = value
tagElement.appendChild(spanElement)
@@ -61,16 +56,13 @@ class API {
* Refresh the tags.
*/
- refreshActionClasses()
- {
- let callback = function(response)
- {
+ refreshActionClasses = () => {
+ let callback = (response) => {
let select = document.getElementById('action-class');
while(select.firstChild)
select.removeChild(select.firstChild)
- for(let action_class in response.action_classes)
- {
+ for(let action_class in response.action_classes) {
let option = document.createElement('option')
option.setAttribute('value', action_class)
option.innerHTML = action_class + ' (' + response.action_classes[action_class] + ')'
@@ -81,45 +73,52 @@ class API {
this.request('/pummeluff/action-classes/', false, callback)
}
+ /*
+ * Reset the form.
+ */
+
+ formCallback = (response) => {
+ if(response.success) {
+ this.refreshRegistry()
+ document.getElementById('uid').value = ''
+ document.getElementById('alias').value = ''
+ document.getElementById('parameter').value = ''
+ document.getElementById('action-class').selectIndex = 0
+ } else {
+ window.alert(response.message)
+ }
+ }
+
/*
* Register a new tag.
*/
- register()
- {
+ register = () => {
let form = document.getElementById('register-form')
let data = new FormData(form)
+ this.request('/pummeluff/register/', data, this.formCallback)
+ }
- let callback = function(response)
- {
- if(response.success)
- {
- api.refreshRegistry()
- document.getElementById('uid').value = ''
- document.getElementById('alias').value = ''
- document.getElementById('parameter').value = ''
- document.getElementById('action-class').selectIndex = 0
- }
- else
- {
- window.alert(response.message)
- }
- }
+ /*
+ * Unregister an existing tag.
+ */
- this.request('/pummeluff/register/', data, callback)
+ unregister = () => {
+ let form = document.getElementById('register-form')
+ let data = new FormData(form)
+ this.request('/pummeluff/unregister/', data, this.formCallback)
}
/*
* Get latest scanned tag.
*/
- getLatestTag()
- {
+ getLatestTag = () => {
let latest_tag = undefined
- let uid_field = document.getElementById('uid')
- let alias_field = document.getElementById('alias')
- let parameter_field = document.getElementById('parameter')
+ let uid_field = document.getElementById('uid')
+ let alias_field = document.getElementById('alias')
+ let parameter_field = document.getElementById('parameter')
let action_class_select = document.getElementById('action-class')
uid_field.value = ''
@@ -127,15 +126,12 @@ class API {
parameter_field.value = ''
action_class_select.selectIndex = 0
- let link = document.getElementById('read-rfid-tag')
+ let link = document.getElementById('read-rfid-tag')
link.classList.add('reading')
- let do_request = function()
- {
- let callback = function(response)
- {
- if(latest_tag && response.success && JSON.stringify(response) != JSON.stringify(latest_tag))
- {
+ let do_request = () => {
+ let callback = (response) => {
+ if(latest_tag && response.success && JSON.stringify(response) != JSON.stringify(latest_tag)) {
uid_field.value = response.uid
if(response.alias)
@@ -148,9 +144,7 @@ class API {
action_class_select.value = response.action_class
link.classList.remove('reading')
- }
- else
- {
+ } else {
setTimeout(() => do_request(), 1000)
}
@@ -167,27 +161,28 @@ class API {
api = new API()
-api.refreshRegistry();
-api.refreshActionClasses();
+api.refreshRegistry()
+api.refreshActionClasses()
-document.addEventListener('click', function(event)
-{
+document.addEventListener('click', (event) => {
let target = event.target
let div = target.closest('div')
- if(div && div.classList.contains('tag'))
- {
- for(let child of div.children)
- {
+ if(div && div.classList.contains('tag')) {
+ for(let child of div.children) {
document.getElementById(child.className).value = child.innerHTML.replace(/^-$/, '')
}
}
})
-document.getElementById('register-form').onsubmit = function()
-{
+document.getElementById('register-form').onsubmit = () => {
api.register()
return false;
}
+document.getElementById('unregister-button').onclick = () => {
+ api.unregister()
+ return false
+}
+
document.getElementById('read-rfid-tag').onclick = () => api.getLatestTag()
diff --git a/mopidy_pummeluff/webui/style.css b/mopidy_pummeluff/webui/style.css
index dc39d7e..15488dc 100644
--- a/mopidy_pummeluff/webui/style.css
+++ b/mopidy_pummeluff/webui/style.css
@@ -18,11 +18,11 @@ body
body
{
- min-height : 100vh;
+ background-color: #222;
+ color : #eee;
font-family : sans-serif;
font-size : 14px;
- color : #eee;
- background-color: #222;
+ min-height : 100vh;
}
/*
@@ -80,15 +80,15 @@ input,
select,
button
{
- width : 100%;
+ background-color: #222;
border : 0;
- padding : 10px;
- border-width : 0 0 2px 0;
- border-style : solid;
border-color : #333;
- background-color: #222;
+ border-style : solid;
+ border-width : 0 0 2px 0;
color : #eee;
outline : none;
+ padding : 10px;
+ width : 100%;
}
select
@@ -103,26 +103,36 @@ input::placeholder
input:focus
{
- border-bottom-color: #fa0;
+ border-bottom-color: #8ff;
}
button
+{
+ color : #eee;
+ cursor : pointer;
+ font-weight: bold;
+ margin-top : 10px;
+}
+
+button#register-button
{
background-color: #4a4;
- color : #eee;
- font-weight : bold;
- margin-top : 10px;
+}
+
+button#unregister-button
+{
+ background-color: #a20;
}
#read-rfid-tag
{
- text-decoration: none;
- color : #fa0;
+ color : #8ff;
font-size : 11px;
+ text-decoration: none;
}
#read-rfid-tag.reading {
- animation: blink 0.5s cubic-bezier(.5, 0, 1, 1) infinite alternate;
+ animation: blink 0.5s cubic-bezier(.5, 0, 1, 1) infinite alternate;
}
@keyframes blink { to { opacity: 0.25; } }
@@ -133,15 +143,15 @@ button
div.tag
{
- display : inline-block;
- cursor : pointer;
background-color: #eee;
- color : #222;
box-shadow : 1px 1px 5px #000;
- padding : 10px;
+ color : #222;
+ cursor : pointer;
+ display : inline-block;
+ line-height : 20px;
margin : 0 20px 20px 0;
+ padding : 10px;
width : 400px;
- line-height : 20px;
}
div.tag span.uid,
@@ -153,14 +163,14 @@ div.tag span.parameter
div.tag span.action-class
{
- display : inline-block;
background-color: #888;
+ border-radius : 10px;
color : #eee;
+ display : inline-block;
font-size : 11px;
line-height : 11px;
- padding : 3px 5px;
margin-left : 5px;
- border-radius : 10px;
+ padding : 3px 5px;
}
div.tag span.alias,