From dec1aa6720e217c82d35522eccc79b23ae8918e7 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sun, 3 Jan 2016 18:01:44 +0100 Subject: [PATCH 01/73] Started on chords support --- openlp/core/common/settings.py | 9 +- openlp/core/lib/__init__.py | 32 +++++- openlp/core/lib/renderer.py | 4 +- openlp/core/lib/serviceitem.py | 16 ++- openlp/plugins/remotes/html/stage.css | 88 +++++++++++++-- openlp/plugins/remotes/html/stage.html | 8 +- openlp/plugins/remotes/html/stage.js | 131 ++++++++++++++++++++++- openlp/plugins/remotes/lib/httprouter.py | 8 +- openlp/plugins/songs/lib/mediaitem.py | 3 + openlp/plugins/songs/songsplugin.py | 5 +- 10 files changed, 274 insertions(+), 30 deletions(-) diff --git a/openlp/core/common/settings.py b/openlp/core/common/settings.py index 56a48319a..13ca5fb8f 100644 --- a/openlp/core/common/settings.py +++ b/openlp/core/common/settings.py @@ -252,7 +252,8 @@ class Settings(QtCore.QSettings): 'shortcuts/blankScreen': [QtGui.QKeySequence(QtCore.Qt.Key_Period)], 'shortcuts/collapse': [QtGui.QKeySequence(QtCore.Qt.Key_Minus)], 'shortcuts/desktopScreen': [QtGui.QKeySequence(QtCore.Qt.Key_D)], - 'shortcuts/delete': [QtGui.QKeySequence(QtGui.QKeySequence.Delete), QtGui.QKeySequence(QtCore.Qt.Key_Delete)], + 'shortcuts/delete': [QtGui.QKeySequence(QtGui.QKeySequence.Delete), + QtGui.QKeySequence(QtCore.Qt.Key_Delete)], 'shortcuts/down': [QtGui.QKeySequence(QtCore.Qt.Key_Down)], 'shortcuts/editSong': [], 'shortcuts/escapeItem': [QtGui.QKeySequence(QtCore.Qt.Key_Escape)], @@ -329,7 +330,8 @@ class Settings(QtCore.QSettings): 'shortcuts/moveBottom': [QtGui.QKeySequence(QtCore.Qt.Key_End)], 'shortcuts/moveDown': [QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], 'shortcuts/nextTrackItem': [], - 'shortcuts/nextItem_live': [QtGui.QKeySequence(QtCore.Qt.Key_Down), QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], + 'shortcuts/nextItem_live': [QtGui.QKeySequence(QtCore.Qt.Key_Down), + QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], 'shortcuts/nextItem_preview': [QtGui.QKeySequence(QtCore.Qt.Key_Down), QtGui.QKeySequence(QtCore.Qt.Key_PageDown)], 'shortcuts/nextService': [QtGui.QKeySequence(QtCore.Qt.Key_Right)], @@ -339,7 +341,8 @@ class Settings(QtCore.QSettings): QtGui.QKeySequence(QtCore.Qt.ALT + QtCore.Qt.Key_F1)], 'shortcuts/openService': [], 'shortcuts/saveService': [], - 'shortcuts/previousItem_live': [QtGui.QKeySequence(QtCore.Qt.Key_Up), QtGui.QKeySequence(QtCore.Qt.Key_PageUp)], + 'shortcuts/previousItem_live': [QtGui.QKeySequence(QtCore.Qt.Key_Up), + QtGui.QKeySequence(QtCore.Qt.Key_PageUp)], 'shortcuts/playbackPause': [], 'shortcuts/playbackPlay': [], 'shortcuts/playbackStop': [], diff --git a/openlp/core/lib/__init__.py b/openlp/core/lib/__init__.py index a6a3c6efe..d2192f711 100644 --- a/openlp/core/lib/__init__.py +++ b/openlp/core/lib/__init__.py @@ -27,6 +27,7 @@ OpenLP work. from distutils.version import LooseVersion import logging import os +import re from PyQt5 import QtCore, QtGui, Qt, QtWidgets @@ -258,11 +259,12 @@ def check_item_selected(list_widget, message): return True -def clean_tags(text): +def clean_tags(text, chords=False): """ Remove Tags from text for display :param text: Text to be cleaned + :param chords: Clean ChordPro tags """ text = text.replace('
', '\n') text = text.replace('{br}', '\n') @@ -270,21 +272,47 @@ def clean_tags(text): for tag in FormattingTags.get_html_tags(): text = text.replace(tag['start tag'], '') text = text.replace(tag['end tag'], '') + # Remove ChordPro tags + if chords: + text = re.sub(r'\[.+?\]', r'', text) return text -def expand_tags(text): +def expand_tags(text, chords=False): """ Expand tags HTML for display :param text: The text to be expanded. + :param chords: Convert ChordPro tags to html """ + if chords: + text = expand_chords(text) for tag in FormattingTags.get_html_tags(): text = text.replace(tag['start tag'], tag['start html']) text = text.replace(tag['end tag'], tag['end html']) return text +def expand_chords(text): + """ + Expand ChordPro tags + + :param text: + """ + text_lines = text.split('{br}') + expanded_text_lines = [] + for line in text_lines: + # If a ChordPro is detected in the line, replace it with a html-span tag and wrap the line in a span tag. + if '[' in line and ']' in line: + new_line = '' + new_line += re.sub(r'(.*?)\[(.+?)\](.*?)', r'\1\3', line) + new_line += '' + expanded_text_lines.append(new_line) + else: + expanded_text_lines.append(line) + return '{br}'.join(expanded_text_lines) + + def create_separated_list(string_list): """ Returns a string that represents a join of a list of strings with a localized separator. This function corresponds diff --git a/openlp/core/lib/renderer.py b/openlp/core/lib/renderer.py index 74922b78d..1378b6742 100644 --- a/openlp/core/lib/renderer.py +++ b/openlp/core/lib/renderer.py @@ -254,11 +254,11 @@ class Renderer(OpenLPMixin, RegistryMixin, RegistryProperties): # If there are (at least) two occurrences of [---] we use the first two slides (and neglect the last # for now). if len(slides) == 3: - html_text = expand_tags('\n'.join(slides[:2])) + html_text = expand_tags('\n'.join(slides[:2]), item.is_capable(ItemCapabilities.HasChords)) # We check both slides to determine if the optional split is needed (there is only one optional # split). else: - html_text = expand_tags('\n'.join(slides)) + html_text = expand_tags('\n'.join(slides), item.is_capable(ItemCapabilities.HasChords)) html_text = html_text.replace('\n', '
') if self._text_fits_on_slide(html_text): # The first two optional slides fit (as a whole) on one slide. Replace the first occurrence diff --git a/openlp/core/lib/serviceitem.py b/openlp/core/lib/serviceitem.py index c99229f7a..a4ea2b9c1 100644 --- a/openlp/core/lib/serviceitem.py +++ b/openlp/core/lib/serviceitem.py @@ -34,7 +34,7 @@ import ntpath from PyQt5 import QtGui from openlp.core.common import RegistryProperties, Settings, translate, AppLocation, md5_hash -from openlp.core.lib import ImageSource, build_icon, clean_tags, expand_tags, create_thumb +from openlp.core.lib import ImageSource, build_icon, clean_tags, expand_tags, expand_chords log = logging.getLogger(__name__) @@ -118,6 +118,8 @@ class ItemCapabilities(object): ``HasThumbnails`` The item has related thumbnails available + ``HasChords`` + The item has chords - only for songs """ CanPreview = 1 CanEdit = 2 @@ -140,6 +142,7 @@ class ItemCapabilities(object): HasDisplayTitle = 19 HasNotes = 20 HasThumbnails = 21 + HasChords = 22 class ServiceItem(RegistryProperties): @@ -260,13 +263,16 @@ class ServiceItem(RegistryProperties): previous_pages[verse_tag] = (slide['raw_slide'], pages) for page in pages: page = page.replace('
', '{br}') - html_data = expand_tags(html.escape(page.rstrip())) - self._display_frames.append({ + html_data = expand_tags(html.escape(page.rstrip()), self.is_capable(ItemCapabilities.HasChords)) + new_frame = { 'title': clean_tags(page), - 'text': clean_tags(page.rstrip()), + 'text': clean_tags(page.rstrip(), self.is_capable(ItemCapabilities.HasChords)), 'html': html_data.replace(' ', ' '), 'verseTag': verse_tag - }) + } + if self.is_capable(ItemCapabilities.HasChords): + new_frame['chords_text'] = expand_chords(clean_tags(page.rstrip())) + self._display_frames.append(new_frame) elif self.service_item_type == ServiceItemType.Image or self.service_item_type == ServiceItemType.Command: pass else: diff --git a/openlp/plugins/remotes/html/stage.css b/openlp/plugins/remotes/html/stage.css index 621722161..7444240d8 100644 --- a/openlp/plugins/remotes/html/stage.css +++ b/openlp/plugins/remotes/html/stage.css @@ -16,22 +16,22 @@ * 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; + font-family: 'Arial Narrow', 'Avenir Next Condensed', sans-serif-condensed, Arial, sans-serif; + font-size: 4.4vw; overflow: hidden; } #currentslide { - font-size: 40pt; - color: white; + font-size: 100%; + color: lightgray; padding-bottom: 0px; } #nextslide { - font-size: 40pt; - color: grey; + font-size: 100%; + color: gray; padding-top: 0px; padding-bottom: 0px; } @@ -41,24 +41,90 @@ body { } #clock { - font-size: 30pt; + font-size: 75%; color: yellow; text-align: right; } #notes { - font-size: 36pt; + font-size: 90%; color: salmon; text-align: right; } +#controls { + display: none; +} + +#chords { + font-size: 50%; + color: gray; + background-color: gray; + color: white; + cursor: pointer; +} + +#header { + height: 1.4em; +} + +#transpose, +#transposevalue, +#capodisplay { + display: inline-block; + font-size: 75%; + color: gray; + vertical-align: middle; +} + +#header .button, +#plus, +#minus { + display: inline-block; + width: 3vw; + line-height: 3vw; + vertical-align: middle; + color: white; + background-color: gray; + font-size: 75%; + text-align: center; + cursor: pointer; +} + #verseorder { - font-size: 30pt; + font-size: 75%; color: green; text-align: left; + line-height: 1.5; + display: inline-block; + vertical-align: middle; } .currenttag { - color: lightgreen; - font-weight: bold; + color: lightgreen; + font-weight: bold; } + +.chordline { + line-height: 2.0; +} + +.chordline1 { + line-height: 1.0 +} + +.chordline span.chord span { + position: relative; +} + +.chordline span.chord span strong { + position: absolute; + top: -1em; + left: 0; + font: 500 75% 'Arial Narrow', 'Avenir Next Condensed', sans-serif-condensed, Arial, sans-serif; + color: yellow; +} + +.nextslide .chordline span.chord span strong { + color: gray; +} \ No newline at end of file diff --git a/openlp/plugins/remotes/html/stage.html b/openlp/plugins/remotes/html/stage.html index be25497bd..e3621f752 100644 --- a/openlp/plugins/remotes/html/stage.html +++ b/openlp/plugins/remotes/html/stage.html @@ -32,9 +32,15 @@ -
+
diff --git a/openlp/plugins/remotes/html/stage.js b/openlp/plugins/remotes/html/stage.js index f82aeecc7..24bf161f5 100644 --- a/openlp/plugins/remotes/html/stage.js +++ b/openlp/plugins/remotes/html/stage.js @@ -16,7 +16,69 @@ * with this program; if not, write to the Free Software Foundation, Inc., 59 * * Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ + var lastChord; + +function getTransposeValue(songId) { + if (localStorage.getItem(songId + '_transposeValue')) {return localStorage.getItem(songId + '_transposeValue');} + else {return 0;} +} + +function storeTransposeValue(songId,transposeValueToSet) { + localStorage.setItem(songId + '_transposeValue', transposeValueToSet); +} + +function transposeChord(chord, transposeValue) { + var chordSplit = chord.replace('♭', 'b').split(/[\/\(\)]/), transposedChord = '', note, notenumber, rest, currentChord, + notesSharp = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','H'], + notesFlat = ['C','Db','D','Eb','Fb','F','Gb','G','Ab','A','B','H'], + notesPreferred = ['b','#','#','#','#','#','#','#','#','#','#','#']; + chordNotes = Array(); + for (i = 0; i <= chordSplit.length - 1; i++) { + if (i > 0) { + transposedChord += '/'; + } + currentchord = chordSplit[i]; + if (currentchord.charAt(0) === '(') { + transposedChord += '('; + if (currentchord.length > 1) { + currentchord = currentchord.substr(1); + } else { + currentchord = ""; + } + } + if (currentchord.length > 0) { + if (currentchord.length > 1) { + if ('#b'.indexOf(currentchord.charAt(1)) === -1) { + note = currentchord.substr(0, 1); + rest = currentchord.substr(1); + } else { + note = currentchord.substr(0, 2); + rest = currentchord.substr(2); + } + } else { + note = currentchord; + rest = ""; + } + notenumber = (notesSharp.indexOf(note) === -1?notesFlat.indexOf(note):notesSharp.indexOf(note)); + notenumber -= parseInt(transposeValue); + while (notenumber > 11) {notenumber -= 12;} + while (notenumber < 0) {notenumber += 12;} + if (i === 0) { + currentChord = notesPreferred[notenumber] === '#' ? notesSharp[notenumber] : notesFlat[notenumber]; + lastChord = currentChord; + }else { + currentChord = notesSharp.indexOf(lastChord) === -1 ? notesFlat[notenumber] : notesSharp[notenumber]; + } + if(!(notesFlat.indexOf(note)===-1 && notesSharp.indexOf(note)===-1)) transposedChord += currentChord + rest; else transposedChord += note + rest; //note+rest; + //transposedChord += currentChord + rest; + } + } + return transposedChord; +} + +var OpenLPChordOverflowFillCount = 0; window.OpenLP = { + showchords:true, loadService: function (event) { $.getJSON( "/api/service/list", @@ -27,6 +89,7 @@ window.OpenLP = { idx = parseInt(idx, 10); if (data.results.items[idx]["selected"]) { $("#notes").html(data.results.items[idx]["notes"].replace(/\n/g, "
")); + $("#songtitle").html(data.results.items[idx]["title"].replace(/\n/g, "
")); if (data.results.items.length > idx + 1) { OpenLP.nextSong = data.results.items[idx + 1]["title"]; } @@ -42,6 +105,7 @@ window.OpenLP = { "/api/controller/live/text", function (data, status) { OpenLP.currentSlides = data.results.slides; + $('#transposevalue').text(getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0])); OpenLP.currentSlide = 0; OpenLP.currentTags = Array(); var div = $("#verseorder"); @@ -61,7 +125,7 @@ window.OpenLP = { } else { if ((slide["text"] == data.results.slides[lastChange]["text"]) && - (data.results.slides.length >= idx + (idx - lastChange))) { + (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. @@ -92,6 +156,37 @@ window.OpenLP = { // 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 + var transposeValue = getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0]), + chordclass=/class="[a-z\s]*chord[a-z\s]*"\s*style="display:\s?none"/g, + chordclassshow='class="chord" style="display:inline"', + regchord=/([\(\w#b♭\+\*\d/\)-]+)<\/span>([\u0080-\uFFFF,\w]*)([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(
)?/g, + replaceChords=function(mstr,$1,$2,$3,$4) { +// regchord=/[\[{]([\(\w#b♭\+\*\d/\)-]+)[\]}]<\/span>([\u0080-\uFFFF,\w]*)([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(
)?/g, + var v='', w=''; + var $1len = 0, $2len = 0, slimchars='fiíIÍjlĺľrtť.,;/ ()|"\'!:\\'; + $1 = transposeChord($1, transposeValue); + for (var i = 0; i < $1.length; i++) if (slimchars.indexOf($1.charAt(i)) === -1) {$1len += 2;} else {$1len += 1;} + for (var i = 0; i < $2.length; i++) if (slimchars.indexOf($2.charAt(i)) === -1) {$2len += 2;} else {$2len += 1;} + for (var i = 0; i < $3.length; i++) if (slimchars.indexOf($2.charAt(i)) === -1) {$2len += 2;} else {$2len += 1;} + if ($1len>=$2len && !$4) { + if ($2.length){ + if (!$3.length) { + for (c = 0; c < Math.ceil(($1len - $2len) / 2) + 1; c++) {w += '_';} + } else { + for (c = 0; c < $1len - $2len + 2; c++) {w += ' ';} + } + } else { + if (!$3.length) { + for (c = 0; c < Math.floor(($1len - $2len) / 2) + 1; c++) {w += '_';} + } else { + for (c = 0; c < $1len - $2len + 1; c++) {w += ' ';} + } + }; + } else { + if (!$2 && $3.charAt(0) == ' ') {for (c = 0; c < $1len; c++) {w += ' ';}} + } + return $.grep(['', $1, '', $2, w, $3, '', $4], Boolean).join(''); + }; $("#verseorder span").removeClass("currenttag"); $("#tag" + OpenLP.currentTags[OpenLP.currentSlide]).addClass("currenttag"); var slide = OpenLP.currentSlides[OpenLP.currentSlide]; @@ -101,6 +196,10 @@ window.OpenLP = { text = slide["title"]; } else { text = slide["text"]; + if(OpenLP.showchords) { + text = text.replace(chordclass,chordclassshow); + text = text.replace(regchord, replaceChords); + } } // use thumbnail if available if (slide["img"]) { @@ -121,19 +220,24 @@ window.OpenLP = { text = text + OpenLP.currentSlides[idx]["title"]; } else { text = text + OpenLP.currentSlides[idx]["text"]; + if(OpenLP.showchords) { + text = text.replace(chordclass,chordclassshow); + text = text.replace(regchord, replaceChords); + } } if (OpenLP.currentTags[idx] != OpenLP.currentTags[idx - 1]) text = text + "

