[~] Refactor
This commit is contained in:
parent
92b1e3a828
commit
b23c7b4537
2
d2/book1/NoSleep.min.js
vendored
Normal file
2
d2/book1/NoSleep.min.js
vendored
Normal file
File diff suppressed because one or more lines are too long
4750
d2/book1/book.js
Normal file
4750
d2/book1/book.js
Normal file
File diff suppressed because it is too large
Load Diff
72
d2/book1/index.html
Normal file
72
d2/book1/index.html
Normal file
@ -0,0 +1,72 @@
|
|||||||
|
|
||||||
|
<!DOCTYPE html>
|
||||||
|
<html>
|
||||||
|
<head>
|
||||||
|
<meta charset="utf-8">
|
||||||
|
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
|
||||||
|
<meta name="viewport" content="width=device-width">
|
||||||
|
<script
|
||||||
|
src="https://code.jquery.com/jquery-3.6.0.slim.min.js"
|
||||||
|
integrity="sha256-u7e5khyithlIdTpu22PHhENmPcRdFiHRjhAuHcs05RI="
|
||||||
|
crossorigin="anonymous"
|
||||||
|
></script>
|
||||||
|
|
||||||
|
<title>Speech synthesiser</title>
|
||||||
|
|
||||||
|
<script src="NoSleep.min.js"></script>
|
||||||
|
<script src="script.js"></script>
|
||||||
|
<script src="book.js"></script>
|
||||||
|
<link rel="stylesheet" href="style.css">
|
||||||
|
<!--[if lt IE 9]>
|
||||||
|
<script src="//html5shiv.googlecode.com/svn/trunk/html5.js"></script>
|
||||||
|
<![endif]-->
|
||||||
|
</head>
|
||||||
|
|
||||||
|
<body>
|
||||||
|
<div class=voice-settings>
|
||||||
|
<h1>Speech synthesiser</h1>
|
||||||
|
|
||||||
|
<p>Enter some text in the input below and press return or the "play" button to hear it. change voices using the dropdown menu.</p>
|
||||||
|
|
||||||
|
<form>
|
||||||
|
<input type="text" class="txt">
|
||||||
|
<div>
|
||||||
|
<label for="rate">Rate</label><input type="range" min="0.5" max="2" value="1" step="0.1" id="rate">
|
||||||
|
<div class="rate-value">1</div>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
<div>
|
||||||
|
<label for="pitch">Pitch</label><input type="range" min="0" max="2" value="1" step="0.1" id="pitch">
|
||||||
|
<div class="pitch-value">1</div>
|
||||||
|
<div class="clearfix"></div>
|
||||||
|
</div>
|
||||||
|
<select class=voice-select>
|
||||||
|
</select>
|
||||||
|
<div class="controls">
|
||||||
|
<button id="play" type="submit">Play</button>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
</div>
|
||||||
|
<div class=screen>
|
||||||
|
<div class=widget>
|
||||||
|
<select name=book>
|
||||||
|
<option value=0>Death of a Hear</option>
|
||||||
|
</select>
|
||||||
|
<br/>
|
||||||
|
<span>Current Sentence: </span>
|
||||||
|
<input type=input name=current-sentence></input>
|
||||||
|
<span>Total Sentences: </span>
|
||||||
|
<input type=input name=total-sentences disabled>
|
||||||
|
</input>
|
||||||
|
<br/>
|
||||||
|
<input type=button name=read-aloud value="Read Aloud">
|
||||||
|
<input type=button name=debug value="Debug">
|
||||||
|
</input>
|
||||||
|
<br/>
|
||||||
|
</div>
|
||||||
|
<pre class=status>
|
||||||
|
</pre>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
</body>
|
||||||
|
</html>
|
483
d2/book1/script.js
Normal file
483
d2/book1/script.js
Normal file
@ -0,0 +1,483 @@
|
|||||||
|
$(window).on('load', () => {
|
||||||
|
window.context = {};
|
||||||
|
window.context.books = [];
|
||||||
|
|
||||||
|
var synth = window.speechSynthesis;
|
||||||
|
|
||||||
|
var inputForm = document.querySelector('form');
|
||||||
|
var inputTxt = document.querySelector('.txt');
|
||||||
|
var voiceSelect = document.querySelector('select');
|
||||||
|
|
||||||
|
var pitch = document.querySelector('#pitch');
|
||||||
|
var pitchValue = document.querySelector('.pitch-value');
|
||||||
|
var rate = document.querySelector('#rate');
|
||||||
|
var rateValue = document.querySelector('.rate-value');
|
||||||
|
|
||||||
|
var voices = [];
|
||||||
|
|
||||||
|
|
||||||
|
context.nosleep_timer = null;
|
||||||
|
|
||||||
|
context.ui = {
|
||||||
|
voice_settings_div: $('.voice-settings'),
|
||||||
|
voice_select: $('.voice-select'),
|
||||||
|
status_pre: $('.status'),
|
||||||
|
books_select: $('.screen .widget select[name=book]'),
|
||||||
|
current_sentence_input:
|
||||||
|
$('.screen .widget input[name=current-sentence]'),
|
||||||
|
total_sentences_input:
|
||||||
|
$('.screen .widget input[name=total-sentences]'),
|
||||||
|
read_aloud:
|
||||||
|
$('.screen .widget input[name=read-aloud]'),
|
||||||
|
debug:
|
||||||
|
$('.screen .widget input[name=debug]'),
|
||||||
|
};
|
||||||
|
context.sentences = null;
|
||||||
|
context.pending_stop = false;
|
||||||
|
context.current_book = null;
|
||||||
|
context.nosleep = new NoSleep();
|
||||||
|
context.is_debug = false;
|
||||||
|
context.log = {
|
||||||
|
error: [],
|
||||||
|
info: [],
|
||||||
|
};
|
||||||
|
context.callbacks = {
|
||||||
|
log_error: (msg) => {
|
||||||
|
if (context.is_debug)
|
||||||
|
{
|
||||||
|
console.error(msg);
|
||||||
|
context.log.error.push(msg);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
enable_no_sleep: () => {
|
||||||
|
if (context.nosleep_timer != null)
|
||||||
|
{
|
||||||
|
context.callbacks.log_error('running already');
|
||||||
|
}
|
||||||
|
|
||||||
|
context.nosleep_timer = setInterval(
|
||||||
|
() => {
|
||||||
|
location.hash = 'nosleep' + Math.random();
|
||||||
|
context.callbacks.update_status();
|
||||||
|
/*
|
||||||
|
if ('vibrate' in window.navigator)
|
||||||
|
{
|
||||||
|
window.navigator.vibrate(200);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
}, 1000
|
||||||
|
);
|
||||||
|
},
|
||||||
|
get_state: () => {
|
||||||
|
let t1 = localStorage['state'];
|
||||||
|
if (t1)
|
||||||
|
{
|
||||||
|
return JSON.parse(t1);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return {};
|
||||||
|
}
|
||||||
|
},
|
||||||
|
get_cookie: (key) => {
|
||||||
|
/*
|
||||||
|
return document.cookie.split('; ').map(
|
||||||
|
(o) => o.split('=')
|
||||||
|
).reduce(
|
||||||
|
(b, a) => {
|
||||||
|
if (a.length == 2) {b[a[0]] = a[1]};
|
||||||
|
return b
|
||||||
|
},
|
||||||
|
{}
|
||||||
|
)[key];
|
||||||
|
*/
|
||||||
|
let t1 = localStorage['state'];
|
||||||
|
if (t1 != undefined)
|
||||||
|
{
|
||||||
|
let t2 = JSON.parse(t1);
|
||||||
|
return t2[key];
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
return undefined;
|
||||||
|
}
|
||||||
|
},
|
||||||
|
set_cookie: (key, value) => {
|
||||||
|
let state = context.callbacks.get_state('state');
|
||||||
|
|
||||||
|
state[key] = value;
|
||||||
|
|
||||||
|
//document.cookie = `${key}=${value};`;
|
||||||
|
localStorage['state'] = JSON.stringify(state);
|
||||||
|
|
||||||
|
context.callbacks.update_status();
|
||||||
|
},
|
||||||
|
disable_no_sleep: () => {
|
||||||
|
if (context.nosleep_timer == null)
|
||||||
|
{
|
||||||
|
context.callbacks.log_error('nothing is running');
|
||||||
|
}
|
||||||
|
clearInterval(context.nosleep_timer);
|
||||||
|
location.hash = '';
|
||||||
|
context.nosleep_timer = null;
|
||||||
|
synth.cancel();
|
||||||
|
},
|
||||||
|
continuous_reading: async() => {
|
||||||
|
if (context.is_reading)
|
||||||
|
{
|
||||||
|
context.pending_stop = true;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
context.is_reading = true;
|
||||||
|
context.nosleep.enable();
|
||||||
|
context.callbacks.enable_no_sleep();
|
||||||
|
context.ui.voice_settings_div.addClass('hidden');
|
||||||
|
context.ui.current_sentence_input.attr(
|
||||||
|
'disabled',
|
||||||
|
'disabled'
|
||||||
|
);
|
||||||
|
|
||||||
|
while (
|
||||||
|
context.callbacks.get_cookie('sentence_id') < context.sentences.length &&
|
||||||
|
!context.pending_stop
|
||||||
|
)
|
||||||
|
{
|
||||||
|
let sentence =
|
||||||
|
context.sentences[context.callbacks.get_cookie('sentence_id')];
|
||||||
|
//context.callbacks.log_error('start');
|
||||||
|
try {
|
||||||
|
await context.read_aloud(
|
||||||
|
context.sentences[
|
||||||
|
context.callbacks.get_cookie('sentence_id')
|
||||||
|
]
|
||||||
|
);
|
||||||
|
} catch (e) {
|
||||||
|
context.callbacks.log_error(e);
|
||||||
|
}
|
||||||
|
//context.callbacks.log_error('finished');
|
||||||
|
if (!context.pending_stop)
|
||||||
|
{
|
||||||
|
context.callbacks.set_cookie(
|
||||||
|
'sentence_id',
|
||||||
|
context.callbacks.get_cookie('sentence_id') + 1
|
||||||
|
);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
context.pending_stop = false;
|
||||||
|
context.ui.current_sentence_input.removeAttr('disabled');
|
||||||
|
context.nosleep.disable();
|
||||||
|
context.ui.voice_settings_div.removeClass('hidden');
|
||||||
|
context.callbacks.disable_no_sleep();
|
||||||
|
context.is_reading = false;
|
||||||
|
},
|
||||||
|
update_status: () => {
|
||||||
|
let data = {};
|
||||||
|
data.state = context.callbacks.get_state();
|
||||||
|
if (
|
||||||
|
context.callbacks.get_cookie('sentence_id') != null &&
|
||||||
|
context.sentences != null &&
|
||||||
|
context.callbacks.get_cookie('sentence_id') < context.sentences.length
|
||||||
|
)
|
||||||
|
{
|
||||||
|
data.sentence = context.sentences[context.callbacks.get_cookie('sentence_id')];
|
||||||
|
}
|
||||||
|
data.pending_stop = context.pending_stop;
|
||||||
|
data.is_reading = context.is_reading;
|
||||||
|
data.log = context.log;
|
||||||
|
context.ui.current_sentence_input.val(
|
||||||
|
context.callbacks.get_cookie('sentence_id')
|
||||||
|
);
|
||||||
|
data.timestamp = (new Date());
|
||||||
|
data.version = 'v0.1.7';
|
||||||
|
data.speech_synthesis = {
|
||||||
|
paused: synth.paused,
|
||||||
|
pending: synth.pending,
|
||||||
|
speaking: synth.speaking,
|
||||||
|
};
|
||||||
|
/*
|
||||||
|
if (!synth.speaking && context.is_reading)
|
||||||
|
{
|
||||||
|
synth.cancel();
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
context.ui.status_pre.text(
|
||||||
|
JSON.stringify(
|
||||||
|
data,
|
||||||
|
null,
|
||||||
|
4,
|
||||||
|
)
|
||||||
|
);
|
||||||
|
},
|
||||||
|
ui_read_aloud_on_click: async() => {
|
||||||
|
let book_id = parseInt(context.ui.books_select.val());
|
||||||
|
if (context.current_book != book_id)
|
||||||
|
{
|
||||||
|
context.current_book = book_id;
|
||||||
|
context.sentences =
|
||||||
|
context.books[
|
||||||
|
context.current_book
|
||||||
|
].replaceAll(/([\.\?\!])\s+/g,'$1\n')
|
||||||
|
.split('\n');
|
||||||
|
context.ui.total_sentences_input.val(
|
||||||
|
context.sentences.length,
|
||||||
|
);
|
||||||
|
{
|
||||||
|
let state = context.callbacks.get_state();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (
|
||||||
|
context.ui.current_sentence_input.val() != ''
|
||||||
|
)
|
||||||
|
{
|
||||||
|
try{
|
||||||
|
let sentence_id = parseInt(
|
||||||
|
context.ui.current_sentence_input.val()
|
||||||
|
);
|
||||||
|
|
||||||
|
if (
|
||||||
|
sentence_id >= 0 &&
|
||||||
|
sentence_id < context.sentences.length
|
||||||
|
)
|
||||||
|
{
|
||||||
|
context.callbacks.set_cookie(
|
||||||
|
'sentence_id',
|
||||||
|
sentence_id
|
||||||
|
);
|
||||||
|
}
|
||||||
|
} catch (e) {
|
||||||
|
context.callbacks.log_error(e);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (context.is_reading && !context.pending_stop)
|
||||||
|
{
|
||||||
|
context.pending_stop = true;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.callbacks.continuous_reading();
|
||||||
|
}
|
||||||
|
},
|
||||||
|
populateVoiceList: () => {
|
||||||
|
voices = synth.getVoices().sort(function (a, b) {
|
||||||
|
const aname = a.name.toUpperCase(), bname = b.name.toUpperCase();
|
||||||
|
if ( aname < bname ) return -1;
|
||||||
|
else if ( aname == bname ) return 0;
|
||||||
|
else return +1;
|
||||||
|
});
|
||||||
|
//var selectedIndex = voiceSelect.selectedIndex < 0 ? 0 : voiceSelect.selectedIndex;
|
||||||
|
voiceSelect.innerHTML = '';
|
||||||
|
for(i = 0; i < voices.length ; i++) {
|
||||||
|
var option = document.createElement('option');
|
||||||
|
option.textContent = voices[i].name + ' (' + voices[i].lang + ')';
|
||||||
|
|
||||||
|
if(voices[i].default) {
|
||||||
|
option.textContent += ' -- DEFAULT';
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
{
|
||||||
|
let voice = context.callbacks.get_cookie('voice');
|
||||||
|
if (voice && option.textContent == voice)
|
||||||
|
{
|
||||||
|
$(option).attr('selected', 'selected');
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
option.setAttribute('data-lang', voices[i].lang);
|
||||||
|
option.setAttribute('data-name', voices[i].name);
|
||||||
|
voiceSelect.appendChild(option);
|
||||||
|
}
|
||||||
|
|
||||||
|
//voiceSelect.selectedIndex = selectedIndex;
|
||||||
|
},
|
||||||
|
init: () => {
|
||||||
|
let state = context.callbacks.get_state();
|
||||||
|
context.ui.voice_select.val(state.voice);
|
||||||
|
if (!state.book_id)
|
||||||
|
{
|
||||||
|
context.callbacks.set_cookie(
|
||||||
|
'book_id',
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (!state.sentence_id)
|
||||||
|
{
|
||||||
|
context.callbacks.set_cookie(
|
||||||
|
'sentence_id',
|
||||||
|
0,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
if (state.book_id)
|
||||||
|
{
|
||||||
|
context.ui.books_select.find(
|
||||||
|
'>option',
|
||||||
|
).eq(state.book_id).attr('selected', 'selected');
|
||||||
|
}
|
||||||
|
if (state.sentence_id)
|
||||||
|
{
|
||||||
|
context.ui.current_sentence_input.val(
|
||||||
|
state.sentence_id,
|
||||||
|
);
|
||||||
|
}
|
||||||
|
},
|
||||||
|
};
|
||||||
|
context.callbacks.populateVoiceList();
|
||||||
|
if (speechSynthesis.onvoiceschanged !== undefined) {
|
||||||
|
speechSynthesis.onvoiceschanged = context.callbacks.populateVoiceList;
|
||||||
|
}
|
||||||
|
|
||||||
|
context.callbacks.init();
|
||||||
|
|
||||||
|
context.ui.read_aloud.on(
|
||||||
|
'click',
|
||||||
|
context.callbacks.ui_read_aloud_on_click,
|
||||||
|
);
|
||||||
|
context.ui.voice_select.on(
|
||||||
|
'change',
|
||||||
|
() => {
|
||||||
|
context.callbacks.set_cookie(
|
||||||
|
'voice',
|
||||||
|
context.ui.voice_select.val()
|
||||||
|
);
|
||||||
|
}
|
||||||
|
);
|
||||||
|
context.ui.debug.on(
|
||||||
|
'click',
|
||||||
|
() => {
|
||||||
|
if (context.is_debug)
|
||||||
|
{
|
||||||
|
context.is_debug = false;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.is_debug = true;
|
||||||
|
}
|
||||||
|
context.callbacks.update_status();
|
||||||
|
}
|
||||||
|
);
|
||||||
|
context.read_aloud = async (raw_line) => {
|
||||||
|
line = raw_line.trim();
|
||||||
|
if (line.length == 0)
|
||||||
|
{
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let sleep_detect = null;
|
||||||
|
let exit = () => {
|
||||||
|
if (sleep_detect != null)
|
||||||
|
{
|
||||||
|
clearInterval(sleep_detect);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return new Promise((response, reject) => {
|
||||||
|
if (synth.speaking) {
|
||||||
|
context.callbacks.log_error('speechSynthesis.speaking');
|
||||||
|
if (reject != undefined)
|
||||||
|
{
|
||||||
|
reject('error');
|
||||||
|
}
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
let utterThis = new SpeechSynthesisUtterance(line);
|
||||||
|
utterThis.onend = function (event) {
|
||||||
|
exit();
|
||||||
|
context.callbacks.log_error(
|
||||||
|
'SpeechSynthesisUtterance.onend ' + event.error
|
||||||
|
);
|
||||||
|
if (response != undefined)
|
||||||
|
{
|
||||||
|
response('done ' + event.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
utterThis.onpause = function (event) {
|
||||||
|
exit();
|
||||||
|
context.callbacks.log_error('SpeechSynthesisUtterance.onpause');
|
||||||
|
if (reject != undefined)
|
||||||
|
{
|
||||||
|
reject('paused ' + event.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
utterThis.onerror = function (event) {
|
||||||
|
exit();
|
||||||
|
context.callbacks.log_error(
|
||||||
|
'SpeechSynthesisUtterance.onerror ' + event.error
|
||||||
|
);
|
||||||
|
if (reject != undefined)
|
||||||
|
{
|
||||||
|
reject('error ' + event.error);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
let selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
|
||||||
|
for(i = 0; i < voices.length ; i++) {
|
||||||
|
if(voices[i].name === selectedOption) {
|
||||||
|
utterThis.voice = voices[i];
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
//window.alert('fuck3');
|
||||||
|
utterThis.pitch = pitch.value;
|
||||||
|
utterThis.rate = rate.value;
|
||||||
|
synth.speak(utterThis);
|
||||||
|
let silence_count = 0;
|
||||||
|
sleep_detect = setInterval(
|
||||||
|
() => {
|
||||||
|
if (!synth.speaking)
|
||||||
|
{
|
||||||
|
context.callbacks.log_error(
|
||||||
|
'silence count is ' + silence_count
|
||||||
|
)
|
||||||
|
|
||||||
|
++silence_count;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (silence_count == 3 || context.pending_stop)
|
||||||
|
{
|
||||||
|
exit();
|
||||||
|
if (context.pending_stop)
|
||||||
|
{
|
||||||
|
synth.cancel();
|
||||||
|
reject('pending stop');
|
||||||
|
}
|
||||||
|
else
|
||||||
|
{
|
||||||
|
context.callbacks.log_error('phone is sleeping, retry');
|
||||||
|
response('utterance is not present');
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
context.read_aloud(
|
||||||
|
line
|
||||||
|
).then(response).catch(reject);
|
||||||
|
*/
|
||||||
|
}
|
||||||
|
},
|
||||||
|
100,
|
||||||
|
);
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
function speak(){
|
||||||
|
let line = inputTxt.value;
|
||||||
|
if (line !== '') {
|
||||||
|
context.read_aloud(line);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
inputForm.onsubmit = function(event) {
|
||||||
|
event.preventDefault();
|
||||||
|
|
||||||
|
speak();
|
||||||
|
|
||||||
|
inputTxt.blur();
|
||||||
|
}
|
||||||
|
|
||||||
|
pitch.onchange = function() {
|
||||||
|
pitchValue.textContent = pitch.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
rate.onchange = function() {
|
||||||
|
rateValue.textContent = rate.value;
|
||||||
|
}
|
||||||
|
|
||||||
|
voiceSelect.onchange = function(){
|
||||||
|
speak();
|
||||||
|
}
|
||||||
|
});
|
84
d2/book1/style.css
Normal file
84
d2/book1/style.css
Normal file
@ -0,0 +1,84 @@
|
|||||||
|
body, html {
|
||||||
|
margin: 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
html {
|
||||||
|
height: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
body {
|
||||||
|
height: 90%;
|
||||||
|
max-width: 800px;
|
||||||
|
margin: 0 auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
h1, p {
|
||||||
|
font-family: sans-serif;
|
||||||
|
text-align: center;
|
||||||
|
padding: 20px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.txt, select, form > div {
|
||||||
|
display: block;
|
||||||
|
margin: 0 auto;
|
||||||
|
font-family: sans-serif;
|
||||||
|
font-size: 16px;
|
||||||
|
padding: 5px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.txt {
|
||||||
|
width: 80%;
|
||||||
|
}
|
||||||
|
|
||||||
|
select {
|
||||||
|
width: 83%;
|
||||||
|
}
|
||||||
|
|
||||||
|
form > div {
|
||||||
|
width: 81%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.txt, form > div {
|
||||||
|
margin-bottom: 10px;
|
||||||
|
overflow: auto;
|
||||||
|
}
|
||||||
|
|
||||||
|
.clearfix {
|
||||||
|
clear: both;
|
||||||
|
}
|
||||||
|
|
||||||
|
label {
|
||||||
|
float: left;
|
||||||
|
width: 10%;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
.rate-value, .pitch-value {
|
||||||
|
float: right;
|
||||||
|
width: 5%;
|
||||||
|
line-height: 1.5;
|
||||||
|
}
|
||||||
|
|
||||||
|
#rate, #pitch {
|
||||||
|
float: right;
|
||||||
|
width: 81%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls {
|
||||||
|
text-align: center;
|
||||||
|
margin-top: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.controls button {
|
||||||
|
padding: 10px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.hidden
|
||||||
|
{
|
||||||
|
display: none !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
pre {
|
||||||
|
word-break: break-all;
|
||||||
|
white-space: pre-wrap;
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user