assets/themes/j1/core/js/template.js in j1-template-2023.9.1 vs assets/themes/j1/core/js/template.js in j1-template-2023.9.2
- old
+ new
@@ -4593,11 +4593,11 @@
var volume = volumeDefault;
var pause_spoken = '. ';
var chunkCounter = 0;
var userStoppedSpeaking = false;
var chunkSpoken = false;
- var scrollOnce = true;
+ var lastScrollPosition = false;
var rateUserDefault;
var pitchUserDefault;
var volumeUserDefault;
var currentLanguage;
var voiceLanguageDefault;
@@ -4650,22 +4650,23 @@
'en-GB': 'Microsoft Hazel - English (United Kingdom) (en-GB)',
'en-US': 'Microsoft Zira Desktop - English (United States) (en-US)',
'de-DE': 'Microsoft Katja Online (Natural) - German (Germany)'
};
- // -------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
// Internal functions
- // -------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
// scan a page to get correct positions for scrolling and highlightning
//
function scanPage(options) {
// see: https://stackoverflow.com/questions/3163615/how-to-scroll-an-html-page-to-a-given-anchor
// see: https://stackoverflow.com/questions/22154129/how-to-make-setinterval-behave-more-in-sync-or-how-to-use-settimeout-instea
- var line = 0;
+ var line = options.startLine;
var lines;
function scanSection(counter) {
+ // jadams, 2023-09-28:
// because of the current translation in progress, the length
// of a page may change to higher or lower values (asian)
//
lines = Math.max(document.body.scrollHeight, document.body.offsetHeight, document.documentElement.clientHeight, document.documentElement.scrollHeight, document.documentElement.offsetHeight);
$('#content').attr("style", "opacity: .3");
@@ -4681,15 +4682,24 @@
}, pageScanCycle);
} else {
setTimeout(function () {
scanFinished = true;
$('#content').attr("style", "opacity: 1");
- $(window).scrollTop(0);
+
+ // jadams, 2023-09-28:
+ // do NOT scroll on stop if paused
+ // disabled
+ // -------------------------------------------------------------------
+ // if (!myOptions.isPaused) {
+ // window.scrollTo({top: 0, behavior: 'smooth'});
+ // }
}, pageScanCycle);
}
}
- scanSection(0);
+ scanSection({
+ startLine: 0
+ });
} // END scanPage
// merge (configuration) objects
//
function extend() {
@@ -4813,30 +4823,35 @@
}
if (isFirefox) {
var voiceLanguageDefault = voiceLanguageFirefoxDefault[currentLanguage];
}
- // -------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
// Public functions (methods)
- // -------------------------------------------------------------------------
+ // ---------------------------------------------------------------------------
//
var methods = {
// main speak2me method.
//
speak: function (options) {
- var opts = $.extend({}, $.fn.speak2me.defaults, options);
var toSpeak = '';
var voiceTags = new Array();
var _this = this;
var obj, processed, finished;
var ignoreTags;
scanFinished = false;
- myOptions = extend(defaultOptions, customOptions || {});
+ myOptions = extend(options, defaultOptions, customOptions || {});
// scan page to find correct positions for scrolling and highlightning
//
- scanPage();
+ if (!myOptions.isPaused) {
+ scanPage({
+ startLine: 0
+ });
+ } else {
+ scanFinished = true;
+ }
// Default values
//
voiceTags['a'] = new voiceTag('Follow the Link:', ':');
voiceTags['q'] = new voiceTag('', pause_spoken);
@@ -4845,23 +4860,20 @@
voiceTags['dl'] = new voiceTag('Start of list.', 'End of list. ');
voiceTags['dt'] = new voiceTag('', ', ');
voiceTags['img'] = new voiceTag('Start of an embedded image with the description,', ', ');
voiceTags['table'] = new voiceTag('Start of an embedded table,', 'This element ist not spoken.');
voiceTags['card-header'] = new voiceTag('', '');
- voiceTags['doc-example'] = new voiceTag('Start of an embedded example element,', 'This element ist not spoken.');
- voiceTags['admonitionblock'] = new voiceTag('Start of an attention element of type, ', ':');
- voiceTags['listingblock'] = new voiceTag('Start of an embedded structured text block,', 'This element ist not spoken.');
- voiceTags['carousel'] = new voiceTag('Start of an embedded carousel element,', 'This element ist not spoken.');
- voiceTags['slider'] = new voiceTag('Start of an embedded slider element,', 'This element ist not spoken.');
- voiceTags['masonry'] = new voiceTag('Start of an embedded masonry element,', 'This element ist not spoken.');
- voiceTags['lightbox'] = new voiceTag('Start of an embedded lightbox element,', 'This element ist not spoken.');
- voiceTags['gallery'] = new voiceTag('Start of an embedded gallery element,', 'This element ist not spoken.');
+ voiceTags['.doc-example'] = new voiceTag('Start of an embedded example element,', 'This element ist not spoken.');
+ voiceTags['.admonitionblock'] = new voiceTag('Start of an attention element of type, ', ':');
+ voiceTags['.listingblock'] = new voiceTag('Start of an embedded structured text block,', 'This element ist not spoken.');
+ voiceTags['.slider'] = new voiceTag('Start of an embedded slider element,', 'This element ist not spoken.');
+ voiceTags['.masonry'] = new voiceTag('Start of an embedded masonry element,', 'This element ist not spoken.');
+ voiceTags['.lightbox-block'] = new voiceTag('Start of an embedded lightbox element,', 'This element ist not spoken.');
+ voiceTags['.gallery'] = new voiceTag('Start of an embedded gallery element,', 'This element ist not spoken.');
voiceTags['figure'] = new voiceTag('Start of an embedded figure with the caption,', '');
voiceTags['blockquote'] = new voiceTag('Blockquote start.', 'Blockquote end.');
voiceTags['quoteblock'] = new voiceTag('Start of an embedded quote block element,', 'Quote block element end.');
-
- // ignoreTags = ['masonry', 'carousel', 'slider', 'pre','audio','button','canvas','code','del','dialog','embed','form','head','iframe','meter','nav','noscript','object','s','script','select','style','textarea','video'];
ignoreTags = ['audio', 'button', 'canvas', 'code', 'del', 'pre', 'dialog', 'embed', 'form', 'head', 'iframe', 'meter', 'nav', 'noscript', 'object', 's', 'script', 'select', 'style', 'textarea', 'video'];
// TODO: NOT working for multiple 'tab' windows
// dispayed in the same browser
//
@@ -5122,10 +5134,11 @@
//
if (speaker.offsetTop !== undefined) {
if (speaker.offsetTop >= speaker.previousScrollPosition) {
speaker.previousScrollPosition = speaker.offsetTop;
}
+ lastScrollPosition = speaker.offsetTop - scrollBlockOffset;
}
// remove highlightning for the paragraph already spoken
//
if (speaker.$paragraph !== undefined) {
@@ -5135,25 +5148,37 @@
chunkCounter++;
});
// loop to prepare ALL chunks to speak or STOP the voice output
//
+ var wasRunOnce = false;
var speechMonitor = setInterval(function () {
// check if all chunks (text) are spoken
//
if (chunkCounter == chunkCounterMax || userStoppedSpeaking) {
chunkCounter = 0;
userStoppedSpeaking = false;
chunkSpoken = false;
speaker.$paragraph !== undefined && speaker.$paragraph.removeClass('speak-highlighted');
- window.scrollTo({
- top: 0,
- behavior: 'smooth'
- });
+
+ // jadams, 2023-09-28:
+ // do NOT scroll on stop if paused
+ // disabled
+ // -----------------------------------------------------------------
+ // if (!myOptions.isPaused) {
+ // window.scrollTo({top: 0, behavior: 'smooth'});
+ // }
+
+ // remove speak indication;
$('.mdib-speaker').removeClass('mdib-spin');
clearInterval(speechMonitor);
} else {
+ if (!wasRunOnce && myOptions.isPaused) {
+ chunkCounter = myOptions.lastChunk;
+ wasRunOnce = true;
+ }
+
// prepare speaker data and start the voice
//
speaker.text = chunks[chunkCounter].text;
speaker.offsetTop = chunks[chunkCounter].offsetTop;
speaker.$paragraph = chunks[chunkCounter].$paragraph;
@@ -5313,26 +5338,24 @@
jQuery(clone).find('a').addBack('a').each(function () {
var anchor = jQuery(this);
copy = anchor[0].innerText;
prepend = voiceTags['a'].prepend;
appended = voiceTags['a'].append;
-
- // jQuery('<div>' + prepend + copy + '</div>').insertBefore(this);
jQuery('<div>' + copy + '</div>').insertBefore(this);
jQuery('<div>' + appended + '</div>').insertBefore(this);
jQuery(this).remove();
});
- // Search for admonitionblock elements and extract the type and
+ // Search for admonition block elements and extract the type and
// content. Insert type and content and then remove the DOM object.
//
- jQuery(clone).find('.admonitionblock').addBack('admonitionblock').each(function () {
+ jQuery(clone).find('.admonitionblock').addBack('.admonitionblock').each(function () {
content_type = this.classList[1];
content_element = jQuery(this).find('.content');
content = content_element[0].innerText;
- prepend = voiceTags['admonitionblock'].prepend + content_type + '. ';
- appended = voiceTags['admonitionblock'].append;
+ prepend = voiceTags['.admonitionblock'].prepend + content_type + '. ';
+ appended = voiceTags['.admonitionblock'].append;
if (content !== undefined && content != '') {
jQuery('<div>' + prepend + ' ' + content + '</div>').insertBefore(this);
jQuery('<div>' + appended + '</div>').insertBefore(this);
}
jQuery(this).remove();
@@ -5351,11 +5374,11 @@
jQuery('<div>' + appended + pause_spoken + '</div>').insertBefore(this);
}
jQuery(this).remove();
});
- // Search for <table>, check for <caption>, insert text
+ // Search for <table> tags, check for <caption>, insert text
// if exists and then remove the DOM object.
//
jQuery(clone).find('table').addBack('table').each(function () {
copy = jQuery(this).find('caption').text();
prepend = voiceTags['table'].prepend;
@@ -5383,160 +5406,134 @@
jQuery(title_element).remove();
});
// Search for doc-example elements and then remove the DOM object.
//
- jQuery(clone).find('.doc-example').addBack('doc-example').each(function () {
- prepend = voiceTags['doc-example'].prepend;
- appended = voiceTags['doc-example'].append;
+ jQuery(clone).find('.doc-example').addBack('.doc-example').each(function () {
+ prepend = voiceTags['.doc-example'].prepend;
+ appended = voiceTags['.doc-example'].append;
jQuery('<div>' + prepend + '</div>').insertBefore(this);
jQuery('<div>' + appended + pause_spoken + '</div>').insertBefore(this);
jQuery(this).remove();
});
- // Search for listingblock elements, check for previous declared <div>
+ // Search for listing block elements, check for previous declared <div>
// container that contains the title element and insert the
// text if exists and then finally remove the DOM object.
//
- jQuery(clone).find('.listingblock').addBack('listingblock').each(function () {
+ jQuery(clone).find('.listingblock').addBack('.listingblock').each(function () {
title_element = jQuery(this).find('.title');
if (title_element.length) {
copy = title_element[0].innerText;
} else {
copy = '';
}
- prepend = voiceTags['listingblock'].prepend;
- appended = voiceTags['listingblock'].append;
+ prepend = voiceTags['.listingblock'].prepend;
+ appended = voiceTags['.listingblock'].append;
if (copy !== undefined && copy != '') {
jQuery('<div>' + prepend + ' with the caption,' + copy + pause_spoken + '</div>').insertBefore(this);
jQuery('<div>' + appended + '</div>').insertBefore(this);
} else {
jQuery('<div>' + prepend + '</div>').insertBefore(this);
jQuery('<div>' + appended + '</div>').insertBefore(this);
}
jQuery(this).remove();
});
- // Search for <carousel> tags, check for previous declared <div>
+ // Search for masonry elements, check for previous declared <div>
// container that contains the title element and insert the
// text if exists and finally remove the DOM object.
//
- jQuery(clone).find('carousel').addBack('carousel').each(function () {
+ jQuery(clone).find('.masonry').addBack('.masonry').each(function () {
if ($(this).prev()[0].innerText !== undefined) {
title = $(this).prev()[0].innerText;
title_element = jQuery(this).prev();
// remove the title 'before' the DOM object deleted
//
jQuery(title_element).remove();
} else {
title = '';
}
- prepend = voiceTags['carousel'].prepend;
- appended = voiceTags['carousel'].append;
+ prepend = voiceTags['.masonry'].prepend;
+ appended = voiceTags['.masonry'].append;
if (title !== undefined && title != '') {
jQuery('<div>' + prepend + ' with the caption,' + title + pause_spoken + '</div>').insertBefore(this);
jQuery('<div>' + appended + '</div>').insertBefore(this);
} else {
jQuery('<div>' + prepend + '</div>').insertBefore(this);
jQuery('<div>' + appended + '</div>').insertBefore(this);
}
jQuery(this).remove();
});
- // Search for <masonry> tags, check for previous declared <div>
+ // Search for slider elements, check for previous declared <div>
// container that contains the title element and insert the
// text if exists and finally remove the DOM object.
//
- jQuery(clone).find('masonry').addBack('masonry').each(function () {
+ jQuery(clone).find('.slider').addBack('.slider').each(function () {
if ($(this).prev()[0].innerText !== undefined) {
title = $(this).prev()[0].innerText;
title_element = jQuery(this).prev();
// remove the title 'before' the DOM object deleted
//
jQuery(title_element).remove();
} else {
title = '';
}
- prepend = voiceTags['masonry'].prepend;
- appended = voiceTags['masonry'].append;
+ prepend = voiceTags['.slider'].prepend;
+ appended = voiceTags['.slider'].append;
if (title !== undefined && title != '') {
- jQuery('<div>' + prepend + ' with the caption,' + title + pause_spoken + '</div>').insertBefore(this);
- jQuery('<div>' + appended + '</div>').insertBefore(this);
- } else {
- jQuery('<div>' + prepend + '</div>').insertBefore(this);
- jQuery('<div>' + appended + '</div>').insertBefore(this);
- }
- jQuery(this).remove();
- });
-
- // Search for <slider> tags, check for previous declared <div>
- // container that contains the title element and insert the
- // text if exists and finally remove the DOM object.
- //
- jQuery(clone).find('slider').addBack('slider').each(function () {
- if ($(this).prev()[0].innerText !== undefined) {
- title = $(this).prev()[0].innerText;
- title_element = jQuery(this).prev();
- // remove the title 'before' the DOM object deleted
- //
- jQuery(title_element).remove();
- } else {
- title = '';
- }
- prepend = voiceTags['slider'].prepend;
- appended = voiceTags['slider'].append;
- if (title !== undefined && title != '') {
jQuery('<div>' + prepend + ' with the caption, ' + title + pause_spoken + '</div>').insertBefore(this);
jQuery('<div>' + appended + '</div>').insertBefore(this);
} else {
jQuery('<div>' + prepend + '</div>').insertBefore(this);
jQuery('<div>' + appended + '</div>').insertBefore(this);
}
jQuery(this).remove();
});
- // Search for <gallery> tags, check for previous declared <div>
+ // Search for gallery elements, check for previous declared <div>
// container that contains the title element and insert the
// text if exists and finally remove the DOM object.
//
- jQuery(clone).find('gallery').addBack('gallery').each(function () {
+ jQuery(clone).find('.gallery').addBack('.gallery').each(function () {
if ($(this).prev()[0].innerText !== undefined) {
title = $(this).prev()[0].innerText;
title_element = jQuery(this).prev();
// remove the title BEFORE the DOM object gets deleted
//
jQuery(title_element).remove();
} else {
title = '';
}
- prepend = voiceTags['gallery'].prepend;
- appended = voiceTags['gallery'].append;
+ prepend = voiceTags['.gallery'].prepend;
+ appended = voiceTags['.gallery'].append;
if (title !== undefined && title != '') {
prepend !== '' && jQuery('<div>' + prepend + ' with the caption ' + title + pause_spoken + '</div>').insertBefore(this);
appended !== '' && jQuery('<div>' + appended + '</div>').insertBefore(this);
} else {
prepend !== '' && jQuery('<div>' + prepend + '</div>').insertBefore(this);
appended !== '' && jQuery('<div>' + appended + '</div>').insertBefore(this);
}
jQuery(this).remove();
});
- // Search for <slider> tags, and extract the <caption> tag data,
+ // Search for a lightbox blocks and extract the <caption> tag data,
// insert the text if exists and finally remove the DOM object.
//
- jQuery(clone).find('lightbox').addBack('gallery').each(function () {
+ jQuery(clone).find('.lightbox-block').addBack('.lightbox-block').each(function () {
if ($(this).prev()[0].innerText !== undefined) {
title = $(this).prev()[0].innerText;
title_element = jQuery(this).prev();
// remove the title 'before' the DOM object deleted
//
jQuery(title_element).remove();
} else {
title = '';
}
- prepend = voiceTags['lightbox'].prepend;
- appended = voiceTags['lightbox'].append;
+ prepend = voiceTags['.lightbox-block'].prepend;
+ appended = voiceTags['.lightbox-block'].append;
if (title !== undefined && title != '') {
jQuery('<div>' + prepend + ' with the caption,' + title + pause_spoken + '</div>').insertBefore(this);
jQuery('<div>' + appended + '</div>').insertBefore(this);
} else {
jQuery('<div>' + prepend + '</div>').insertBefore(this);
@@ -5714,36 +5711,56 @@
// jadams
stop: function () {
window.speechSynthesis.cancel();
userStoppedSpeaking = true;
- // jadams
+ // jadams, 2023-09-28;
+ // do not work
+ // -----------------------------------------------------------------------
// NOTE: stopping coincident active speech synthesis
// in multiple browser windows (tabs) does NOT work
- //
+ // -----------------------------------------------------------------------
// user_session.speech_synthesis_active = false;
// j1.writeCookie({
// name: 'user_session',
// data: user_session,
// secure: false,
// expires: 0
// });
- return this;
+ // return this;
},
+
// END stop
enabled: function () {
return 'speechSynthesis' in window;
},
// END enabled
isSpeaking: function () {
return window.speechSynthesis.speaking;
},
- // END is Speaking
+ // END isSpeaking
+ isSpoken: function () {
+ if (window.speechSynthesis.speaking) {
+ return chunkCounter;
+ } else {
+ return false;
+ }
+ },
+ // END isSpoken
+
+ isScrolled: function () {
+ if (window.speechSynthesis.speaking) {
+ return lastScrollPosition;
+ } else {
+ return false;
+ }
+ },
+ // END isSpoken
isPaused: function () {
return window.speechSynthesis.paused;
},
// END isPaused
@@ -5889,19 +5906,19 @@
if (voices[i].name === voiceLanguageDefault) {
option.setAttribute('selected', 'selected');
}
} else {
if (voices[i].name.includes(voiceUserDefault)) {
- // option.setAttribute('selected', 'selected');
+ // option.setAttribute('selected', 'selected');
}
}
option.setAttribute('data-speak2me-language', voices[i].language);
obj.find('select').append(option);
}
return i - skippedVoices;
},
- // END get Voiuces
+ // END getVoiuces
setVoice: function () {
// The setVoice function has to have two attributes
// if not, exit the function.
//
@@ -5944,12 +5961,12 @@
}
}
}
}
return this;
- } // END set Voice
- }; // END methods
+ } // END setVoice
+ }; // END public methods
// main speak2me method
//
$.fn.speak2me = function (method) {
if (methods[method]) {
@@ -5957,10 +5974,10 @@
} else if (typeof method === 'object' || !method) {
return methods.speak.apply(this, arguments);
} else {
jQuery.error('Method ' + method + ' does not exist on jQuery.speak2me');
}
- };
+ }; // END main
})(jQuery);
/***/ }),
/***/ 525:
\ No newline at end of file