"; else text = text + "
"; } - text = text.replace(/\n/g, "
"); + text = text.replace(/\n/g, "
"); $("#nextslide").html(text); } else { text = "

" + $("#next-text").val() + ": " + OpenLP.nextSong + "

"; $("#nextslide").html(text); } + if(!OpenLP.showchords) $(".chordline").toggleClass('chordline1'); }, updateClock: function(data) { var div = $("#clock"); @@ -141,6 +245,7 @@ window.OpenLP = { var h = t.getHours(); if (data.results.twelve && h > 12) h = h - 12; + if (h < 10) h = '0' + h + ''; var m = t.getMinutes(); if (m < 10) m = '0' + m + ''; @@ -151,8 +256,7 @@ window.OpenLP = { "/api/poll", function (data, status) { OpenLP.updateClock(data); - if (OpenLP.currentItem != data.results.item || - OpenLP.currentService != data.results.service) { + if (OpenLP.currentItem != data.results.item || OpenLP.currentService != data.results.service) { OpenLP.currentItem = data.results.item; OpenLP.currentService = data.results.service; OpenLP.loadSlides(); @@ -163,8 +267,27 @@ window.OpenLP = { } } ); +// $('span.chord').each(function(){this.style.display="inline"}); } } $.ajaxSetup({ cache: false }); setInterval("OpenLP.pollServer();", 500); OpenLP.pollServer(); +$(document).ready(function() { + $('#transposeup').click(function(e) { + $('#transposevalue').text(parseInt($('#transposevalue').text()) + 1); + storeTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0], $('#transposevalue').text()); + //alert(getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0])); + //$('body').get(0).style.'font-size' = (parseFloat($('body').css('font-size')) + 0.1) + 'vw'); + OpenLP.loadSlides(); + }); + $('#transposedown').click(function(e) { + $('#transposevalue').text(parseInt($('#transposevalue').text()) - 1); + storeTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0], $('#transposevalue').text()); + OpenLP.loadSlides(); + }); + $("#chords").click(function(){ OpenLP.showchords=OpenLP.showchords?false:true; OpenLP.updateSlide(); }); + $('#plus').click(function() { var fs=$('#currentslide').css('font-size').match(/\d+/); $('#currentslide').css("font-size",+fs+10+"px");$('#nextslide').css("font-size",+fs+10+"px"); } ); + $("#minus").click(function() {var fs=$('#currentslide').css('font-size').match(/\d+/); $('#currentslide').css("font-size",+fs-10+"px");$('#nextslide').css("font-size",+fs-10+"px"); } ); + $('body').hover(function(){ $('#controls').fadeIn(500);},function(){ $('#controls').fadeOut(500);}); +}); diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index 9f6e68506..1ab688351 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -546,8 +546,14 @@ class HttpRouter(RegistryProperties): item['tag'] = str(frame['verseTag']) else: item['tag'] = str(index + 1) - item['text'] = str(frame['text']) + # Use chords if available and enabled + if current_item.is_capable(ItemCapabilities.HasChords): + item['text'] = str(frame['chords_text']) + else: + item['text'] = str(frame['text']) item['html'] = str(frame['html']) + print('text: %s' % item['text']) + print('html: %s' % item['html']) # Handle images, unless a custom thumbnail is given or if thumbnails is disabled elif current_item.is_image() and not frame.get('image', '') and Settings().value('remotes/thumbnails'): item['tag'] = str(index + 1) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index 687aac9ac..d0c6c0619 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -471,6 +471,9 @@ class SongMediaItem(MediaManagerItem): if song.media_files: service_item.add_capability(ItemCapabilities.HasBackgroundAudio) service_item.background_audio = [m.file_name for m in song.media_files] + # If chords are enabled and detected, mark the item as having chords + if Settings().value(self.settings_section + '/chords') and '[' in song.lyrics: + service_item.add_capability(ItemCapabilities.HasChords) return True def generate_footer(self, item, song): diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 670d0d602..2ae4d92b8 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -65,7 +65,10 @@ __default_settings__ = { 'songs/last directory export': '', 'songs/songselect username': '', 'songs/songselect password': '', - 'songs/songselect searches': '' + 'songs/songselect searches': '', + 'songs/chords': True, + 'songs/stageview chords': False, + 'songs/mainview chords': False } From 12c2b5e57888ec81d2650c1cea56bd3e53cde332 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 27 May 2016 08:41:38 +0200 Subject: [PATCH 02/73] Removed leftovers from merge with trunk --- openlp/plugins/remotes/html/stage.css.THIS | 130 --------- openlp/plugins/remotes/html/stage.js.THIS | 293 --------------------- 2 files changed, 423 deletions(-) delete mode 100644 openlp/plugins/remotes/html/stage.css.THIS delete mode 100644 openlp/plugins/remotes/html/stage.js.THIS diff --git a/openlp/plugins/remotes/html/stage.css.THIS b/openlp/plugins/remotes/html/stage.css.THIS deleted file mode 100644 index dafe4aedf..000000000 --- a/openlp/plugins/remotes/html/stage.css.THIS +++ /dev/null @@ -1,130 +0,0 @@ -/****************************************************************************** -* 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: 'Arial Narrow', 'Avenir Next Condensed', sans-serif-condensed, Arial, sans-serif; - font-size: 4.4vw; - overflow: hidden; -} - -#currentslide { - font-size: 100%; - color: lightgray; - padding-bottom: 0px; -} - -#nextslide { - font-size: 100%; - color: gray; - padding-top: 0px; - padding-bottom: 0px; -} - -#right { - float: right; -} - -#clock { - font-size: 75%; - color: yellow; - text-align: right; -} - -#notes { - font-size: 90%; - color: salmon; - text-align: right; -} - -#controls { - display: none; -} - -#chords { - font-size: 50%; - color: gray; - background-color: gray; - color: white; - cursor: pointer; -} - -#header { - height: 1.4em; -} - -#transpose, -#transposevalue, -#capodisplay { - display: inline-block; - font-size: 75%; - color: gray; - vertical-align: middle; -} - -#header .button, -#plus, -#minus { - display: inline-block; - width: 3vw; - line-height: 3vw; - vertical-align: middle; - color: white; - background-color: gray; - font-size: 75%; - text-align: center; - cursor: pointer; -} - -#verseorder { - font-size: 75%; - color: green; - text-align: left; - line-height: 1.5; - display: inline-block; - vertical-align: middle; -} - -.currenttag { - color: lightgreen; - font-weight: bold; -} - -.chordline { - line-height: 2.0; -} - -.chordline1 { - line-height: 1.0 -} - -.chordline span.chord span { - position: relative; -} - -.chordline span.chord span strong { - position: absolute; - top: -1em; - left: 0; - font: 500 75% 'Arial Narrow', 'Avenir Next Condensed', sans-serif-condensed, Arial, sans-serif; - color: yellow; -} - -.nextslide .chordline span.chord span strong { - color: gray; -} \ No newline at end of file diff --git a/openlp/plugins/remotes/html/stage.js.THIS b/openlp/plugins/remotes/html/stage.js.THIS deleted file mode 100644 index 7da9ae840..000000000 --- a/openlp/plugins/remotes/html/stage.js.THIS +++ /dev/null @@ -1,293 +0,0 @@ -/****************************************************************************** - * 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 * - ******************************************************************************/ - var lastChord; - -function getTransposeValue(songId) { - if (localStorage.getItem(songId + '_transposeValue')) {return localStorage.getItem(songId + '_transposeValue');} - else {return 0;} -} - -function storeTransposeValue(songId,transposeValueToSet) { - localStorage.setItem(songId + '_transposeValue', transposeValueToSet); -} - -function transposeChord(chord, transposeValue) { - var chordSplit = chord.replace('♭', 'b').split(/[\/\(\)]/), transposedChord = '', note, notenumber, rest, currentChord, - notesSharp = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','H'], - notesFlat = ['C','Db','D','Eb','Fb','F','Gb','G','Ab','A','B','H'], - notesPreferred = ['b','#','#','#','#','#','#','#','#','#','#','#']; - chordNotes = Array(); - for (i = 0; i <= chordSplit.length - 1; i++) { - if (i > 0) { - transposedChord += '/'; - } - currentchord = chordSplit[i]; - if (currentchord.charAt(0) === '(') { - transposedChord += '('; - if (currentchord.length > 1) { - currentchord = currentchord.substr(1); - } else { - currentchord = ""; - } - } - if (currentchord.length > 0) { - if (currentchord.length > 1) { - if ('#b'.indexOf(currentchord.charAt(1)) === -1) { - note = currentchord.substr(0, 1); - rest = currentchord.substr(1); - } else { - note = currentchord.substr(0, 2); - rest = currentchord.substr(2); - } - } else { - note = currentchord; - rest = ""; - } - notenumber = (notesSharp.indexOf(note) === -1?notesFlat.indexOf(note):notesSharp.indexOf(note)); - notenumber -= parseInt(transposeValue); - while (notenumber > 11) {notenumber -= 12;} - while (notenumber < 0) {notenumber += 12;} - if (i === 0) { - currentChord = notesPreferred[notenumber] === '#' ? notesSharp[notenumber] : notesFlat[notenumber]; - lastChord = currentChord; - }else { - currentChord = notesSharp.indexOf(lastChord) === -1 ? notesFlat[notenumber] : notesSharp[notenumber]; - } - if(!(notesFlat.indexOf(note)===-1 && notesSharp.indexOf(note)===-1)) transposedChord += currentChord + rest; else transposedChord += note + rest; //note+rest; - //transposedChord += currentChord + rest; - } - } - return transposedChord; -} - -var OpenLPChordOverflowFillCount = 0; -window.OpenLP = { - showchords:true, - 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, "
")); - $("#songtitle").html(data.results.items[idx]["title"].replace(/\n/g, "
")); - 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; - $('#transposevalue').text(getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0])); - 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(" "); - $("#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(" "); - $("#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 - var transposeValue = getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0]), - chordclass=/class="[a-z\s]*chord[a-z\s]*"\s*style="display:\s?none"/g, - chordclassshow='class="chord" style="display:inline"', - regchord=/([\(\w#b♭\+\*\d/\)-]+)<\/span>([\u0080-\uFFFF,\w]*)([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(
)?/g, - replaceChords=function(mstr,$1,$2,$3,$4) { -// regchord=/[\[{]([\(\w#b♭\+\*\d/\)-]+)[\]}]<\/span>([\u0080-\uFFFF,\w]*)([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(
)?/g, - var v='', w=''; - var $1len = 0, $2len = 0, slimchars='fiíIÍjlĺľrtť.,;/ ()|"\'!:\\'; - $1 = transposeChord($1, transposeValue); - for (var i = 0; i < $1.length; i++) if (slimchars.indexOf($1.charAt(i)) === -1) {$1len += 2;} else {$1len += 1;} - for (var i = 0; i < $2.length; i++) if (slimchars.indexOf($2.charAt(i)) === -1) {$2len += 2;} else {$2len += 1;} - for (var i = 0; i < $3.length; i++) if (slimchars.indexOf($2.charAt(i)) === -1) {$2len += 2;} else {$2len += 1;} - if ($1len>=$2len && !$4) { - if ($2.length){ - if (!$3.length) { - for (c = 0; c < Math.ceil(($1len - $2len) / 2) + 1; c++) {w += '_';} - } else { - for (c = 0; c < $1len - $2len + 2; c++) {w += ' ';} - } - } else { - if (!$3.length) { - for (c = 0; c < Math.floor(($1len - $2len) / 2) + 1; c++) {w += '_';} - } else { - for (c = 0; c < $1len - $2len + 1; c++) {w += ' ';} - } - }; - } else { - if (!$2 && $3.charAt(0) == ' ') {for (c = 0; c < $1len; c++) {w += ' ';}} - } - return $.grep(['', $1, '', $2, w, $3, '', $4], Boolean).join(''); - }; - $("#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"]; - if(OpenLP.showchords) { - text = text.replace(chordclass,chordclassshow); - text = text.replace(regchord, replaceChords); - } - } - // use thumbnail if available - if (slide["img"]) { - text += "

