it works
@ -47,7 +47,7 @@ class ApiController(RegistryMixin, OpenLPMixin, RegistryProperties):
|
||||
Register the poll return service and start the servers.
|
||||
"""
|
||||
self.poller = Poller()
|
||||
Registry().register('Poller', self.poller)
|
||||
Registry().register('poller', self.poller)
|
||||
self.ws_server = WebSocketServer()
|
||||
self.http_server = HttpServer()
|
||||
|
||||
|
@ -22,6 +22,7 @@
|
||||
"""
|
||||
The Endpoint class, which provides plugins with a way to serve their own portion of the API
|
||||
"""
|
||||
|
||||
import os
|
||||
|
||||
from mako.template import Template
|
||||
@ -35,7 +36,6 @@ class Endpoint(object):
|
||||
"""
|
||||
Create an endpoint with a URL prefix
|
||||
"""
|
||||
print("init")
|
||||
self.url_prefix = url_prefix
|
||||
self.static_dir = static_dir
|
||||
self.template_dir = template_dir
|
||||
@ -59,5 +59,16 @@ class Endpoint(object):
|
||||
return func
|
||||
return decorator
|
||||
|
||||
def render_template(self, filename, **kwargs):
|
||||
"""
|
||||
Render a mako template
|
||||
"""
|
||||
if not self.template_dir:
|
||||
raise Exception('No template directory specified')
|
||||
path = os.path.abspath(os.path.join(self.template_dir, filename))
|
||||
print("path = ", path)
|
||||
return Template(filename=path, input_encoding='utf-8').render(**kwargs)
|
||||
|
||||
from .controller import controller_endpoint
|
||||
from .core import stage_endpoint
|
||||
from .service import service_endpoint
|
||||
|
@ -31,10 +31,10 @@ from openlp.core.lib import ItemCapabilities, create_thumb
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
controller_endpoint = Endpoint('api')
|
||||
controller_endpoint = Endpoint('controller')
|
||||
|
||||
|
||||
@controller_endpoint.route('controller/live/text')
|
||||
@controller_endpoint.route('live/text')
|
||||
def controller_text(request):
|
||||
"""
|
||||
Perform an action on the slide controller.
|
||||
@ -90,34 +90,4 @@ def controller_text(request):
|
||||
return json_data
|
||||
|
||||
|
||||
@controller_endpoint.route('service/list')
|
||||
def service_list(request):
|
||||
"""
|
||||
Handles requests for service items in the service manager
|
||||
|
||||
"""
|
||||
return {'results': {'items': get_service_items()}}
|
||||
|
||||
|
||||
def get_service_items():
|
||||
"""
|
||||
Read the service item in use and return the data as a json object
|
||||
"""
|
||||
live_controller = Registry().get('live_controller')
|
||||
service_items = []
|
||||
if live_controller.service_item:
|
||||
current_unique_identifier = live_controller.service_item.unique_identifier
|
||||
else:
|
||||
current_unique_identifier = None
|
||||
for item in Registry().get('service_manager').service_items:
|
||||
service_item = item['service_item']
|
||||
service_items.append({
|
||||
'id': str(service_item.unique_identifier),
|
||||
'title': str(service_item.get_display_title()),
|
||||
'plugin': str(service_item.name),
|
||||
'notes': str(service_item.notes),
|
||||
'selected': (service_item.unique_identifier == current_unique_identifier)
|
||||
})
|
||||
return service_items
|
||||
|
||||
register_endpoint(controller_endpoint)
|
||||
|
@ -3,15 +3,18 @@ import os
|
||||
|
||||
from openlp.core.api.http.endpoint import Endpoint
|
||||
from openlp.core.api.http import register_endpoint
|
||||
from openlp.core.common import AppLocation, UiStrings, translate
|
||||
from openlp.core.common import Registry, AppLocation, UiStrings, translate
|
||||
from openlp.core.lib import image_to_byte
|
||||
|
||||
|
||||
from mako.template import Template
|
||||
template_dir = static_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'templates')
|
||||
static_dir = os.path.join(os.path.dirname(os.path.realpath(__file__)), 'static')
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
stage_endpoint = Endpoint('')
|
||||
stage_endpoint = Endpoint('stage', template_dir=template_dir, static_dir=static_dir)
|
||||
main_endpoint = Endpoint('main', template_dir=template_dir, static_dir=static_dir)
|
||||
blank_endpoint = Endpoint('', template_dir=template_dir, static_dir=static_dir)
|
||||
|
||||
FILE_TYPES = {
|
||||
'.html': 'text/html',
|
||||
@ -27,7 +30,7 @@ remote = translate('RemotePlugin.Mobile', 'Remote')
|
||||
stage = translate('RemotePlugin.Mobile', 'Stage View')
|
||||
live = translate('RemotePlugin.Mobile', 'Live View')
|
||||
|
||||
template_vars = {
|
||||
TRANSLATED_STRINGS = {
|
||||
'app_title': "{main} {remote}".format(main=UiStrings().OLPV2x, remote=remote),
|
||||
'stage_title': "{main} {stage}".format(main=UiStrings().OLPV2x, stage=stage),
|
||||
'live_title': "{main} {live}".format(main=UiStrings().OLPV2x, live=live),
|
||||
@ -56,101 +59,87 @@ template_vars = {
|
||||
}
|
||||
|
||||
|
||||
@stage_endpoint.route('$')
|
||||
@stage_endpoint.route('(stage)$')
|
||||
@stage_endpoint.route('(main)$')
|
||||
@stage_endpoint.route('(css)')
|
||||
@stage_endpoint.route('(js)')
|
||||
@stage_endpoint.route('(assets)')
|
||||
def file_access(request):
|
||||
@stage_endpoint.route('')
|
||||
def stage_index(request):
|
||||
"""
|
||||
Get a list of songs`
|
||||
Deliver the page for the /stage url
|
||||
"""
|
||||
file_name = request.path
|
||||
html_dir = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'core', 'api', 'html')
|
||||
log.debug('serve file request {name}'.format(name=file_name))
|
||||
if file_name.startswith('/'):
|
||||
file_name = file_name[1:]
|
||||
if not file_name:
|
||||
file_name = 'index.html'
|
||||
if '.' not in file_name:
|
||||
file_name += '.html'
|
||||
if file_name.startswith('/'):
|
||||
file_name = file_name[1:]
|
||||
path = os.path.normpath(os.path.join(html_dir, file_name))
|
||||
return _process_file(path)
|
||||
#file_name = request.path
|
||||
#html_dir = os.path.join(AppLocation.get_directory(AppLocation.AppDir), 'core', 'api', 'html')
|
||||
#log.debug('serve file request {name}'.format(name=file_name))
|
||||
#if file_name.startswith('/'):
|
||||
# file_name = file_name[1:]
|
||||
#if not file_name:
|
||||
# file_name = 'index.mako'
|
||||
#if '.' not in file_name:
|
||||
# file_name += '.html'
|
||||
#if file_name.startswith('/'):
|
||||
# file_name = file_name[1:]
|
||||
#path = os.path.normpath(os.path.join(html_dir, file_name))
|
||||
return stage_endpoint.render_template('stage.mako', **TRANSLATED_STRINGS, static_url=static_dir)
|
||||
|
||||
|
||||
@stage_endpoint.route('(stage)/(.*)$')
|
||||
def bespoke_file_access(request):
|
||||
@main_endpoint.route('')
|
||||
def main_index(request):
|
||||
"""
|
||||
Allow Stage view to be delivered with custom views.
|
||||
|
||||
:param request: base path of the URL. Not used but passed by caller
|
||||
:return:
|
||||
Deliver the page for the /main url
|
||||
"""
|
||||
file_name = request.path
|
||||
config_dir = os.path.join(AppLocation.get_data_path(), 'stages')
|
||||
log.debug('serve file request {name}'.format(name=file_name))
|
||||
parts = file_name.split('/')
|
||||
if len(parts) == 1:
|
||||
file_name = os.path.join(parts[0], 'stage.html')
|
||||
elif len(parts) == 3:
|
||||
file_name = os.path.join(parts[1], parts[2])
|
||||
path = os.path.normpath(os.path.join(config_dir, file_name))
|
||||
return _process_file(path)
|
||||
return stage_endpoint.render_template('main.mako', **TRANSLATED_STRINGS)
|
||||
|
||||
|
||||
@stage_endpoint.route('main/image$')
|
||||
@blank_endpoint.route('')
|
||||
def static_file_loader(request):
|
||||
"""
|
||||
Dummy endpoint to trigger endpoint creation
|
||||
:param request:
|
||||
"""
|
||||
pass
|
||||
|
||||
|
||||
# @stage_endpoint.route('(stage)/(.*)$')
|
||||
# def bespoke_file_access(request):
|
||||
# """
|
||||
# Allow Stage view to be delivered with custom views.
|
||||
#
|
||||
# :param request: base path of the URL. Not used but passed by caller
|
||||
# :return:
|
||||
# """
|
||||
# file_name = request.path
|
||||
# config_dir = os.path.join(AppLocation.get_data_path(), 'stages')
|
||||
# log.debug('serve file request {name}'.format(name=file_name))
|
||||
# parts = file_name.split('/')
|
||||
# if len(parts) == 1:
|
||||
# file_name = os.path.join(parts[0], 'stage.mako')
|
||||
# elif len(parts) == 3:
|
||||
# file_name = os.path.join(parts[1], parts[2])
|
||||
# path = os.path.normpath(os.path.join(config_dir, file_name))
|
||||
# #return _process_file(path)
|
||||
# pass
|
||||
|
||||
|
||||
@main_endpoint.route('image')
|
||||
def main_image(request):
|
||||
"""
|
||||
Return the latest display image as a byte stream.
|
||||
:param request: base path of the URL. Not used but passed by caller
|
||||
:return:
|
||||
"""
|
||||
# result = {
|
||||
# 'slide_image': 'data:image/png;base64,' + str(image_to_byte(self.live_controller.slide_image))
|
||||
# }
|
||||
# self.do_json_header()
|
||||
# return json.dumps({'results': result}).encode()
|
||||
pass
|
||||
live_controller = Registry().get('live_controller')
|
||||
result = {
|
||||
'slide_image': 'data:image/png;base64,' + str(image_to_byte(live_controller.slide_image))
|
||||
}
|
||||
return {'results': result}
|
||||
|
||||
@stage_endpoint.route(r'^/(\w+)/thumbnails([^/]+)?/(.*)$')
|
||||
def main_image(request):
|
||||
"""
|
||||
Get a list of songs
|
||||
:param request: base path of the URL. Not used but passed by caller
|
||||
:return:
|
||||
"""
|
||||
# songs = db.query(Song).get()
|
||||
# return {'songs': [dictify(song) for song in songs]}
|
||||
print("AAA")
|
||||
|
||||
|
||||
def _process_file(path):
|
||||
"""
|
||||
Common file processing code
|
||||
|
||||
:param path: path to file to be loaded
|
||||
:return: web resource to be loaded
|
||||
"""
|
||||
ext, content_type = get_content_type(path)
|
||||
file_handle = None
|
||||
try:
|
||||
if ext == '.html':
|
||||
variables = template_vars
|
||||
content = Template(filename=path, input_encoding='utf-8').render(**variables)
|
||||
else:
|
||||
file_handle = open(path, 'rb')
|
||||
log.debug('Opened {path}'.format(path=path))
|
||||
content = file_handle.read().decode("utf-8")
|
||||
except IOError:
|
||||
log.exception('Failed to open {path}'.format(path=path))
|
||||
return None
|
||||
finally:
|
||||
if file_handle:
|
||||
file_handle.close()
|
||||
return content
|
||||
# @stage_endpoint.route(r'^/(\w+)/thumbnails([^/]+)?/(.*)$')
|
||||
# def main_image(request):
|
||||
# """
|
||||
# Get a list of songs
|
||||
# :param request: base path of the URL. Not used but passed by caller
|
||||
# :return:
|
||||
# """
|
||||
# # songs = db.query(Song).get()
|
||||
# # return {'songs': [dictify(song) for song in songs]}
|
||||
# print("AAA")
|
||||
|
||||
|
||||
def get_content_type(file_name):
|
||||
@ -165,3 +154,5 @@ def get_content_type(file_name):
|
||||
return ext, content_type
|
||||
|
||||
register_endpoint(stage_endpoint)
|
||||
register_endpoint(blank_endpoint)
|
||||
register_endpoint(main_endpoint)
|
64
openlp/core/api/http/endpoint/service.py
Normal file
@ -0,0 +1,64 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# vim: autoindent shiftwidth=4 expandtab textwidth=120 tabstop=4 softtabstop=4
|
||||
|
||||
###############################################################################
|
||||
# OpenLP - Open Source Lyrics Projection #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# Copyright (c) 2008-2016 OpenLP Developers #
|
||||
# --------------------------------------------------------------------------- #
|
||||
# This program 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; version 2 of the License. #
|
||||
# #
|
||||
# This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 #
|
||||
# Temple Place, Suite 330, Boston, MA 02111-1307 USA #
|
||||
###############################################################################
|
||||
import logging
|
||||
|
||||
from openlp.core.api.http.endpoint import Endpoint
|
||||
from openlp.core.api.http import register_endpoint
|
||||
from openlp.core.common import Registry
|
||||
|
||||
|
||||
log = logging.getLogger(__name__)
|
||||
|
||||
service_endpoint = Endpoint('service')
|
||||
|
||||
|
||||
@service_endpoint.route('list')
|
||||
def service_list(request):
|
||||
"""
|
||||
Handles requests for service items in the service manager
|
||||
|
||||
"""
|
||||
return {'results': {'items': get_service_items()}}
|
||||
|
||||
|
||||
def get_service_items():
|
||||
"""
|
||||
Read the service item in use and return the data as a json object
|
||||
"""
|
||||
live_controller = Registry().get('live_controller')
|
||||
service_items = []
|
||||
if live_controller.service_item:
|
||||
current_unique_identifier = live_controller.service_item.unique_identifier
|
||||
else:
|
||||
current_unique_identifier = None
|
||||
for item in Registry().get('service_manager').service_items:
|
||||
service_item = item['service_item']
|
||||
service_items.append({
|
||||
'id': str(service_item.unique_identifier),
|
||||
'title': str(service_item.get_display_title()),
|
||||
'plugin': str(service_item.name),
|
||||
'notes': str(service_item.notes),
|
||||
'selected': (service_item.unique_identifier == current_unique_identifier)
|
||||
})
|
||||
return service_items
|
||||
|
||||
register_endpoint(service_endpoint)
|
9404
openlp/core/api/http/endpoint/static/assets/jquery.js
vendored
Normal file
4
openlp/core/api/http/endpoint/static/assets/jquery.min.js
vendored
Normal file
9357
openlp/core/api/http/endpoint/static/assets/jquery.mobile.js
Normal file
2
openlp/core/api/http/endpoint/static/assets/jquery.mobile.min.css
vendored
Normal file
2
openlp/core/api/http/endpoint/static/assets/jquery.mobile.min.js
vendored
Normal file
32
openlp/core/api/http/endpoint/static/css/main.css
Normal file
@ -0,0 +1,32 @@
|
||||
/******************************************************************************
|
||||
* OpenLP - Open Source Lyrics Projection *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* Copyright (c) 2008-2016 OpenLP Developers *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* This program 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; version 2 of the License. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 *
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
||||
******************************************************************************/
|
||||
body {
|
||||
background-color: black;
|
||||
font-family: sans-serif;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
.size {
|
||||
position: absolute;
|
||||
top: 0px;
|
||||
vertical-align: middle;
|
||||
height: 100%;
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
}
|
31
openlp/core/api/http/endpoint/static/css/openlp.css
Normal file
@ -0,0 +1,31 @@
|
||||
/******************************************************************************
|
||||
* OpenLP - Open Source Lyrics Projection *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* Copyright (c) 2008-2016 OpenLP Developers *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* This program 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; version 2 of the License. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 *
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
||||
******************************************************************************/
|
||||
|
||||
.ui-icon-blank {
|
||||
background-image: url(../images/ui-icon-blank.png);
|
||||
}
|
||||
|
||||
.ui-icon-unblank {
|
||||
background-image: url(../images/ui-icon-unblank.png);
|
||||
}
|
||||
|
||||
/* Overwrite style from jquery-mobile.min.css */
|
||||
.ui-li .ui-btn-text a.ui-link-inherit{
|
||||
white-space: normal;
|
||||
}
|
64
openlp/core/api/http/endpoint/static/css/stage.css
Normal file
@ -0,0 +1,64 @@
|
||||
/******************************************************************************
|
||||
* OpenLP - Open Source Lyrics Projection *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* Copyright (c) 2008-2016 OpenLP Developers *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* This program 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; version 2 of the License. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 *
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
||||
******************************************************************************/
|
||||
|
||||
body {
|
||||
background-color: black;
|
||||
font-family: sans-serif;
|
||||
overflow: hidden;
|
||||
}
|
||||
|
||||
#currentslide {
|
||||
font-size: 40pt;
|
||||
color: white;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
#nextslide {
|
||||
font-size: 40pt;
|
||||
color: grey;
|
||||
padding-top: 0px;
|
||||
padding-bottom: 0px;
|
||||
}
|
||||
|
||||
#right {
|
||||
float: right;
|
||||
}
|
||||
|
||||
#clock {
|
||||
font-size: 30pt;
|
||||
color: yellow;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#notes {
|
||||
font-size: 36pt;
|
||||
color: salmon;
|
||||
text-align: right;
|
||||
}
|
||||
|
||||
#verseorder {
|
||||
font-size: 30pt;
|
||||
color: green;
|
||||
text-align: left;
|
||||
}
|
||||
|
||||
.currenttag {
|
||||
color: lightgreen;
|
||||
font-weight: bold;
|
||||
}
|
BIN
openlp/core/api/http/endpoint/static/images/ajax-loader.gif
Normal file
After Width: | Height: | Size: 7.6 KiB |
BIN
openlp/core/api/http/endpoint/static/images/ajax-loader.png
Normal file
After Width: | Height: | Size: 340 B |
BIN
openlp/core/api/http/endpoint/static/images/favicon.ico
Normal file
After Width: | Height: | Size: 4.2 KiB |
BIN
openlp/core/api/http/endpoint/static/images/form-check-off.png
Normal file
After Width: | Height: | Size: 364 B |
BIN
openlp/core/api/http/endpoint/static/images/form-check-on.png
Normal file
After Width: | Height: | Size: 460 B |
BIN
openlp/core/api/http/endpoint/static/images/form-radio-off.png
Normal file
After Width: | Height: | Size: 453 B |
BIN
openlp/core/api/http/endpoint/static/images/form-radio-on.png
Normal file
After Width: | Height: | Size: 519 B |
After Width: | Height: | Size: 1.2 KiB |
BIN
openlp/core/api/http/endpoint/static/images/icons-18-black.png
Normal file
After Width: | Height: | Size: 1.7 KiB |
BIN
openlp/core/api/http/endpoint/static/images/icons-18-white.png
Normal file
After Width: | Height: | Size: 1.8 KiB |
BIN
openlp/core/api/http/endpoint/static/images/icons-36-black.png
Normal file
After Width: | Height: | Size: 3.5 KiB |
BIN
openlp/core/api/http/endpoint/static/images/icons-36-white.png
Normal file
After Width: | Height: | Size: 3.6 KiB |
BIN
openlp/core/api/http/endpoint/static/images/ui-icon-blank.png
Normal file
After Width: | Height: | Size: 225 B |
BIN
openlp/core/api/http/endpoint/static/images/ui-icon-unblank.png
Normal file
After Width: | Height: | Size: 231 B |
50
openlp/core/api/http/endpoint/static/js/main.js
Normal file
@ -0,0 +1,50 @@
|
||||
/******************************************************************************
|
||||
* OpenLP - Open Source Lyrics Projection *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* Copyright (c) 2008-2016 OpenLP Developers *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* This program 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; version 2 of the License. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 *
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
||||
******************************************************************************/
|
||||
window.OpenLP = {
|
||||
loadSlide: function (event) {
|
||||
$.getJSON(
|
||||
"/main/image",
|
||||
function (data, status) {
|
||||
var img = document.getElementById('image');
|
||||
img.src = data.results.slide_image;
|
||||
img.style.display = 'block';
|
||||
}
|
||||
);
|
||||
},
|
||||
pollServer: function () {
|
||||
if ("WebSocket" in window) {
|
||||
// Let us open a web socket
|
||||
var ws = new WebSocket('ws://' + location.hostname + ':4317/main_poll');
|
||||
ws.binaryType = 'arraybuffer';
|
||||
ws.onmessage = function (evt) {
|
||||
var msg = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(evt.data)));
|
||||
if (OpenLP.slideCount != msg.results.slide_count) {
|
||||
OpenLP.slideCount = msg.results.slide_count;
|
||||
OpenLP.loadSlide();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The browser doesn't support WebSocket
|
||||
alert("WebSocket NOT supported by your Browser!");
|
||||
}
|
||||
}
|
||||
};
|
||||
$.ajaxSetup({ cache: false });
|
||||
OpenLP.pollServer();
|
||||
|
390
openlp/core/api/http/endpoint/static/js/openlp.js
Normal file
@ -0,0 +1,390 @@
|
||||
/******************************************************************************
|
||||
* OpenLP - Open Source Lyrics Projection *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* Copyright (c) 2008-2016 OpenLP Developers *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* This program 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; version 2 of the License. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 *
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
||||
******************************************************************************/
|
||||
|
||||
window.OpenLP = {
|
||||
getElement: function(event) {
|
||||
var targ;
|
||||
if (!event) {
|
||||
var event = window.event;
|
||||
}
|
||||
if (event.target) {
|
||||
targ = event.target;
|
||||
}
|
||||
else if (event.srcElement) {
|
||||
targ = event.srcElement;
|
||||
}
|
||||
if (targ.nodeType == 3) {
|
||||
// defeat Safari bug
|
||||
targ = targ.parentNode;
|
||||
}
|
||||
var isSecure = false;
|
||||
var isAuthorised = false;
|
||||
return $(targ);
|
||||
},
|
||||
getSearchablePlugins: function () {
|
||||
$.getJSON(
|
||||
"/api/plugin/search",
|
||||
function (data, status) {
|
||||
var select = $("#search-plugin");
|
||||
select.html("");
|
||||
$.each(data.results.items, function (idx, value) {
|
||||
select.append("<option value='" + value[0] + "'>" + value[1] + "</option>");
|
||||
});
|
||||
select.selectmenu("refresh");
|
||||
}
|
||||
);
|
||||
},
|
||||
loadService: function (event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
$.getJSON(
|
||||
"/api/service/list",
|
||||
function (data, status) {
|
||||
var ul = $("#service-manager > div[data-role=content] > ul[data-role=listview]");
|
||||
ul.html("");
|
||||
$.each(data.results.items, function (idx, value) {
|
||||
var text = value["title"];
|
||||
if (value["notes"]) {
|
||||
text += ' - ' + value["notes"];
|
||||
}
|
||||
var li = $("<li data-icon=\"false\">").append(
|
||||
$("<a href=\"#\">").attr("value", parseInt(idx, 10)).text(text));
|
||||
li.attr("uuid", value["id"])
|
||||
li.children("a").click(OpenLP.setItem);
|
||||
ul.append(li);
|
||||
});
|
||||
ul.listview("refresh");
|
||||
}
|
||||
);
|
||||
},
|
||||
loadController: function (event) {
|
||||
if (event) {
|
||||
event.preventDefault();
|
||||
}
|
||||
$.getJSON(
|
||||
"/api/controller/live/text",
|
||||
function (data, status) {
|
||||
var ul = $("#slide-controller > div[data-role=content] > ul[data-role=listview]");
|
||||
ul.html("");
|
||||
for (idx in data.results.slides) {
|
||||
var indexInt = parseInt(idx,10);
|
||||
var slide = data.results.slides[idx];
|
||||
var text = slide["tag"];
|
||||
if (text != "") {
|
||||
text = text + ": ";
|
||||
}
|
||||
if (slide["title"]) {
|
||||
text += slide["title"]
|
||||
} else {
|
||||
text += slide["text"];
|
||||
}
|
||||
if (slide["slide_notes"]) {
|
||||
text += ("<div style='font-size:smaller;font-weight:normal'>" + slide["slide_notes"] + "</div>");
|
||||
}
|
||||
text = text.replace(/\n/g, '<br />');
|
||||
if (slide["img"]) {
|
||||
text += "<img src='" + slide["img"].replace("/thumbnails/", "/thumbnails88x88/") + "'>";
|
||||
}
|
||||
var li = $("<li data-icon=\"false\">").append($("<a href=\"#\">").html(text));
|
||||
if (slide["selected"]) {
|
||||
li.attr("data-theme", "e");
|
||||
}
|
||||
li.children("a").click(OpenLP.setSlide);
|
||||
li.find("*").attr("value", indexInt );
|
||||
ul.append(li);
|
||||
}
|
||||
OpenLP.currentItem = data.results.item;
|
||||
ul.listview("refresh");
|
||||
}
|
||||
);
|
||||
},
|
||||
setItem: function (event) {
|
||||
event.preventDefault();
|
||||
var item = OpenLP.getElement(event);
|
||||
var id = item.attr("value");
|
||||
if (typeof id !== "number") {
|
||||
id = "\"" + id + "\"";
|
||||
}
|
||||
var text = "{\"request\": {\"id\": " + id + "}}";
|
||||
$.getJSON(
|
||||
"/api/service/set",
|
||||
{"data": text},
|
||||
function (data, status) {
|
||||
$.mobile.changePage("#slide-controller");
|
||||
$("#service-manager > div[data-role=content] ul[data-role=listview] li").attr("data-theme", "c").removeClass("ui-btn-up-e").addClass("ui-btn-up-c");
|
||||
while (item[0].tagName != "LI") {
|
||||
item = item.parent();
|
||||
}
|
||||
item.attr("data-theme", "e").removeClass("ui-btn-up-c").addClass("ui-btn-up-e");
|
||||
$("#service-manager > div[data-role=content] ul[data-role=listview]").listview("refresh");
|
||||
}
|
||||
);
|
||||
},
|
||||
setSlide: function (event) {
|
||||
event.preventDefault();
|
||||
var slide = OpenLP.getElement(event);
|
||||
var id = slide.attr("value");
|
||||
if (typeof id !== "number") {
|
||||
id = "\"" + id + "\"";
|
||||
}
|
||||
var text = "{\"request\": {\"id\": " + id + "}}";
|
||||
$.getJSON(
|
||||
"/api/controller/live/set",
|
||||
{"data": text},
|
||||
function (data, status) {
|
||||
$("#slide-controller div[data-role=content] ul[data-role=listview] li").attr("data-theme", "c").removeClass("ui-btn-up-e").addClass("ui-btn-up-c");
|
||||
while (slide[0].tagName != "LI") {
|
||||
slide = slide.parent();
|
||||
}
|
||||
slide.attr("data-theme", "e").removeClass("ui-btn-up-c").addClass("ui-btn-up-e");
|
||||
$("#slide-controller div[data-role=content] ul[data-role=listview]").listview("refresh");
|
||||
}
|
||||
);
|
||||
},
|
||||
pollServer: function () {
|
||||
if ("WebSocket" in window) {
|
||||
// Let us open a web socket
|
||||
var ws = new WebSocket('ws://' + location.hostname + ':4317/poll');
|
||||
ws.binaryType = 'arraybuffer';
|
||||
ws.onmessage = function (evt) {
|
||||
var data = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(evt.data)));
|
||||
|
||||
var prevItem = OpenLP.currentItem;
|
||||
OpenLP.currentSlide = data.results.slide;
|
||||
OpenLP.currentItem = data.results.item;
|
||||
OpenLP.isSecure = data.results.isSecure;
|
||||
OpenLP.isAuthorised = data.results.isAuthorised;
|
||||
if ($("#service-manager").is(":visible")) {
|
||||
if (OpenLP.currentService != data.results.service) {
|
||||
OpenLP.currentService = data.results.service;
|
||||
OpenLP.loadService();
|
||||
}
|
||||
$("#service-manager div[data-role=content] ul[data-role=listview] li").attr("data-theme", "c").removeClass("ui-btn-up-e").addClass("ui-btn-up-c");
|
||||
$("#service-manager div[data-role=content] ul[data-role=listview] li a").each(function () {
|
||||
var item = $(this);
|
||||
while (item[0].tagName != "LI") {
|
||||
item = item.parent();
|
||||
}
|
||||
if (item.attr("uuid") == OpenLP.currentItem) {
|
||||
item.attr("data-theme", "e").removeClass("ui-btn-up-c").addClass("ui-btn-up-e");
|
||||
return false;
|
||||
}
|
||||
});
|
||||
$("#service-manager div[data-role=content] ul[data-role=listview]").listview("refresh");
|
||||
}
|
||||
if ($("#slide-controller").is(":visible")) {
|
||||
if (prevItem != OpenLP.currentItem) {
|
||||
OpenLP.loadController();
|
||||
return;
|
||||
}
|
||||
var idx = 0;
|
||||
$("#slide-controller div[data-role=content] ul[data-role=listview] li").attr("data-theme", "c").removeClass("ui-btn-up-e").addClass("ui-btn-up-c");
|
||||
$("#slide-controller div[data-role=content] ul[data-role=listview] li a").each(function () {
|
||||
var item = $(this);
|
||||
if (idx == OpenLP.currentSlide) {
|
||||
while (item[0].tagName != "LI") {
|
||||
item = item.parent();
|
||||
}
|
||||
item.attr("data-theme", "e").removeClass("ui-btn-up-c").addClass("ui-btn-up-e");
|
||||
return false;
|
||||
}
|
||||
idx++;
|
||||
});
|
||||
$("#slide-controller div[data-role=content] ul[data-role=listview]").listview("refresh");
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The browser doesn't support WebSocket
|
||||
alert("WebSocket NOT supported by your Browser!");
|
||||
}
|
||||
},
|
||||
nextItem: function (event) {
|
||||
event.preventDefault();
|
||||
$.getJSON("/api/service/next");
|
||||
},
|
||||
previousItem: function (event) {
|
||||
event.preventDefault();
|
||||
$.getJSON("/api/service/previous");
|
||||
},
|
||||
nextSlide: function (event) {
|
||||
event.preventDefault();
|
||||
$.getJSON("/api/controller/live/next");
|
||||
},
|
||||
previousSlide: function (event) {
|
||||
event.preventDefault();
|
||||
$.getJSON("/api/controller/live/previous");
|
||||
},
|
||||
blankDisplay: function (event) {
|
||||
event.preventDefault();
|
||||
$.getJSON("/api/display/blank");
|
||||
},
|
||||
themeDisplay: function (event) {
|
||||
event.preventDefault();
|
||||
$.getJSON("/api/display/theme");
|
||||
},
|
||||
desktopDisplay: function (event) {
|
||||
event.preventDefault();
|
||||
$.getJSON("/api/display/desktop");
|
||||
},
|
||||
showDisplay: function (event) {
|
||||
event.preventDefault();
|
||||
$.getJSON("/api/display/show");
|
||||
},
|
||||
showAlert: function (event) {
|
||||
event.preventDefault();
|
||||
var alert = OpenLP.escapeString($("#alert-text").val())
|
||||
var text = "{\"request\": {\"text\": \"" + alert + "\"}}";
|
||||
$.getJSON(
|
||||
"/api/alert",
|
||||
{"data": text},
|
||||
function () {
|
||||
$("#alert-text").val("");
|
||||
}
|
||||
);
|
||||
},
|
||||
search: function (event) {
|
||||
event.preventDefault();
|
||||
var query = OpenLP.escapeString($("#search-text").val())
|
||||
var text = "{\"request\": {\"text\": \"" + query + "\"}}";
|
||||
$.getJSON(
|
||||
"/api/" + $("#search-plugin").val() + "/search",
|
||||
{"data": text},
|
||||
function (data, status) {
|
||||
var ul = $("#search > div[data-role=content] > ul[data-role=listview]");
|
||||
ul.html("");
|
||||
if (data.results.items.length == 0) {
|
||||
var li = $("<li data-icon=\"false\">").text(translationStrings["no_results"]);
|
||||
ul.append(li);
|
||||
}
|
||||
else {
|
||||
$.each(data.results.items, function (idx, value) {
|
||||
if (typeof value[0] !== "number"){
|
||||
value[0] = OpenLP.escapeString(value[0])
|
||||
}
|
||||
var txt = "";
|
||||
if (value.length > 2) {
|
||||
txt = value[1] + " ( " + value[2] + " )";
|
||||
} else {
|
||||
txt = value[1];
|
||||
}
|
||||
ul.append($("<li>").append($("<a>").attr("href", "#options")
|
||||
.attr("data-rel", "dialog").attr("value", value[0])
|
||||
.click(OpenLP.showOptions).text(txt)));
|
||||
});
|
||||
}
|
||||
ul.listview("refresh");
|
||||
}
|
||||
);
|
||||
},
|
||||
showOptions: function (event) {
|
||||
event.preventDefault();
|
||||
var element = OpenLP.getElement(event);
|
||||
$("#selected-item").val(element.attr("value"));
|
||||
},
|
||||
goLive: function (event) {
|
||||
event.preventDefault();
|
||||
var id = $("#selected-item").val();
|
||||
if (typeof id !== "number") {
|
||||
id = "\"" + id + "\"";
|
||||
}
|
||||
var text = "{\"request\": {\"id\": " + id + "}}";
|
||||
$.getJSON(
|
||||
"/api/" + $("#search-plugin").val() + "/live",
|
||||
{"data": text}
|
||||
);
|
||||
$.mobile.changePage("#slide-controller");
|
||||
},
|
||||
addToService: function (event) {
|
||||
event.preventDefault();
|
||||
var id = $("#selected-item").val();
|
||||
if (typeof id !== "number") {
|
||||
id = "\"" + id + "\"";
|
||||
}
|
||||
var text = "{\"request\": {\"id\": " + id + "}}";
|
||||
$.getJSON(
|
||||
"/api/" + $("#search-plugin").val() + "/add",
|
||||
{"data": text},
|
||||
function () {
|
||||
$("#options").dialog("close");
|
||||
}
|
||||
);
|
||||
},
|
||||
addAndGoToService: function (event) {
|
||||
event.preventDefault();
|
||||
var id = $("#selected-item").val();
|
||||
if (typeof id !== "number") {
|
||||
id = "\"" + id + "\"";
|
||||
}
|
||||
var text = "{\"request\": {\"id\": " + id + "}}";
|
||||
$.getJSON(
|
||||
"/api/" + $("#search-plugin").val() + "/add",
|
||||
{"data": text},
|
||||
function () {
|
||||
//$("#options").dialog("close");
|
||||
$.mobile.changePage("#service-manager");
|
||||
}
|
||||
);
|
||||
},
|
||||
escapeString: function (string) {
|
||||
return string.replace(/\\/g, "\\\\").replace(/"/g, "\\\"")
|
||||
}
|
||||
}
|
||||
// Initial jQueryMobile options
|
||||
$(document).bind("mobileinit", function(){
|
||||
$.mobile.defaultDialogTransition = "none";
|
||||
$.mobile.defaultPageTransition = "none";
|
||||
});
|
||||
// Service Manager
|
||||
$("#service-manager").live("pagebeforeshow", OpenLP.loadService);
|
||||
$("#service-refresh").live("click", OpenLP.loadService);
|
||||
$("#service-next").live("click", OpenLP.nextItem);
|
||||
$("#service-previous").live("click", OpenLP.previousItem);
|
||||
$("#service-blank").live("click", OpenLP.blankDisplay);
|
||||
$("#service-theme").live("click", OpenLP.themeDisplay);
|
||||
$("#service-desktop").live("click", OpenLP.desktopDisplay);
|
||||
$("#service-show").live("click", OpenLP.showDisplay);
|
||||
// Slide Controller
|
||||
$("#slide-controller").live("pagebeforeshow", OpenLP.loadController);
|
||||
$("#controller-refresh").live("click", OpenLP.loadController);
|
||||
$("#controller-next").live("click", OpenLP.nextSlide);
|
||||
$("#controller-previous").live("click", OpenLP.previousSlide);
|
||||
$("#controller-blank").live("click", OpenLP.blankDisplay);
|
||||
$("#controller-theme").live("click", OpenLP.themeDisplay);
|
||||
$("#controller-desktop").live("click", OpenLP.desktopDisplay);
|
||||
$("#controller-show").live("click", OpenLP.showDisplay);
|
||||
// Alerts
|
||||
$("#alert-submit").live("click", OpenLP.showAlert);
|
||||
// Search
|
||||
$("#search-submit").live("click", OpenLP.search);
|
||||
$("#search-text").live("keypress", function(event) {
|
||||
if (event.which == 13)
|
||||
{
|
||||
OpenLP.search(event);
|
||||
}
|
||||
});
|
||||
$("#go-live").live("click", OpenLP.goLive);
|
||||
$("#add-to-service").live("click", OpenLP.addToService);
|
||||
$("#add-and-go-to-service").live("click", OpenLP.addAndGoToService);
|
||||
// Poll the server twice a second to get any updates.
|
||||
$.ajaxSetup({cache: false});
|
||||
$("#search").live("pageinit", function (event) {
|
||||
OpenLP.getSearchablePlugins();
|
||||
});
|
||||
OpenLP.pollServer();
|
178
openlp/core/api/http/endpoint/static/js/stage.js
Normal file
@ -0,0 +1,178 @@
|
||||
/******************************************************************************
|
||||
* OpenLP - Open Source Lyrics Projection *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* Copyright (c) 2008-2016 OpenLP Developers *
|
||||
* --------------------------------------------------------------------------- *
|
||||
* This program 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; version 2 of the License. *
|
||||
* *
|
||||
* This program 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 this program; if not, write to the Free Software Foundation, Inc., 59 *
|
||||
* Temple Place, Suite 330, Boston, MA 02111-1307 USA *
|
||||
******************************************************************************/
|
||||
window.OpenLP = {
|
||||
loadService: function (event) {
|
||||
$.getJSON(
|
||||
"/api/service/list",
|
||||
function (data, status) {
|
||||
OpenLP.nextSong = "";
|
||||
$("#notes").html("");
|
||||
for (idx in data.results.items) {
|
||||
idx = parseInt(idx, 10);
|
||||
if (data.results.items[idx]["selected"]) {
|
||||
$("#notes").html(data.results.items[idx]["notes"].replace(/\n/g, "<br />"));
|
||||
if (data.results.items.length > idx + 1) {
|
||||
OpenLP.nextSong = data.results.items[idx + 1]["title"];
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
OpenLP.updateSlide();
|
||||
}
|
||||
);
|
||||
},
|
||||
loadSlides: function (event) {
|
||||
$.getJSON(
|
||||
"/api/controller/live/text",
|
||||
function (data, status) {
|
||||
OpenLP.currentSlides = data.results.slides;
|
||||
OpenLP.currentSlide = 0;
|
||||
OpenLP.currentTags = Array();
|
||||
var div = $("#verseorder");
|
||||
div.html("");
|
||||
var tag = "";
|
||||
var tags = 0;
|
||||
var lastChange = 0;
|
||||
$.each(data.results.slides, function(idx, slide) {
|
||||
var prevtag = tag;
|
||||
tag = slide["tag"];
|
||||
if (tag != prevtag) {
|
||||
// If the tag has changed, add new one to the list
|
||||
lastChange = idx;
|
||||
tags = tags + 1;
|
||||
div.append(" <span>");
|
||||
$("#verseorder span").last().attr("id", "tag" + tags).text(tag);
|
||||
}
|
||||
else {
|
||||
if ((slide["text"] == data.results.slides[lastChange]["text"]) &&
|
||||
(data.results.slides.length >= idx + (idx - lastChange))) {
|
||||
// If the tag hasn't changed, check to see if the same verse
|
||||
// has been repeated consecutively. Note the verse may have been
|
||||
// split over several slides, so search through. If so, repeat the tag.
|
||||
var match = true;
|
||||
for (var idx2 = 0; idx2 < idx - lastChange; idx2++) {
|
||||
if(data.results.slides[lastChange + idx2]["text"] != data.results.slides[idx + idx2]["text"]) {
|
||||
match = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (match) {
|
||||
lastChange = idx;
|
||||
tags = tags + 1;
|
||||
div.append(" <span>");
|
||||
$("#verseorder span").last().attr("id", "tag" + tags).text(tag);
|
||||
}
|
||||
}
|
||||
}
|
||||
OpenLP.currentTags[idx] = tags;
|
||||
if (slide["selected"])
|
||||
OpenLP.currentSlide = idx;
|
||||
})
|
||||
OpenLP.loadService();
|
||||
}
|
||||
);
|
||||
},
|
||||
updateSlide: function() {
|
||||
// Show the current slide on top. Any trailing slides for the same verse
|
||||
// are shown too underneath in grey.
|
||||
// Then leave a blank line between following verses
|
||||
$("#verseorder span").removeClass("currenttag");
|
||||
$("#tag" + OpenLP.currentTags[OpenLP.currentSlide]).addClass("currenttag");
|
||||
var slide = OpenLP.currentSlides[OpenLP.currentSlide];
|
||||
var text = "";
|
||||
// use title if available
|
||||
if (slide["title"]) {
|
||||
text = slide["title"];
|
||||
} else {
|
||||
text = slide["text"];
|
||||
}
|
||||
// use thumbnail if available
|
||||
if (slide["img"]) {
|
||||
text += "<br /><img src='" + slide["img"].replace("/thumbnails/", "/thumbnails320x240/") + "'><br />";
|
||||
}
|
||||
// use notes if available
|
||||
if (slide["slide_notes"]) {
|
||||
text += '<br />' + slide["slide_notes"];
|
||||
}
|
||||
text = text.replace(/\n/g, "<br />");
|
||||
$("#currentslide").html(text);
|
||||
text = "";
|
||||
if (OpenLP.currentSlide < OpenLP.currentSlides.length - 1) {
|
||||
for (var idx = OpenLP.currentSlide + 1; idx < OpenLP.currentSlides.length; idx++) {
|
||||
if (OpenLP.currentTags[idx] != OpenLP.currentTags[idx - 1])
|
||||
text = text + "<p class=\"nextslide\">";
|
||||
if (OpenLP.currentSlides[idx]["title"]) {
|
||||
text = text + OpenLP.currentSlides[idx]["title"];
|
||||
} else {
|
||||
text = text + OpenLP.currentSlides[idx]["text"];
|
||||
}
|
||||
if (OpenLP.currentTags[idx] != OpenLP.currentTags[idx - 1])
|
||||
text = text + "</p>";
|
||||
else
|
||||
text = text + "<br />";
|
||||
}
|
||||
text = text.replace(/\n/g, "<br />");
|
||||
$("#nextslide").html(text);
|
||||
}
|
||||
else {
|
||||
text = "<p class=\"nextslide\">" + $("#next-text").val() + ": " + OpenLP.nextSong + "</p>";
|
||||
$("#nextslide").html(text);
|
||||
}
|
||||
},
|
||||
updateClock: function() {
|
||||
var div = $("#clock");
|
||||
var t = new Date();
|
||||
var h = t.getHours();
|
||||
if (OpenLP.twelve && h > 12)
|
||||
h = h - 12;
|
||||
var m = t.getMinutes();
|
||||
if (m < 10)
|
||||
m = '0' + m + '';
|
||||
div.html(h + ":" + m);
|
||||
},
|
||||
pollServer: function () {
|
||||
if ("WebSocket" in window) {
|
||||
// Let us open a web socket
|
||||
var ws = new WebSocket('ws://' + location.hostname + ':4317/poll');
|
||||
ws.binaryType = 'arraybuffer';
|
||||
ws.onmessage = function (evt) {
|
||||
var msg = JSON.parse(String.fromCharCode.apply(null, new Uint8Array(evt.data)));
|
||||
OpenLP.twelve = msg.results.twelve;
|
||||
OpenLP.updateClock();
|
||||
if (OpenLP.currentItem != msg.results.item ||
|
||||
OpenLP.currentService != msg.results.service) {
|
||||
OpenLP.currentItem = msg.results.item;
|
||||
OpenLP.currentService = msg.results.service;
|
||||
OpenLP.loadSlides();
|
||||
}
|
||||
else if (OpenLP.currentSlide != msg.results.slide) {
|
||||
OpenLP.currentSlide = parseInt(msg.results.slide, 10);
|
||||
OpenLP.updateSlide();
|
||||
}
|
||||
}
|
||||
} else {
|
||||
// The browser doesn't support WebSocket
|
||||
alert("WebSocket NOT supported by your Browser!");
|
||||
}
|
||||
},
|
||||
};
|
||||
$.ajaxSetup({ cache: false });
|
||||
setInterval("OpenLP.updateClock();", 1000);
|
||||
OpenLP.pollServer();
|
||||
OpenLP.updateClock();
|
@ -46,14 +46,12 @@ class HttpWorker(QtCore.QObject):
|
||||
|
||||
:param server: The http server class.
|
||||
"""
|
||||
print("http init")
|
||||
super(HttpWorker, self).__init__()
|
||||
|
||||
def run(self):
|
||||
"""
|
||||
Run the thread.
|
||||
"""
|
||||
print("runnnn")
|
||||
serve(application, host='0.0.0.0', port=4318)
|
||||
|
||||
def stop(self):
|
||||
|
@ -69,7 +69,8 @@ def _make_response(view_result):
|
||||
"""
|
||||
Create a Response object from response
|
||||
"""
|
||||
print(view_result)
|
||||
print("##")
|
||||
print(type(view_result))
|
||||
if isinstance(view_result, Response):
|
||||
return view_result
|
||||
elif isinstance(view_result, tuple):
|
||||
@ -86,6 +87,9 @@ def _make_response(view_result):
|
||||
elif isinstance(view_result, dict):
|
||||
return Response(body=json.dumps(view_result), status=200,
|
||||
content_type='application/json', charset='utf8')
|
||||
elif isinstance(view_result, str):
|
||||
return Response(body=view_result, status=200,
|
||||
content_type='text/html', charset='utf8')
|
||||
|
||||
|
||||
def _handle_exception(error):
|
||||
@ -116,6 +120,7 @@ class WSGIApplication(object):
|
||||
Add a route
|
||||
"""
|
||||
route_regex = _route_to_regex(route)
|
||||
print("###", route, route_regex)
|
||||
if route_regex not in self.route_map:
|
||||
self.route_map[route_regex] = {}
|
||||
self.route_map[route_regex][method.upper()] = view_func
|
||||
@ -124,23 +129,36 @@ class WSGIApplication(object):
|
||||
"""
|
||||
Add a static directory as a route
|
||||
"""
|
||||
if not route in self.static_routes:
|
||||
if route not in self.static_routes:
|
||||
self.static_routes[route] = DirectoryApp(os.path.abspath(static_dir))
|
||||
|
||||
def dispatch(self, request):
|
||||
"""
|
||||
Find the appropriate URL and run the view function
|
||||
"""
|
||||
# We are not interested in this so discard
|
||||
print("rrr",request.path)
|
||||
if '/favicon.ico' in request.path:
|
||||
return
|
||||
# First look to see if this is a static file request
|
||||
for route, static_app in self.static_routes.items():
|
||||
print(route, request.path)
|
||||
if re.match(route, request.path):
|
||||
print("matched")
|
||||
# Pop the path info twice in order to get rid of the "/<plugin>/static"
|
||||
request.path_info_pop()
|
||||
# request.path_info_pop()
|
||||
request.path_info_pop()
|
||||
return request.get_response(static_app)
|
||||
# If not a static route, try the views
|
||||
for route, views in self.route_map.items():
|
||||
match = re.match(route, request.path)
|
||||
path = request.path
|
||||
# /api is legacy so we need to handle backwards compatibility
|
||||
if path.startswith('/api'):
|
||||
path = path[4:]
|
||||
print("MMMATCHED")
|
||||
print(route, request.path, path)
|
||||
match = re.match(route, path)
|
||||
print(match)
|
||||
if match and request.method.upper() in views:
|
||||
kwargs = match.groupdict()
|
||||
log.debug('Found {method} {url}'.format(method=request.method, url=request.path))
|
||||
|
@ -47,7 +47,6 @@ class WebSocketWorker(QtCore.QObject):
|
||||
|
||||
:param server: The http server class.
|
||||
"""
|
||||
print("ws init")
|
||||
self.ws_server = server
|
||||
super(WebSocketWorker, self).__init__()
|
||||
|
||||
@ -55,7 +54,6 @@ class WebSocketWorker(QtCore.QObject):
|
||||
"""
|
||||
Run the thread.
|
||||
"""
|
||||
print("ws run")
|
||||
self.ws_server.start_server()
|
||||
|
||||
def stop(self):
|
||||
@ -127,7 +125,7 @@ class WebSocketServer(RegistryProperties, OpenLPMixin):
|
||||
log.debug("web socket handler registered with client")
|
||||
previous_poll = None
|
||||
previous_main_poll = None
|
||||
poller = Registry().get('Poller')
|
||||
poller = Registry().get('poller')
|
||||
# TODO: FIXME: These URLs need to be named better
|
||||
if path == '/poll':
|
||||
while True:
|
||||
@ -143,12 +141,3 @@ class WebSocketServer(RegistryProperties, OpenLPMixin):
|
||||
yield from request.send(main_poll)
|
||||
previous_main_poll = main_poll
|
||||
yield from asyncio.sleep(0.2)
|
||||
|
||||
def stop_server(self):
|
||||
"""
|
||||
Stop the server
|
||||
"""
|
||||
if self.http_thread.isRunning():
|
||||
self.http_thread.stop()
|
||||
self.httpd = None
|
||||
log.debug('Stopped the server.')
|
||||
|
@ -359,7 +359,7 @@ class HttpRouter(RegistryProperties, OpenLPMixin):
|
||||
log.debug('serve file request {name}'.format(name=file_name))
|
||||
parts = file_name.split('/')
|
||||
if len(parts) == 1:
|
||||
file_name = os.path.join(parts[0], 'stage.html')
|
||||
file_name = os.path.join(parts[0], 'stage.mako')
|
||||
elif len(parts) == 3:
|
||||
file_name = os.path.join(parts[1], parts[2])
|
||||
path = os.path.normpath(os.path.join(self.config_dir, file_name))
|
||||
@ -406,7 +406,7 @@ class HttpRouter(RegistryProperties, OpenLPMixin):
|
||||
"""
|
||||
log.debug('serve file request {name}'.format(name=file_name))
|
||||
if not file_name:
|
||||
file_name = 'index.html'
|
||||
file_name = 'index.mako'
|
||||
if '.' not in file_name:
|
||||
file_name += '.html'
|
||||
if file_name.startswith('/'):
|
||||
|
@ -369,7 +369,7 @@ class TestRouter(TestCase, TestMixin):
|
||||
|
||||
def remote_stage_personal_html_test(self):
|
||||
"""
|
||||
Test the stage url with a parameter after loaded a url/stage.html file
|
||||
Test the stage url with a parameter after loaded a url/stage.mako file
|
||||
"""
|
||||
# GIVEN: initial route
|
||||
self.router.config_dir = ''
|
||||
@ -383,7 +383,7 @@ class TestRouter(TestCase, TestMixin):
|
||||
self.router.stages('stages', 'trb')
|
||||
|
||||
# THEN: we should use the specific stage file instance
|
||||
self.router._process_file.assert_called_with(os.path.join('trb', 'stage.html'))
|
||||
self.router._process_file.assert_called_with(os.path.join('trb', 'stage.mako'))
|
||||
|
||||
def remote_stage_personal_css_test(self):
|
||||
"""
|
||||
|