"; - } - // use notes if available - if (slide["slide_notes"]) { - text += '
' + slide["slide_notes"]; - } - text = text.replace(/\n/g, "
"); - $("#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 + "

"; - if (OpenLP.currentSlides[idx]["title"]) { - text = text + OpenLP.currentSlides[idx]["title"]; - } else { - text = text + OpenLP.currentSlides[idx]["text"]; - if(OpenLP.showchords) { - text = text.replace(chordclass,chordclassshow); - text = text.replace(regchord, replaceChords); - } - } - if (OpenLP.currentTags[idx] != OpenLP.currentTags[idx - 1]) - text = text + "

"; - else - text = text + "
"; - } - text = text.replace(/\n/g, "
"); - $("#nextslide").html(text); - } - else { - text = "

" + $("#next-text").val() + ": " + OpenLP.nextSong + "

"; - $("#nextslide").html(text); - } - if(!OpenLP.showchords) $(".chordline").toggleClass('chordline1'); - }, - updateClock: function(data) { - var div = $("#clock"); - var t = new Date(); - var h = t.getHours(); - if (data.results.twelve && h > 12) - h = h - 12; - if (h < 10) h = '0' + h + ''; - var m = t.getMinutes(); - if (m < 10) - m = '0' + m + ''; - div.html(h + ":" + m); - }, - pollServer: function () { - $.getJSON( - "/api/poll", - function (data, status) { - OpenLP.updateClock(data); - if (OpenLP.currentItem != data.results.item || OpenLP.currentService != data.results.service) { - OpenLP.currentItem = data.results.item; - OpenLP.currentService = data.results.service; - OpenLP.loadSlides(); - } - else if (OpenLP.currentSlide != data.results.slide) { - OpenLP.currentSlide = parseInt(data.results.slide, 10); - OpenLP.updateSlide(); - } - } - ); -// $('span.chord').each(function(){this.style.display="inline"}); - } -} -$.ajaxSetup({ cache: false }); -setInterval("OpenLP.pollServer();", 500); -OpenLP.pollServer(); -$(document).ready(function() { - $('#transposeup').click(function(e) { - $('#transposevalue').text(parseInt($('#transposevalue').text()) + 1); - storeTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0], $('#transposevalue').text()); - //alert(getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0])); - //$('body').get(0).style.'font-size' = (parseFloat($('body').css('font-size')) + 0.1) + 'vw'); - OpenLP.loadSlides(); - }); - $('#transposedown').click(function(e) { - $('#transposevalue').text(parseInt($('#transposevalue').text()) - 1); - storeTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0], $('#transposevalue').text()); - OpenLP.loadSlides(); - }); - $("#chords").click(function(){ OpenLP.showchords=OpenLP.showchords?false:true; OpenLP.updateSlide(); }); - $('#plus').click(function() { var fs=$('#currentslide').css('font-size').match(/\d+/); $('#currentslide').css("font-size",+fs+10+"px");$('#nextslide').css("font-size",+fs+10+"px"); } ); - $("#minus").click(function() {var fs=$('#currentslide').css('font-size').match(/\d+/); $('#currentslide').css("font-size",+fs-10+"px");$('#nextslide').css("font-size",+fs-10+"px"); } ); - $('body').hover(function(){ $('#controls').fadeIn(500);},function(){ $('#controls').fadeOut(500);}); -}); From 374e40e2428155a9e3ee90907ba066ec93bb00a9 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Fri, 27 May 2016 08:45:23 +0200 Subject: [PATCH 03/73] Only show stage chords controls if enabled in settings. --- openlp/plugins/remotes/html/js/stage.js | 35 ++++++++++++++++++++++-- openlp/plugins/remotes/lib/httprouter.py | 3 +- openlp/plugins/songs/songsplugin.py | 6 ++-- 3 files changed, 37 insertions(+), 7 deletions(-) diff --git a/openlp/plugins/remotes/html/js/stage.js b/openlp/plugins/remotes/html/js/stage.js index 7da9ae840..7602b14ac 100644 --- a/openlp/plugins/remotes/html/js/stage.js +++ b/openlp/plugins/remotes/html/js/stage.js @@ -16,8 +16,8 @@ * with this program; if not, write to the Free Software Foundation, Inc., 59 * * Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ - var lastChord; - +var lastChord; + function getTransposeValue(songId) { if (localStorage.getItem(songId + '_transposeValue')) {return localStorage.getItem(songId + '_transposeValue');} else {return 0;} @@ -78,7 +78,8 @@ function transposeChord(chord, transposeValue) { var OpenLPChordOverflowFillCount = 0; window.OpenLP = { - showchords:true, + showchords:false, + stageviewChords:false, loadService: function (event) { $.getJSON( "/api/service/list", @@ -251,11 +252,39 @@ window.OpenLP = { m = '0' + m + ''; div.html(h + ":" + m); }, + stageChords: function(stageviewChords) { + if (stageviewChords != OpenLP.stageviewChords) { + OpenLP.stageviewChords = stageviewChords; + OpenLP.showchords = stageviewChords; + if (!stageviewChords) { + $('#transpose').hide(); + $('#transposedown').hide(); + $('#transposevalue').hide(); + $('#transposeup').hide(); + $('#transposeup').hide(); + $('#capodisplay').hide(); + $('#chords').hide(); + $('#plus').hide(); + $('#minus').hide(); + } else { + $('#transpose').show(); + $('#transposedown').show(); + $('#transposevalue').show(); + $('#transposeup').show(); + $('#transposeup').show(); + $('#capodisplay').show(); + $('#chords').show(); + $('#plus').show(); + $('#minus').show(); + } + } + }, pollServer: function () { $.getJSON( "/api/poll", function (data, status) { OpenLP.updateClock(data); + OpenLP.stageChords(data.results.stageviewChords); if (OpenLP.currentItem != data.results.item || OpenLP.currentService != data.results.service) { OpenLP.currentItem = data.results.item; OpenLP.currentService = data.results.service; diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index 5e17088f3..f553da45d 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -477,7 +477,8 @@ class HttpRouter(RegistryProperties): 'display': self.live_controller.desktop_screen.isChecked(), 'version': 2, 'isSecure': Settings().value(self.settings_section + '/authentication enabled'), - 'isAuthorised': self.authorised + 'isAuthorised': self.authorised, + 'stageviewChords': Settings().value('songs/stageview chords'), } self.do_json_header() return json.dumps({'results': result}).encode() diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index de4acb686..79ffdcc54 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -66,9 +66,9 @@ __default_settings__ = { 'songs/songselect username': '', 'songs/songselect password': '', 'songs/songselect searches': '', - 'songs/chords': True, - 'songs/stageview chords': False, - 'songs/mainview chords': False + 'songs/stageview chords': True, + 'songs/mainview chords': False, + 'songs/disable chords import': False, } From 13dd5322693193b7b6eae837ea7db96d1c14c304 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sat, 28 May 2016 23:11:59 +0200 Subject: [PATCH 04/73] Moved chords to a new web view. --- openlp/plugins/remotes/html/chords.html | 47 ++++ openlp/plugins/remotes/html/css/chords.css | 130 +++++++++ openlp/plugins/remotes/html/css/stage.css | 88 +------ openlp/plugins/remotes/html/js/chords.js | 293 +++++++++++++++++++++ openlp/plugins/remotes/html/js/stage.js | 160 +---------- openlp/plugins/remotes/html/stage.html | 8 +- openlp/plugins/remotes/lib/httprouter.py | 6 +- openlp/plugins/remotes/lib/remotetab.py | 18 ++ openlp/plugins/songs/lib/mediaitem.py | 4 +- openlp/plugins/songs/songsplugin.py | 1 - 10 files changed, 511 insertions(+), 244 deletions(-) create mode 100644 openlp/plugins/remotes/html/chords.html create mode 100644 openlp/plugins/remotes/html/css/chords.css create mode 100644 openlp/plugins/remotes/html/js/chords.js diff --git a/openlp/plugins/remotes/html/chords.html b/openlp/plugins/remotes/html/chords.html new file mode 100644 index 000000000..b8ad05347 --- /dev/null +++ b/openlp/plugins/remotes/html/chords.html @@ -0,0 +1,47 @@ + + + + + + ${chords_title} + + + + + + + + + +
+
+ + diff --git a/openlp/plugins/remotes/html/css/chords.css b/openlp/plugins/remotes/html/css/chords.css new file mode 100644 index 000000000..dafe4aedf --- /dev/null +++ b/openlp/plugins/remotes/html/css/chords.css @@ -0,0 +1,130 @@ +/****************************************************************************** +* 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: 'Arial Narrow', 'Avenir Next Condensed', sans-serif-condensed, Arial, sans-serif; + font-size: 4.4vw; + overflow: hidden; +} + +#currentslide { + font-size: 100%; + color: lightgray; + padding-bottom: 0px; +} + +#nextslide { + font-size: 100%; + color: gray; + padding-top: 0px; + padding-bottom: 0px; +} + +#right { + float: right; +} + +#clock { + font-size: 75%; + color: yellow; + text-align: right; +} + +#notes { + font-size: 90%; + color: salmon; + text-align: right; +} + +#controls { + display: none; +} + +#chords { + font-size: 50%; + color: gray; + background-color: gray; + color: white; + cursor: pointer; +} + +#header { + height: 1.4em; +} + +#transpose, +#transposevalue, +#capodisplay { + display: inline-block; + font-size: 75%; + color: gray; + vertical-align: middle; +} + +#header .button, +#plus, +#minus { + display: inline-block; + width: 3vw; + line-height: 3vw; + vertical-align: middle; + color: white; + background-color: gray; + font-size: 75%; + text-align: center; + cursor: pointer; +} + +#verseorder { + font-size: 75%; + color: green; + text-align: left; + line-height: 1.5; + display: inline-block; + vertical-align: middle; +} + +.currenttag { + color: lightgreen; + font-weight: bold; +} + +.chordline { + line-height: 2.0; +} + +.chordline1 { + line-height: 1.0 +} + +.chordline span.chord span { + position: relative; +} + +.chordline span.chord span strong { + position: absolute; + top: -1em; + left: 0; + font: 500 75% 'Arial Narrow', 'Avenir Next Condensed', sans-serif-condensed, Arial, sans-serif; + color: yellow; +} + +.nextslide .chordline span.chord span strong { + color: gray; +} \ No newline at end of file diff --git a/openlp/plugins/remotes/html/css/stage.css b/openlp/plugins/remotes/html/css/stage.css index dafe4aedf..a0da64ff3 100644 --- a/openlp/plugins/remotes/html/css/stage.css +++ b/openlp/plugins/remotes/html/css/stage.css @@ -16,22 +16,22 @@ * 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: 'Arial Narrow', 'Avenir Next Condensed', sans-serif-condensed, Arial, sans-serif; - font-size: 4.4vw; + font-family: sans-serif; overflow: hidden; } #currentslide { - font-size: 100%; - color: lightgray; + font-size: 40pt; + color: white; padding-bottom: 0px; } #nextslide { - font-size: 100%; - color: gray; + font-size: 40pt; + color: grey; padding-top: 0px; padding-bottom: 0px; } @@ -41,90 +41,24 @@ body { } #clock { - font-size: 75%; + font-size: 30pt; color: yellow; text-align: right; } #notes { - font-size: 90%; + font-size: 36pt; color: salmon; text-align: right; } -#controls { - display: none; -} - -#chords { - font-size: 50%; - color: gray; - background-color: gray; - color: white; - cursor: pointer; -} - -#header { - height: 1.4em; -} - -#transpose, -#transposevalue, -#capodisplay { - display: inline-block; - font-size: 75%; - color: gray; - vertical-align: middle; -} - -#header .button, -#plus, -#minus { - display: inline-block; - width: 3vw; - line-height: 3vw; - vertical-align: middle; - color: white; - background-color: gray; - font-size: 75%; - text-align: center; - cursor: pointer; -} - #verseorder { - font-size: 75%; + font-size: 30pt; color: green; text-align: left; - line-height: 1.5; - display: inline-block; - vertical-align: middle; } .currenttag { - color: lightgreen; - font-weight: bold; + color: lightgreen; + font-weight: bold; } - -.chordline { - line-height: 2.0; -} - -.chordline1 { - line-height: 1.0 -} - -.chordline span.chord span { - position: relative; -} - -.chordline span.chord span strong { - position: absolute; - top: -1em; - left: 0; - font: 500 75% 'Arial Narrow', 'Avenir Next Condensed', sans-serif-condensed, Arial, sans-serif; - color: yellow; -} - -.nextslide .chordline span.chord span strong { - color: gray; -} \ No newline at end of file diff --git a/openlp/plugins/remotes/html/js/chords.js b/openlp/plugins/remotes/html/js/chords.js new file mode 100644 index 000000000..d8716f551 --- /dev/null +++ b/openlp/plugins/remotes/html/js/chords.js @@ -0,0 +1,293 @@ +/****************************************************************************** + * 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 * + ******************************************************************************/ +var lastChord; + +function getTransposeValue(songId) { + if (localStorage.getItem(songId + '_transposeValue')) {return localStorage.getItem(songId + '_transposeValue');} + else {return 0;} +} + +function storeTransposeValue(songId,transposeValueToSet) { + localStorage.setItem(songId + '_transposeValue', transposeValueToSet); +} + +function transposeChord(chord, transposeValue) { + var chordSplit = chord.replace('♭', 'b').split(/[\/\(\)]/), transposedChord = '', note, notenumber, rest, currentChord, + notesSharp = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','H'], + notesFlat = ['C','Db','D','Eb','Fb','F','Gb','G','Ab','A','B','H'], + notesPreferred = ['b','#','#','#','#','#','#','#','#','#','#','#']; + chordNotes = Array(); + for (i = 0; i <= chordSplit.length - 1; i++) { + if (i > 0) { + transposedChord += '/'; + } + currentchord = chordSplit[i]; + if (currentchord.charAt(0) === '(') { + transposedChord += '('; + if (currentchord.length > 1) { + currentchord = currentchord.substr(1); + } else { + currentchord = ""; + } + } + if (currentchord.length > 0) { + if (currentchord.length > 1) { + if ('#b'.indexOf(currentchord.charAt(1)) === -1) { + note = currentchord.substr(0, 1); + rest = currentchord.substr(1); + } else { + note = currentchord.substr(0, 2); + rest = currentchord.substr(2); + } + } else { + note = currentchord; + rest = ""; + } + notenumber = (notesSharp.indexOf(note) === -1?notesFlat.indexOf(note):notesSharp.indexOf(note)); + notenumber -= parseInt(transposeValue); + while (notenumber > 11) {notenumber -= 12;} + while (notenumber < 0) {notenumber += 12;} + if (i === 0) { + currentChord = notesPreferred[notenumber] === '#' ? notesSharp[notenumber] : notesFlat[notenumber]; + lastChord = currentChord; + }else { + currentChord = notesSharp.indexOf(lastChord) === -1 ? notesFlat[notenumber] : notesSharp[notenumber]; + } + if(!(notesFlat.indexOf(note)===-1 && notesSharp.indexOf(note)===-1)) transposedChord += currentChord + rest; else transposedChord += note + rest; //note+rest; + //transposedChord += currentChord + rest; + } + } + return transposedChord; +} + +var OpenLPChordOverflowFillCount = 0; +window.OpenLP = { + showchords:true, + 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, "
")); + $("#songtitle").html(data.results.items[idx]["title"].replace(/\n/g, "
")); + 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; + $('#transposevalue').text(getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0])); + 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(" "); + $("#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(" "); + $("#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 + var transposeValue = getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0]), + chordclass=/class="[a-z\s]*chord[a-z\s]*"\s*style="display:\s?none"/g, + chordclassshow='class="chord" style="display:inline"', + regchord=/([\(\w#b♭\+\*\d/\)-]+)<\/span>([\u0080-\uFFFF,\w]*)([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(
)?/g, + replaceChords=function(mstr,$1,$2,$3,$4) { +// regchord=/[\[{]([\(\w#b♭\+\*\d/\)-]+)[\]}]<\/span>([\u0080-\uFFFF,\w]*)([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(
)?/g, + var v='', w=''; + var $1len = 0, $2len = 0, slimchars='fiíIÍjlĺľrtť.,;/ ()|"\'!:\\'; + $1 = transposeChord($1, transposeValue); + for (var i = 0; i < $1.length; i++) if (slimchars.indexOf($1.charAt(i)) === -1) {$1len += 2;} else {$1len += 1;} + for (var i = 0; i < $2.length; i++) if (slimchars.indexOf($2.charAt(i)) === -1) {$2len += 2;} else {$2len += 1;} + for (var i = 0; i < $3.length; i++) if (slimchars.indexOf($2.charAt(i)) === -1) {$2len += 2;} else {$2len += 1;} + if ($1len>=$2len && !$4) { + if ($2.length){ + if (!$3.length) { + for (c = 0; c < Math.ceil(($1len - $2len) / 2) + 1; c++) {w += '_';} + } else { + for (c = 0; c < $1len - $2len + 2; c++) {w += ' ';} + } + } else { + if (!$3.length) { + for (c = 0; c < Math.floor(($1len - $2len) / 2) + 1; c++) {w += '_';} + } else { + for (c = 0; c < $1len - $2len + 1; c++) {w += ' ';} + } + }; + } else { + if (!$2 && $3.charAt(0) == ' ') {for (c = 0; c < $1len; c++) {w += ' ';}} + } + return $.grep(['', $1, '', $2, w, $3, '', $4], Boolean).join(''); + }; + $("#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"]; + if(OpenLP.showchords) { + text = text.replace(chordclass,chordclassshow); + text = text.replace(regchord, replaceChords); + } + } + // use thumbnail if available + if (slide["img"]) { + text += "

"; + } + // use notes if available + if (slide["slide_notes"]) { + text += '
' + slide["slide_notes"]; + } + text = text.replace(/\n/g, "
"); + $("#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 + "

"; + if (OpenLP.currentSlides[idx]["title"]) { + text = text + OpenLP.currentSlides[idx]["title"]; + } else { + text = text + OpenLP.currentSlides[idx]["text"]; + if(OpenLP.showchords) { + text = text.replace(chordclass,chordclassshow); + text = text.replace(regchord, replaceChords); + } + } + if (OpenLP.currentTags[idx] != OpenLP.currentTags[idx - 1]) + text = text + "

"; + else + text = text + "
"; + } + text = text.replace(/\n/g, "
"); + $("#nextslide").html(text); + } + else { + text = "

" + $("#next-text").val() + ": " + OpenLP.nextSong + "

"; + $("#nextslide").html(text); + } + if(!OpenLP.showchords) $(".chordline").toggleClass('chordline1'); + }, + updateClock: function(data) { + var div = $("#clock"); + var t = new Date(); + var h = t.getHours(); + if (data.results.twelve && h > 12) + h = h - 12; + if (h < 10) h = '0' + h + ''; + var m = t.getMinutes(); + if (m < 10) + m = '0' + m + ''; + div.html(h + ":" + m); + }, + pollServer: function () { + $.getJSON( + "/api/poll", + function (data, status) { + OpenLP.updateClock(data); + if (OpenLP.currentItem != data.results.item || OpenLP.currentService != data.results.service) { + OpenLP.currentItem = data.results.item; + OpenLP.currentService = data.results.service; + OpenLP.loadSlides(); + } + else if (OpenLP.currentSlide != data.results.slide) { + OpenLP.currentSlide = parseInt(data.results.slide, 10); + OpenLP.updateSlide(); + } + } + ); +// $('span.chord').each(function(){this.style.display="inline"}); + } +} +$.ajaxSetup({ cache: false }); +setInterval("OpenLP.pollServer();", 500); +OpenLP.pollServer(); +$(document).ready(function() { + $('#transposeup').click(function(e) { + $('#transposevalue').text(parseInt($('#transposevalue').text()) + 1); + storeTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0], $('#transposevalue').text()); + //alert(getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0])); + //$('body').get(0).style.'font-size' = (parseFloat($('body').css('font-size')) + 0.1) + 'vw'); + OpenLP.loadSlides(); + }); + $('#transposedown').click(function(e) { + $('#transposevalue').text(parseInt($('#transposevalue').text()) - 1); + storeTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0], $('#transposevalue').text()); + OpenLP.loadSlides(); + }); + $("#chords").click(function(){ OpenLP.showchords=OpenLP.showchords?false:true; OpenLP.updateSlide(); }); + $('#plus').click(function() { var fs=$('#currentslide').css('font-size').match(/\d+/); $('#currentslide').css("font-size",+fs+10+"px");$('#nextslide').css("font-size",+fs+10+"px"); } ); + $("#minus").click(function() {var fs=$('#currentslide').css('font-size').match(/\d+/); $('#currentslide').css("font-size",+fs-10+"px");$('#nextslide').css("font-size",+fs-10+"px"); } ); + $('body').hover(function(){ $('#controls').fadeIn(500);},function(){ $('#controls').fadeOut(500);}); +}); diff --git a/openlp/plugins/remotes/html/js/stage.js b/openlp/plugins/remotes/html/js/stage.js index 7602b14ac..df26dbd3f 100644 --- a/openlp/plugins/remotes/html/js/stage.js +++ b/openlp/plugins/remotes/html/js/stage.js @@ -16,70 +16,7 @@ * with this program; if not, write to the Free Software Foundation, Inc., 59 * * Temple Place, Suite 330, Boston, MA 02111-1307 USA * ******************************************************************************/ -var lastChord; - -function getTransposeValue(songId) { - if (localStorage.getItem(songId + '_transposeValue')) {return localStorage.getItem(songId + '_transposeValue');} - else {return 0;} -} - -function storeTransposeValue(songId,transposeValueToSet) { - localStorage.setItem(songId + '_transposeValue', transposeValueToSet); -} - -function transposeChord(chord, transposeValue) { - var chordSplit = chord.replace('♭', 'b').split(/[\/\(\)]/), transposedChord = '', note, notenumber, rest, currentChord, - notesSharp = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','H'], - notesFlat = ['C','Db','D','Eb','Fb','F','Gb','G','Ab','A','B','H'], - notesPreferred = ['b','#','#','#','#','#','#','#','#','#','#','#']; - chordNotes = Array(); - for (i = 0; i <= chordSplit.length - 1; i++) { - if (i > 0) { - transposedChord += '/'; - } - currentchord = chordSplit[i]; - if (currentchord.charAt(0) === '(') { - transposedChord += '('; - if (currentchord.length > 1) { - currentchord = currentchord.substr(1); - } else { - currentchord = ""; - } - } - if (currentchord.length > 0) { - if (currentchord.length > 1) { - if ('#b'.indexOf(currentchord.charAt(1)) === -1) { - note = currentchord.substr(0, 1); - rest = currentchord.substr(1); - } else { - note = currentchord.substr(0, 2); - rest = currentchord.substr(2); - } - } else { - note = currentchord; - rest = ""; - } - notenumber = (notesSharp.indexOf(note) === -1?notesFlat.indexOf(note):notesSharp.indexOf(note)); - notenumber -= parseInt(transposeValue); - while (notenumber > 11) {notenumber -= 12;} - while (notenumber < 0) {notenumber += 12;} - if (i === 0) { - currentChord = notesPreferred[notenumber] === '#' ? notesSharp[notenumber] : notesFlat[notenumber]; - lastChord = currentChord; - }else { - currentChord = notesSharp.indexOf(lastChord) === -1 ? notesFlat[notenumber] : notesSharp[notenumber]; - } - if(!(notesFlat.indexOf(note)===-1 && notesSharp.indexOf(note)===-1)) transposedChord += currentChord + rest; else transposedChord += note + rest; //note+rest; - //transposedChord += currentChord + rest; - } - } - return transposedChord; -} - -var OpenLPChordOverflowFillCount = 0; window.OpenLP = { - showchords:false, - stageviewChords:false, loadService: function (event) { $.getJSON( "/api/service/list", @@ -90,7 +27,6 @@ window.OpenLP = { idx = parseInt(idx, 10); if (data.results.items[idx]["selected"]) { $("#notes").html(data.results.items[idx]["notes"].replace(/\n/g, "
")); - $("#songtitle").html(data.results.items[idx]["title"].replace(/\n/g, "
")); if (data.results.items.length > idx + 1) { OpenLP.nextSong = data.results.items[idx + 1]["title"]; } @@ -106,7 +42,6 @@ window.OpenLP = { "/api/controller/live/text", function (data, status) { OpenLP.currentSlides = data.results.slides; - $('#transposevalue').text(getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0])); OpenLP.currentSlide = 0; OpenLP.currentTags = Array(); var div = $("#verseorder"); @@ -126,7 +61,7 @@ window.OpenLP = { } else { if ((slide["text"] == data.results.slides[lastChange]["text"]) && - (data.results.slides.length > idx + (idx - lastChange))) { + (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. @@ -157,37 +92,6 @@ window.OpenLP = { // 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 - var transposeValue = getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0]), - chordclass=/class="[a-z\s]*chord[a-z\s]*"\s*style="display:\s?none"/g, - chordclassshow='class="chord" style="display:inline"', - regchord=/([\(\w#b♭\+\*\d/\)-]+)<\/span>([\u0080-\uFFFF,\w]*)([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(
)?/g, - replaceChords=function(mstr,$1,$2,$3,$4) { -// regchord=/[\[{]([\(\w#b♭\+\*\d/\)-]+)[\]}]<\/span>([\u0080-\uFFFF,\w]*)([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(
)?/g, - var v='', w=''; - var $1len = 0, $2len = 0, slimchars='fiíIÍjlĺľrtť.,;/ ()|"\'!:\\'; - $1 = transposeChord($1, transposeValue); - for (var i = 0; i < $1.length; i++) if (slimchars.indexOf($1.charAt(i)) === -1) {$1len += 2;} else {$1len += 1;} - for (var i = 0; i < $2.length; i++) if (slimchars.indexOf($2.charAt(i)) === -1) {$2len += 2;} else {$2len += 1;} - for (var i = 0; i < $3.length; i++) if (slimchars.indexOf($2.charAt(i)) === -1) {$2len += 2;} else {$2len += 1;} - if ($1len>=$2len && !$4) { - if ($2.length){ - if (!$3.length) { - for (c = 0; c < Math.ceil(($1len - $2len) / 2) + 1; c++) {w += '_';} - } else { - for (c = 0; c < $1len - $2len + 2; c++) {w += ' ';} - } - } else { - if (!$3.length) { - for (c = 0; c < Math.floor(($1len - $2len) / 2) + 1; c++) {w += '_';} - } else { - for (c = 0; c < $1len - $2len + 1; c++) {w += ' ';} - } - }; - } else { - if (!$2 && $3.charAt(0) == ' ') {for (c = 0; c < $1len; c++) {w += ' ';}} - } - return $.grep(['', $1, '', $2, w, $3, '', $4], Boolean).join(''); - }; $("#verseorder span").removeClass("currenttag"); $("#tag" + OpenLP.currentTags[OpenLP.currentSlide]).addClass("currenttag"); var slide = OpenLP.currentSlides[OpenLP.currentSlide]; @@ -197,10 +101,6 @@ window.OpenLP = { text = slide["title"]; } else { text = slide["text"]; - if(OpenLP.showchords) { - text = text.replace(chordclass,chordclassshow); - text = text.replace(regchord, replaceChords); - } } // use thumbnail if available if (slide["img"]) { @@ -221,24 +121,19 @@ window.OpenLP = { text = text + OpenLP.currentSlides[idx]["title"]; } else { text = text + OpenLP.currentSlides[idx]["text"]; - if(OpenLP.showchords) { - text = text.replace(chordclass,chordclassshow); - text = text.replace(regchord, replaceChords); - } } if (OpenLP.currentTags[idx] != OpenLP.currentTags[idx - 1]) text = text + "

"; else text = text + "
"; } - text = text.replace(/\n/g, "
"); + text = text.replace(/\n/g, "
"); $("#nextslide").html(text); } else { text = "

" + $("#next-text").val() + ": " + OpenLP.nextSong + "

"; $("#nextslide").html(text); } - if(!OpenLP.showchords) $(".chordline").toggleClass('chordline1'); }, updateClock: function(data) { var div = $("#clock"); @@ -246,46 +141,18 @@ window.OpenLP = { var h = t.getHours(); if (data.results.twelve && h > 12) h = h - 12; - if (h < 10) h = '0' + h + ''; var m = t.getMinutes(); if (m < 10) m = '0' + m + ''; div.html(h + ":" + m); }, - stageChords: function(stageviewChords) { - if (stageviewChords != OpenLP.stageviewChords) { - OpenLP.stageviewChords = stageviewChords; - OpenLP.showchords = stageviewChords; - if (!stageviewChords) { - $('#transpose').hide(); - $('#transposedown').hide(); - $('#transposevalue').hide(); - $('#transposeup').hide(); - $('#transposeup').hide(); - $('#capodisplay').hide(); - $('#chords').hide(); - $('#plus').hide(); - $('#minus').hide(); - } else { - $('#transpose').show(); - $('#transposedown').show(); - $('#transposevalue').show(); - $('#transposeup').show(); - $('#transposeup').show(); - $('#capodisplay').show(); - $('#chords').show(); - $('#plus').show(); - $('#minus').show(); - } - } - }, pollServer: function () { $.getJSON( "/api/poll", function (data, status) { OpenLP.updateClock(data); - OpenLP.stageChords(data.results.stageviewChords); - if (OpenLP.currentItem != data.results.item || OpenLP.currentService != data.results.service) { + if (OpenLP.currentItem != data.results.item || + OpenLP.currentService != data.results.service) { OpenLP.currentItem = data.results.item; OpenLP.currentService = data.results.service; OpenLP.loadSlides(); @@ -296,27 +163,8 @@ window.OpenLP = { } } ); -// $('span.chord').each(function(){this.style.display="inline"}); } } $.ajaxSetup({ cache: false }); setInterval("OpenLP.pollServer();", 500); OpenLP.pollServer(); -$(document).ready(function() { - $('#transposeup').click(function(e) { - $('#transposevalue').text(parseInt($('#transposevalue').text()) + 1); - storeTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0], $('#transposevalue').text()); - //alert(getTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0])); - //$('body').get(0).style.'font-size' = (parseFloat($('body').css('font-size')) + 0.1) + 'vw'); - OpenLP.loadSlides(); - }); - $('#transposedown').click(function(e) { - $('#transposevalue').text(parseInt($('#transposevalue').text()) - 1); - storeTransposeValue(OpenLP.currentSlides[0].text.split("\n")[0], $('#transposevalue').text()); - OpenLP.loadSlides(); - }); - $("#chords").click(function(){ OpenLP.showchords=OpenLP.showchords?false:true; OpenLP.updateSlide(); }); - $('#plus').click(function() { var fs=$('#currentslide').css('font-size').match(/\d+/); $('#currentslide').css("font-size",+fs+10+"px");$('#nextslide').css("font-size",+fs+10+"px"); } ); - $("#minus").click(function() {var fs=$('#currentslide').css('font-size').match(/\d+/); $('#currentslide').css("font-size",+fs-10+"px");$('#nextslide').css("font-size",+fs-10+"px"); } ); - $('body').hover(function(){ $('#controls').fadeIn(500);},function(){ $('#controls').fadeOut(500);}); -}); diff --git a/openlp/plugins/remotes/html/stage.html b/openlp/plugins/remotes/html/stage.html index ac830e62b..e0ef27575 100644 --- a/openlp/plugins/remotes/html/stage.html +++ b/openlp/plugins/remotes/html/stage.html @@ -32,15 +32,9 @@ - +
diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index f553da45d..69a58379f 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -151,6 +151,7 @@ class HttpRouter(RegistryProperties): ('^/$', {'function': self.serve_file, 'secure': False}), ('^/(stage)$', {'function': self.serve_file, 'secure': False}), ('^/(stage)/(.*)$', {'function': self.stages, 'secure': False}), + ('^/(chords)$', {'function': self.serve_file, 'secure': False}), ('^/(main)$', {'function': self.serve_file, 'secure': False}), (r'^/(\w+)/thumbnails([^/]+)?/(.*)$', {'function': self.serve_thumbnail, 'secure': False}), (r'^/api/poll$', {'function': self.poll, 'secure': False}), @@ -313,10 +314,12 @@ class HttpRouter(RegistryProperties): """ remote = translate('RemotePlugin.Mobile', 'Remote') stage = translate('RemotePlugin.Mobile', 'Stage View') + chords = translate('RemotePlugin.Mobile', 'Chords View') live = translate('RemotePlugin.Mobile', 'Live View') self.template_vars = { 'app_title': "%s %s" % (UiStrings().OLPV2x, remote), 'stage_title': "%s %s" % (UiStrings().OLPV2x, stage), + 'chords_title': "%s %s" % (UiStrings().OLPV2x, chords), 'live_title': "%s %s" % (UiStrings().OLPV2x, live), 'service_manager': translate('RemotePlugin.Mobile', 'Service Manager'), 'slide_controller': translate('RemotePlugin.Mobile', 'Slide Controller'), @@ -403,6 +406,8 @@ class HttpRouter(RegistryProperties): file_name = 'index.html' elif file_name == 'stage': file_name = 'stage.html' + elif file_name == 'chords': + file_name = 'chords.html' elif file_name == 'main': file_name = 'main.html' if file_name.startswith('/'): @@ -478,7 +483,6 @@ class HttpRouter(RegistryProperties): 'version': 2, 'isSecure': Settings().value(self.settings_section + '/authentication enabled'), 'isAuthorised': self.authorised, - 'stageviewChords': Settings().value('songs/stageview chords'), } self.do_json_header() return json.dumps({'results': result}).encode() diff --git a/openlp/plugins/remotes/lib/remotetab.py b/openlp/plugins/remotes/lib/remotetab.py index 76ee65571..bf27c9bed 100644 --- a/openlp/plugins/remotes/lib/remotetab.py +++ b/openlp/plugins/remotes/lib/remotetab.py @@ -81,6 +81,12 @@ class RemoteTab(SettingsTab): self.stage_url.setObjectName('stage_url') self.stage_url.setOpenExternalLinks(True) self.http_setting_layout.addRow(self.stage_url_label, self.stage_url) + self.chords_url_label = QtWidgets.QLabel(self.http_settings_group_box) + self.chords_url_label.setObjectName('chords_url_label') + self.chords_url = QtWidgets.QLabel(self.http_settings_group_box) + self.chords_url.setObjectName('chords_url') + self.chords_url.setOpenExternalLinks(True) + self.http_setting_layout.addRow(self.chords_url_label, self.chords_url) self.live_url_label = QtWidgets.QLabel(self.http_settings_group_box) self.live_url_label.setObjectName('live_url_label') self.live_url = QtWidgets.QLabel(self.http_settings_group_box) @@ -117,6 +123,12 @@ class RemoteTab(SettingsTab): self.stage_https_url.setObjectName('stage_https_url') self.stage_https_url.setOpenExternalLinks(True) self.https_settings_layout.addRow(self.stage_https_url_label, self.stage_https_url) + self.chords_https_url_label = QtWidgets.QLabel(self.http_settings_group_box) + self.chords_https_url_label.setObjectName('chords_https_url_label') + self.chords_https_url = QtWidgets.QLabel(self.https_settings_group_box) + self.chords_https_url.setObjectName('chords_https_url') + self.chords_https_url.setOpenExternalLinks(True) + self.https_settings_layout.addRow(self.chords_https_url_label, self.chords_https_url) self.live_https_url_label = QtWidgets.QLabel(self.https_settings_group_box) self.live_https_url_label.setObjectName('live_url_label') self.live_https_url = QtWidgets.QLabel(self.https_settings_group_box) @@ -171,6 +183,7 @@ class RemoteTab(SettingsTab): self.port_label.setText(translate('RemotePlugin.RemoteTab', 'Port number:')) self.remote_url_label.setText(translate('RemotePlugin.RemoteTab', 'Remote URL:')) self.stage_url_label.setText(translate('RemotePlugin.RemoteTab', 'Stage view URL:')) + self.chords_url_label.setText(translate('RemotePlugin.RemoteTab', 'Chords view URL:')) self.live_url_label.setText(translate('RemotePlugin.RemoteTab', 'Live view URL:')) self.twelve_hour_check_box.setText(translate('RemotePlugin.RemoteTab', 'Display stage time in 12h format')) self.thumbnails_check_box.setText(translate('RemotePlugin.RemoteTab', @@ -187,6 +200,7 @@ class RemoteTab(SettingsTab): self.https_port_label.setText(self.port_label.text()) self.remote_https_url_label.setText(self.remote_url_label.text()) self.stage_https_url_label.setText(self.stage_url_label.text()) + self.chords_https_url_label.setText(self.chords_url_label.text()) self.live_https_url_label.setText(self.live_url_label.text()) self.user_login_group_box.setTitle(translate('RemotePlugin.RemoteTab', 'User Authentication')) self.user_id_label.setText(translate('RemotePlugin.RemoteTab', 'User id:')) @@ -205,6 +219,10 @@ class RemoteTab(SettingsTab): https_url_temp = https_url + 'stage' self.stage_url.setText('%s' % (http_url_temp, http_url_temp)) self.stage_https_url.setText('%s' % (https_url_temp, https_url_temp)) + http_url_temp = http_url + 'chords' + https_url_temp = https_url + 'chords' + self.chords_url.setText('%s' % (http_url_temp, http_url_temp)) + self.chords_https_url.setText('%s' % (https_url_temp, https_url_temp)) http_url_temp = http_url + 'main' https_url_temp = https_url + 'main' self.live_url.setText('%s' % (http_url_temp, http_url_temp)) diff --git a/openlp/plugins/songs/lib/mediaitem.py b/openlp/plugins/songs/lib/mediaitem.py index ebac5aa7b..6f88ef051 100644 --- a/openlp/plugins/songs/lib/mediaitem.py +++ b/openlp/plugins/songs/lib/mediaitem.py @@ -578,8 +578,8 @@ class SongMediaItem(MediaManagerItem): if song.media_files: service_item.add_capability(ItemCapabilities.HasBackgroundAudio) service_item.background_audio = [m.file_name for m in song.media_files] - # If chords are enabled and detected, mark the item as having chords - if Settings().value(self.settings_section + '/chords') and '[' in song.lyrics: + # If chords are detected, mark the item as having chords + if '[' in song.lyrics: service_item.add_capability(ItemCapabilities.HasChords) return True diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index 79ffdcc54..eeb77620f 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -66,7 +66,6 @@ __default_settings__ = { 'songs/songselect username': '', 'songs/songselect password': '', 'songs/songselect searches': '', - 'songs/stageview chords': True, 'songs/mainview chords': False, 'songs/disable chords import': False, } From d9510625eb4341bd5d8776830ab0e2bb497602ad Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Sat, 28 May 2016 23:53:49 +0200 Subject: [PATCH 05/73] Started implementing support for multiple notations, for now english, german and neo-latin is supported. --- openlp/plugins/remotes/html/js/chords.js | 19 +++++++++++++++---- openlp/plugins/remotes/lib/httprouter.py | 3 +-- openlp/plugins/songs/songsplugin.py | 1 + 3 files changed, 17 insertions(+), 6 deletions(-) diff --git a/openlp/plugins/remotes/html/js/chords.js b/openlp/plugins/remotes/html/js/chords.js index d8716f551..0d6acccfe 100644 --- a/openlp/plugins/remotes/html/js/chords.js +++ b/openlp/plugins/remotes/html/js/chords.js @@ -18,6 +18,16 @@ ******************************************************************************/ var lastChord; +var notesSharpNotation = {} +var notesFlatNotation = {} + +notesSharpNotation['german'] = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','H']; +notesFlatNotation['german'] = ['C','Db','D','Eb','Fb','F','Gb','G','Ab','A','B','H']; +notesSharpNotation['english'] = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','B']; +notesFlatNotation['english'] = ['C','Db','D','Eb','Fb','F','Gb','G','Ab','A','Bb','B']; +notesSharpNotation['neo-latin'] = ['Do','Do#','Re','Re#','Mi','Fa','Fa#','Sol','Sol#','La','La#','Si']; +notesFlatNotation['neo-latin'] = ['Do','Reb','Re','Mib','Fab','Fa','Solb','Sol','Lab','La','Sib','Si']; + function getTransposeValue(songId) { if (localStorage.getItem(songId + '_transposeValue')) {return localStorage.getItem(songId + '_transposeValue');} else {return 0;} @@ -27,10 +37,10 @@ function storeTransposeValue(songId,transposeValueToSet) { localStorage.setItem(songId + '_transposeValue', transposeValueToSet); } -function transposeChord(chord, transposeValue) { +function transposeChord(chord, transposeValue, notation) { var chordSplit = chord.replace('♭', 'b').split(/[\/\(\)]/), transposedChord = '', note, notenumber, rest, currentChord, - notesSharp = ['C','C#','D','D#','E','F','F#','G','G#','A','A#','H'], - notesFlat = ['C','Db','D','Eb','Fb','F','Gb','G','Ab','A','B','H'], + notesSharp = notesSharpNotation[notation], + notesFlat = notesFlatNotation[notation], notesPreferred = ['b','#','#','#','#','#','#','#','#','#','#','#']; chordNotes = Array(); for (i = 0; i <= chordSplit.length - 1; i++) { @@ -164,7 +174,7 @@ window.OpenLP = { // regchord=/[\[{]([\(\w#b♭\+\*\d/\)-]+)[\]}]<\/span>([\u0080-\uFFFF,\w]*)([\u0080-\uFFFF,\w,\s,\.,\,,\!,\?,\;,\:,\|,\",\',\-,\_]*)(
)?/g, var v='', w=''; var $1len = 0, $2len = 0, slimchars='fiíIÍjlĺľrtť.,;/ ()|"\'!:\\'; - $1 = transposeChord($1, transposeValue); + $1 = transposeChord($1, transposeValue, OpenLP.chordNotation); for (var i = 0; i < $1.length; i++) if (slimchars.indexOf($1.charAt(i)) === -1) {$1len += 2;} else {$1len += 1;} for (var i = 0; i < $2.length; i++) if (slimchars.indexOf($2.charAt(i)) === -1) {$2len += 2;} else {$2len += 1;} for (var i = 0; i < $3.length; i++) if (slimchars.indexOf($2.charAt(i)) === -1) {$2len += 2;} else {$2len += 1;} @@ -256,6 +266,7 @@ window.OpenLP = { "/api/poll", function (data, status) { OpenLP.updateClock(data); + OpenLP.chordNotation = data.results.chordNotation; if (OpenLP.currentItem != data.results.item || OpenLP.currentService != data.results.service) { OpenLP.currentItem = data.results.item; OpenLP.currentService = data.results.service; diff --git a/openlp/plugins/remotes/lib/httprouter.py b/openlp/plugins/remotes/lib/httprouter.py index 69a58379f..11aa4e829 100644 --- a/openlp/plugins/remotes/lib/httprouter.py +++ b/openlp/plugins/remotes/lib/httprouter.py @@ -483,6 +483,7 @@ class HttpRouter(RegistryProperties): 'version': 2, 'isSecure': Settings().value(self.settings_section + '/authentication enabled'), 'isAuthorised': self.authorised, + 'chordNotation': Settings().value('songs/chord notation'), } self.do_json_header() return json.dumps({'results': result}).encode() @@ -560,8 +561,6 @@ class HttpRouter(RegistryProperties): else: item['text'] = str(frame['text']) item['html'] = str(frame['html']) - print('text: %s' % item['text']) - print('html: %s' % item['html']) # Handle images, unless a custom thumbnail is given or if thumbnails is disabled elif current_item.is_image() and not frame.get('image', '') and Settings().value('remotes/thumbnails'): item['tag'] = str(index + 1) diff --git a/openlp/plugins/songs/songsplugin.py b/openlp/plugins/songs/songsplugin.py index eeb77620f..29a2841a6 100644 --- a/openlp/plugins/songs/songsplugin.py +++ b/openlp/plugins/songs/songsplugin.py @@ -66,6 +66,7 @@ __default_settings__ = { 'songs/songselect username': '', 'songs/songselect password': '', 'songs/songselect searches': '', + 'songs/chord notation': 'english', # Can be english, german or neo-latin 'songs/mainview chords': False, 'songs/disable chords import': False, } From 5f36fcbf396d5e3649fc678617415cf025935cd8 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 2 Jun 2016 15:53:30 +0200 Subject: [PATCH 06/73] Added chord settings to the song tab. --- openlp/plugins/songs/lib/songstab.py | 69 ++++++++++++++++++++++++++++ 1 file changed, 69 insertions(+) diff --git a/openlp/plugins/songs/lib/songstab.py b/openlp/plugins/songs/lib/songstab.py index 5a8c18a50..b09f05855 100644 --- a/openlp/plugins/songs/lib/songstab.py +++ b/openlp/plugins/songs/lib/songstab.py @@ -57,6 +57,34 @@ class SongsTab(SettingsTab): self.display_copyright_check_box.setObjectName('copyright_check_box') self.mode_layout.addWidget(self.display_copyright_check_box) self.left_layout.addWidget(self.mode_group_box) + + self.chords_group_box = QtWidgets.QGroupBox(self.left_column) + self.chords_group_box.setObjectName('chords_group_box') + self.chords_layout = QtWidgets.QVBoxLayout(self.chords_group_box) + self.chords_layout.setObjectName('chords_layout') + self.mainview_chords_check_box = QtWidgets.QCheckBox(self.mode_group_box) + self.mainview_chords_check_box.setObjectName('tool_bar_active_check_box') + self.chords_layout.addWidget(self.mainview_chords_check_box) + self.disable_chords_import_check_box = QtWidgets.QCheckBox(self.mode_group_box) + self.disable_chords_import_check_box.setObjectName('tool_bar_active_check_box') + self.chords_layout.addWidget(self.disable_chords_import_check_box) + + # Chords notation + self.chord_notation_label = QtWidgets.QLabel(self.chords_group_box) + self.chord_notation_label.setWordWrap(True) + self.chords_layout.addWidget(self.chord_notation_label) + self.english_notation_radio_button = QtWidgets.QRadioButton(self.chords_group_box) + self.english_notation_radio_button.setObjectName('english_notation_radio_button') + self.chords_layout.addWidget(self.english_notation_radio_button) + self.german_notation_radio_button = QtWidgets.QRadioButton(self.chords_group_box) + self.german_notation_radio_button.setObjectName('german_notation_radio_button') + self.chords_layout.addWidget(self.german_notation_radio_button) + self.neolatin_notation_radio_button = QtWidgets.QRadioButton(self.chords_group_box) + self.neolatin_notation_radio_button.setObjectName('neolatin_notation_radio_button') + self.chords_layout.addWidget(self.neolatin_notation_radio_button) + + self.left_layout.addWidget(self.chords_group_box) + self.left_layout.addStretch() self.right_layout.addStretch() self.tool_bar_active_check_box.stateChanged.connect(self.on_tool_bar_active_check_box_changed) @@ -64,6 +92,11 @@ class SongsTab(SettingsTab): self.add_from_service_check_box.stateChanged.connect(self.on_add_from_service_check_box_changed) self.display_songbook_check_box.stateChanged.connect(self.on_songbook_check_box_changed) self.display_copyright_check_box.stateChanged.connect(self.on_copyright_check_box_changed) + self.mainview_chords_check_box.stateChanged.connect(self.on_mainview_chords_check_box_changed) + self.disable_chords_import_check_box.stateChanged.connect(self.on_disable_chords_import_check_box_changed) + self.english_notation_radio_button.clicked.connect(self.on_english_notation_button_clicked) + self.german_notation_radio_button.clicked.connect(self.on_german_notation_button_clicked) + self.neolatin_notation_radio_button.clicked.connect(self.on_neolatin_notation_button_clicked) def retranslateUi(self): self.mode_group_box.setTitle(translate('SongsPlugin.SongsTab', 'Songs Mode')) @@ -76,6 +109,13 @@ class SongsTab(SettingsTab): self.display_copyright_check_box.setText(translate('SongsPlugin.SongsTab', 'Display "%s" symbol before copyright info') % SongStrings.CopyrightSymbol) + self.chords_group_box.setTitle(translate('SongsPlugin.SongsTab', 'Chords')) + self.mainview_chords_check_box.setText(translate('SongsPlugin.SongsTab', 'Display chords in the main view')) + self.disable_chords_import_check_box.setText(translate('SongsPlugin.SongsTab', 'Ignore chords when importing songs')) + self.chord_notation_label.setText(translate('SongsPlugin.SongsTab', 'Chord notation to use:')) + self.english_notation_radio_button.setText(translate('SongsPlugin.SongsTab', 'English') + ' (C-D-E-F-G-A-B)') + self.german_notation_radio_button.setText(translate('SongsPlugin.SongsTab', 'German') + ' (C-D-E-F-G-A-H)') + self.neolatin_notation_radio_button.setText(translate('SongsPlugin.SongsTab', 'Neo-Latin') + ' (Do-Re-Mi-Fa-Sol-La-Si)') def on_search_as_type_check_box_changed(self, check_state): self.song_search = (check_state == QtCore.Qt.Checked) @@ -95,6 +135,21 @@ class SongsTab(SettingsTab): def on_copyright_check_box_changed(self, check_state): self.display_copyright_symbol = (check_state == QtCore.Qt.Checked) + def on_mainview_chords_check_box_changed(self, check_state): + self.mainview_chords = (check_state == QtCore.Qt.Checked) + + def on_disable_chords_import_check_box_changed(self, check_state): + self.disable_chords_import = (check_state == QtCore.Qt.Checked) + + def on_english_notation_button_clicked(self): + self.chord_notation = 'english' + + def on_german_notation_button_clicked(self): + self.chord_notation = 'german' + + def on_neolatin_notation_button_clicked(self): + self.chord_notation = 'neo-latin' + def load(self): settings = Settings() settings.beginGroup(self.settings_section) @@ -103,11 +158,22 @@ class SongsTab(SettingsTab): self.update_load = settings.value('add song from service') self.display_songbook = settings.value('display songbook') self.display_copyright_symbol = settings.value('display copyright symbol') + self.chord_notation = settings.value('chord notation') + self.mainview_chords = settings.value('mainview chords') + self.disable_chords_import = settings.value('disable chords import') self.tool_bar_active_check_box.setChecked(self.tool_bar) self.update_on_edit_check_box.setChecked(self.update_edit) self.add_from_service_check_box.setChecked(self.update_load) self.display_songbook_check_box.setChecked(self.display_songbook) self.display_copyright_check_box.setChecked(self.display_copyright_symbol) + self.mainview_chords_check_box.setChecked(self.mainview_chords) + self.disable_chords_import_check_box.setChecked(self.disable_chords_import) + if self.chord_notation == 'german': + self.german_notation_radio_button.setChecked(True) + elif self.chord_notation == 'neo-latin': + self.neolatin_notation_radio_button.setChecked(True) + else: + self.english_notation_radio_button.setChecked(True) settings.endGroup() def save(self): @@ -118,6 +184,9 @@ class SongsTab(SettingsTab): settings.setValue('add song from service', self.update_load) settings.setValue('display songbook', self.display_songbook) settings.setValue('display copyright symbol', self.display_copyright_symbol) + settings.setValue('mainview chords', self.mainview_chords) + settings.setValue('disable chords import', self.disable_chords_import) + settings.setValue('chord notation', self.chord_notation) settings.endGroup() if self.tab_visited: self.settings_form.register_post_process('songs_config_updated') From e51ffd9759e247806678e4c25acb2921eaab89b8 Mon Sep 17 00:00:00 2001 From: Tomas Groth Date: Thu, 2 Jun 2016 15:54:44 +0200 Subject: [PATCH 07/73] Removed resizing buttons and reuse the stage.css --- openlp/plugins/remotes/html/chords.html | 4 +- openlp/plugins/remotes/html/css/chords.css | 63 ++++------------------ openlp/plugins/remotes/html/js/chords.js | 12 ++--- 3 files changed, 13 insertions(+), 66 deletions(-) diff --git a/openlp/plugins/remotes/html/chords.html b/openlp/plugins/remotes/html/chords.html index b8ad05347..e5c1f2cb9 100644 --- a/openlp/plugins/remotes/html/chords.html +++ b/openlp/plugins/remotes/html/chords.html @@ -23,6 +23,7 @@ ${chords_title} + @@ -32,9 +33,6 @@