listview webpart highlight list item - javascript

I need help getting started.
I have a listview webpart on my Wiki page. I would like to highlight the rows of the listview where the modified date is => 90 days old.
Can someone point me to a tutorial or something to get me started?

Conditional Formatting with SharePoint Designer
The type of behavior you're looking for is known as conditional formatting. Ordinarily, you can add conditional formatting to a list view web part by editing the page it's on using SharePoint Designer; conditional formatting is one of the options that will appear in the ribbon menu when you click on the list view web part in SharePoint Designer.
However, you may not be able to edit a wiki page using SharePoint Designer.
A JavaScript-based Alternative
In your case, you may be better off doing something with JavaScript to find the modified field for each row, compare its value to today's date, and apply highlighting as necessary.
One thing you can do is take the code below, copy it into a text file, and save that text file into a library in your SharePoint site. Then add a content editor web part to your wiki page, edit its properties, and set the "content link" property of the web part to point to the URL of the text file. Save the page and get out of edit mode, and you'll see a link to add conditional formatting rules through the browser. This requires you to have access to create lists and list items on the site.
<div id="_conditional_formatting_link" style="display:none; ">
<div unselectable="on" style="display:inline-block; user-select:none; cursor:pointer; padding: 3px; background-color:#9b9b9b; color:white; border:1px solid #888;" onclick="javascript:var rules = document.getElementById('_conditional_formatting'); if(rules.style.display == 'none'){rules.style.display = 'inline-block'}else{rules.style.display = 'none'}">
Conditional Formatting
</div>
</div>
<div id="_conditional_formatting" style="display:none;background-color:#dfdfdf; border: 1px solid black; width:95%; max-width:1100px;">
<a style="border:0px;padding:5px;float:right;" title="Reapply Formatting" href="javascript:getConditions(false);">
<img style="border:0px;" src="/_layouts/images/staticrefresh.gif"/>
</a>
<ol id="_conditional_formatting_rules">
</ol>
<div style="text-align:right; ">
<div id="_add_conditional_formatting_rule" unselectable="on" onclick="javascript: Add_Conditional_Formatting();" style="user-select:none; cursor:pointer; padding: 3px; margin: 3px; display:inline-block; background-color:#9b9b9b; border:1px solid #888; color:white;">Add Rule</div>
</div>
</div>
<script>
function target() { var column; var comparison; var value; var style; var scope; var type; var id; var offset; } /* structure for storing formatting rules */
var conditionalFormattingList = "Conditional Formatting";
function getConditions(reloadRules) {
/* if reloadRules, query the conditions list and get all the rules. Otherwise just reapply the ones in memory to the current document. */
if (typeof (reloadRules) == "undefined") { reloadRules = true; }
if (reloadRules) {
while (document.getElementById("_conditional_formatting_rules").children.length > 0) { /* Clear out the currently displayed list of rules. */
document.getElementById("_conditional_formatting_rules").removeChild(document.getElementById("_conditional_formatting_rules").children[0]);
}
this.clientContext = new SP.ClientContext();
var list = clientContext.get_web().get_lists().getByTitle(conditionalFormattingList);
var camlQuery = new SP.CamlQuery();
var folder = list.get_rootFolder();
camlQuery.set_viewXml('<View><Query><Where><Eq><FieldRef Name=\'URL\' /><Value Type=\'Text\'>' + document.location.pathname + '</Value></Eq></Where><OrderBy><FieldRef Name=\'Priority\' /><FieldRef Name=\'Name\' /></OrderBy></Query></View>');
this.items = list.getItems(camlQuery);
clientContext.load(list, 'EffectiveBasePermissions');
clientContext.load(items);
clientContext.load(folder);
}
this.clientContext.executeQueryAsync(
Function.createDelegate(this,
function () {
/*Get the current user name from the drop-down box*/
var Me = document.querySelector("#RibbonContainer-TabRowRight span[title='Open Menu'] [accesskey='W'] span").innerHTML;
if (reloadRules) {
var baseFormUrl = folder.get_serverRelativeUrl() + "/EditForm.aspx?ID=";
/* Figure out if the current user has access to create or edit items on the Conditional Formatting list */
var perms = list.get_effectiveBasePermissions();
this.hasEdit = perms.has(SP.PermissionKind.editListItems);
this.hasCreate = perms.has(SP.PermissionKind.addListItems);
/* Fill an array with our formatting rules */
this.targets = [];
var itemEnumerator = this.items.getEnumerator();
while (itemEnumerator.moveNext()) {
var item = itemEnumerator.get_current();
var targ = new target();
targ.column = item.get_item("Column");
targ.comparison = item.get_item("Comparison");
targ.style = item.get_item("Style");
targ.scope = item.get_item("Scope");
targ.type = item.get_item("Type");
targ.value = item.get_item("Value"); if (targ.value == null) { targ.value = ""; }
targ.id = item.get_item("ID");
targ.offset = item.get_item("Offset");
targets.push(targ);
}
}
if (!this.hasCreate) { document.getElementById("_add_conditional_formatting_rule").style.display = "none"; }
for (var targetIterator = 0; targetIterator < targets.length; targetIterator++) {
if (reloadRules) {
var rulelist = document.getElementById("_conditional_formatting_rules");
var ruletoadd = document.createElement("li");
var comparisondisplay = targets[targetIterator].type.indexOf("Field") != -1 ? "value of the <b>" + targets[targetIterator].value + "</b> column" : "<b>'" + targets[targetIterator].value + "'</b>";
if (targets[targetIterator].type == "Special" || targets[targetIterator].type == "Number") {
if (targets[targetIterator].value.toString().toLowerCase() == "[me]") { comparisondisplay = "<b>[Me](" + Me + ")</b>"; }
else { comparisondisplay = "<b>" + targets[targetIterator].value + "</b>"; }
}
if (targets[targetIterator].value == "") { comparisondisplay = "<b>(blank)</b>"; }
if (targets[targetIterator].offset != null) {
comparisondisplay += "<b>" + (targets[targetIterator].offset < 0 ? " " : " +") + targets[targetIterator].offset + "</b>"
}
var editLink = this.hasEdit ? "<div style='display:inline-block;cursor:pointer;' onclick='SP.UI.ModalDialog.commonModalDialogOpen(" + '"' + baseFormUrl + targets[targetIterator].id + '&Source=' + document.location.pathname + '"' + ",{},refreshPageConditions); '>" + "<img src='/_layouts/images/EDITITEM.GIF' style='vertical-align:middle;' title='Customize' alt='Customize'/>" + " </div>" : "";
ruletoadd.innerHTML = editLink + "When <b>" + targets[targetIterator].column + "</b> "
+ targets[targetIterator].comparison + " " + comparisondisplay
+ ", apply {" + (targets[targetIterator].style == null ? "remove all formatting" : "<span style='" + targets[targetIterator].style + "'>" + targets[targetIterator].style + "</span>") + "} to the <b>" + targets[targetIterator].scope + "</b>" + ((targets[targetIterator].scope != "Cell" && targets[targetIterator].scope != "Row") ? " column" : "");
rulelist.appendChild(ruletoadd);
}
var tables = document.querySelectorAll("table.ms-listviewtable"); /* Should get all the list view web parts on the page. */
var t_i = 0;
while (t_i < tables.length) {
var columnIndex = null; /* Index of the column to compare against */
var valueIndex = null; /* Index of a second column from which to pull the value to compare */
var styleTargetIndex = null; /* Index of a column to apply formatting to */
var thisTable = tables[t_i];
var headings = thisTable.rows[0].cells;
var h_i = 0;
while (h_i < headings.length) { /* Check all the column headings... */
var thisHeading = headings[h_i].querySelector("div:first-child");
if (thisHeading != null) {
/* In Internet Explorer, the headings have a DisplayName attribute you can grab. If that's not there, just grab the innerText or textContent */
var dispname = thisHeading.DisplayName ? thisHeading.DisplayName : (thisHeading.innerText ? thisHeading.innerText : thisHeading.textContent);
dispname = dispname.replace(/^\s+|\s+$/g, '');/* removes leading and trailing whitespace */
if (targets[targetIterator].scope != "Cell" && targets[targetIterator].scope != "Row") {
/*If the scope isn't Cell or Row, see if this is the cell to which the formatting should applied */
if (dispname == targets[targetIterator].scope) { styleTargetIndex = h_i; }
}
if (targets[targetIterator].type.indexOf("Field") != -1) {
/*If the value type is a Field, check to see if this is the field whose value we care about */
if (dispname == targets[targetIterator].value.toString()) { valueIndex = h_i; }
}
if (dispname == targets[targetIterator].column) { columnIndex = h_i; }
}
h_i += 1;
}
if (columnIndex != null) { /* If we found a matching heading, let's try to apply the rules... */
var rows = thisTable.rows;
for (var i = (rows.length > 0 ? 1 : 0) ; i < rows.length; i++) {
var cells = rows[i].children;
if (cells.length <= columnIndex) { continue }
var innerLink = cells[columnIndex].querySelector("a"); /* I want to specifically target links so that we can change their text color if necessary */
/* Populate valueToEval with the text value of the current cell, or its inner link if it has one */
var valueToEval = cells[columnIndex].innerText ? (innerLink != null ? innerLink.innerText : cells[columnIndex].innerText) : (innerLink != null ? innerLink.textContent : cells[columnIndex].textContent);
if (typeof (valueToEval) == "undefined") { valueToEval = "" } /* Treat empties as blanks */
var listValueToCompareAgainst = null;
if (valueIndex != null) { /* valueIndex only has a value if we need to grab the comparison value from another column on the list */
valueLink = cells[valueIndex].querySelector("a");
listValueToCompareAgainst = cells[valueIndex].innerText ? (valueLink != null ? valueLink.innerText : cells[valueIndex].innerText) : (valueLink != null ? valueLink.textContent : cells[valueIndex].textContent);
}
var needsStyling = false;
switch (targets[targetIterator].type) {
case "Number":
if (!isNaN(Number(valueToEval))) {
valueToEval = Number(valueToEval);
}
if (!isNaN(Number(targets[targetIterator].value))) {
targets[targetIterator].value = Number(targets[targetIterator].value);
}
break;
case "Date":
valueToEval = new Date(valueToEval);
targets[targetIterator].value = new Date(targets[targetIterator].value);
if (targets[targetIterator].offset != null) {
targets[targetIterator].value.setDate(targets[targetIterator].value.getDate() + Number(targets[targetIterator].offset));
}
break;
case "Text": /* Already covered, bro */ break;
case "Date Field":
valueToEval = new Date(valueToEval);
targets[targetIterator].value = new Date(listValueToCompareAgainst);
if (targets[targetIterator].offset != null) {
targets[targetIterator].value.setDate(targets[targetIterator].value.getDate() + Number(targets[targetIterator].offset));
}
break;
case "Text Field": targets[targetIterator].value = listValueToCompareAgainst; break;
case "Number Field":
if (!isNaN(Number(listValueToCompareAgainst))) {
targets[targetIterator].value = listValueToCompareAgainst;
if (targets[targetIterator].offset != null) {
targets[targetIterator].value += Number(targets[targetIterator].offset);
}
}
if (!isNaN(Number(valueToEval))) {
valueToEval = Number(valueToEval);
}
break;
case "Special":
if (targets[targetIterator].value.toLowerCase) {
if (targets[targetIterator].value.toLowerCase() == "[me]") { targets[targetIterator].value = Me }
else if (targets[targetIterator].value.toLowerCase().indexOf("[today]") != -1) {
var dateDifference = Number(targets[targetIterator].value.toLowerCase().replace("[today]", "").replace(" ", "").replace("+", ""));
targets[targetIterator].value = new Date();
if (!isNaN(dateDifference)) { targets[targetIterator].value.setDate(targets[targetIterator].value.getDate() + dateDifference); }
if (targets[targetIterator].offset != null) {
targets[targetIterator].value.setDate(targets[targetIterator].value.getDate() + Number(targets[targetIterator].offset));
}
valueToEval = new Date(valueToEval);
}
} else { valueToEval = new Date(valueToEval); }
break;
}
switch (targets[targetIterator].comparison) {
case "Greater Than or Equal To": needsStyling = (valueToEval >= targets[targetIterator].value); break;
case "Greater Than": needsStyling = (valueToEval > targets[targetIterator].value); break;
case "Less Than or Equal To": needsStyling = (valueToEval <= targets[targetIterator].value); break;
case "Less Than": needsStyling = (valueToEval < targets[targetIterator].value); break;
case "Equal To": needsStyling = (valueToEval == targets[targetIterator].value); break;
case "Not Equal To": needsStyling = (valueToEval != targets[targetIterator].value); break;
case "Contains": needsStyling = (valueToEval.indexOf(targets[targetIterator].value) != -1); break;
case "Does Not Contain": needsStyling = (valueToEval.indexOf(targets[targetIterator].value) == -1); break;
}
if (needsStyling) {
var links;
if (targets[targetIterator].scope != "Row") {
var targetIndex = (styleTargetIndex != null) ? styleTargetIndex : columnIndex;
cells[targetIndex].setAttribute("style", targets[targetIterator].style);
links = cells[targetIndex].querySelectorAll("a");
} else {
rows[i].setAttribute("style", targets[targetIterator].style);
for (var j = 0; j < cells.length; j++) {
cells[j].setAttribute("style", targets[targetIterator].style);
}
links = rows[i].querySelectorAll("a");
}
for (var j = 0; j < links.length; j++) {
if (links[j].title != "Open Menu") {
links[j].setAttribute("style", targets[targetIterator].style);
links[j].style.backgroundColor = "";
}
links[j].style.border = "0px";
}
}
}
}
t_i += 1;
}
}
document.getElementById("_conditional_formatting_link").style.display = "inline-block";
}
),
Function.createDelegate(this,
function (sender, args) { /* There was an error accessing the list. Time to create it! */
var lci = new SP.ListCreationInformation();
lci.set_title(conditionalFormattingList);
lci.set_templateType(SP.ListTemplateType.genericList);
var condition_list = clientContext.get_web().get_lists().add(lci);
clientContext.load(condition_list);
/* Drop the Title field */
var colTitle = condition_list.get_fields().getByTitle("Title");
colTitle.set_required(false);
colTitle.set_hidden(true);
colTitle.update();
condition_list.update();
/* Add New Fields */
var colColumn = condition_list.get_fields().addFieldAsXml('<Field Description=\'The column to compare (must be visible on the page)\' DisplayName=\'Column\' Type=\'Text\'/>', true, SP.AddFieldOptions.defaultValue);
var colComparison = condition_list.get_fields().addFieldAsXml('<Field Description=\'\' Type=\'Choice\' DisplayName=\'Comparison\' Format=\'Dropdown\' FillInChoice=\'FALSE\'><Default>Equal To</Default><CHOICES><CHOICE>Greater Than</CHOICE><CHOICE>Greater Than or Equal To</CHOICE><CHOICE>Equal To</CHOICE><CHOICE>Less Than or Equal To</CHOICE><CHOICE>Less Than</CHOICE><CHOICE>Not Equal To</CHOICE><CHOICE>Contains</CHOICE><CHOICE>Does Not Contain</CHOICE></CHOICES></Field>', true, SP.AddFieldOptions.defaultValue);
var colValue = condition_list.get_fields().addFieldAsXml('<Field Description=\'The value or the name of a column to compare against\' DisplayName=\'Value\' Type=\'Text\'/>', true, SP.AddFieldOptions.defaultValue);
var colType = condition_list.get_fields().addFieldAsXml('<Field Description=\'Indicate the type of value you are comparing against. Choose Special if using the [Me] or [Today] placeholders.\' Type=\'Choice\' DisplayName=\'Type\' Format=\'Dropdown\' FillInChoice=\'FALSE\'><Default>Text</Default><CHOICES><CHOICE>Date</CHOICE><CHOICE>Number</CHOICE><CHOICE>Text</CHOICE><CHOICE>Date Field</CHOICE><CHOICE>Number Field</CHOICE><CHOICE>Text Field</CHOICE><CHOICE>Special</CHOICE></CHOICES></Field>');
var colOffset = condition_list.get_fields().addFieldAsXml('<Field Description=\'Optionally specify a number to offset the value by when comparing against a number or date.\' DisplayName=\'Offset\' Type=\'Number\' />', true, SP.AddFieldOptions.defaultValue);
var colStyle = condition_list.get_fields().addFieldAsXml('<Field NumLines=\'4\' Description=\'The CSS to apply to when the condition is met. Leave blank to remove formatting. Example syntax: background-color:darkred; color:white; font-weight:bold;\' DisplayName=\'Style\' Type=\'Note\' />', true, SP.AddFieldOptions.defaultValue);
var colScope = condition_list.get_fields().addFieldAsXml('<Field Description=\'The scope to which the style should be applied. Choose Row, Cell, or specify a column name.\' Type=\'Choice\' DisplayName=\'Scope\' Format=\'Dropdown\' FillInChoice=\'TRUE\'><Default>Cell</Default><CHOICES><CHOICE>Cell</CHOICE><CHOICE>Row</CHOICE></CHOICES></Field>', true, SP.AddFieldOptions.defaultValue);
var colPriority = condition_list.get_fields().addFieldAsXml('<Field Description=\'Priority determines which styles are applied in case of overlapping conditions. Higher numbers are applied later.\' DisplayName=\'Priority\' Type=\'Number\' />', true, SP.AddFieldOptions.defaultValue);
var colUrl = condition_list.get_fields().addFieldAsXml('<Field Description=\'Page where this rule should be applied\' DisplayName=\'URL\' Type=\'Text\'/>', true, SP.AddFieldOptions.defaultValue);
clientContext.executeQueryAsync(
Function.createDelegate(this, function () { getConditions(); }),
Function.createDelegate(this, function (sender, args) { document.getElementById("_conditional_formatting").innerHTML = ("An error occcurred while trying to apply conditional formatting to the list for you. Error details: " + args.get_message() + " " + args.get_stackTrace()); document.getElementById("_conditional_formatting_link").style.display = "inline-block"; }));
}
));
}
/* This method is called when the Add Rule button is clicked. */
function Add_Conditional_Formatting() {
/* Create a new item with only the URL and Priority fields filled out */
var currUrl = document.location.pathname;
var clientContext = new SP.ClientContext();
var itemCreateInfo = new SP.ListItemCreationInformation();
var newItem = clientContext.get_web().get_lists().getByTitle(conditionalFormattingList).addItem(itemCreateInfo);
newItem.set_item('URL', currUrl);
/* Give the new item a priority that will put it at the end of the list. This is kind of a hack since the highest priority is not necessarily the rulecount. */
newItem.set_item('Priority', document.getElementById("_conditional_formatting_rules").children.length + 1);
newItem.update();
clientContext.load(newItem);
clientContext.executeQueryAsync(Function.createDelegate(this, function () {
getConditions(); /* Reload to refresh the rules list after adding the item */
}), Function.createDelegate(this, function (sender, args) { alert(args.get_message()); }));
}
/* This method is called when the Edit Item dialog box is closed. It refreshes the page it the item was saved. */
function refreshPageConditions(result) { if (result != SP.UI.DialogResult.cancel) { window.location.replace(document.location.href) } }
ExecuteOrDelayUntilScriptLoaded(function () {
getConditions();
/* If there are any collapsible sections on the page, keep checking to see whether formatting needs to be reapplied */
this.TableRowCount = 0;
if (document.querySelector("img[alt='expand']") != null) {
setInterval(function () {
var tempTableRowCount = document.querySelectorAll("tr").length;
if (tempTableRowCount != this.TableRowCount) {
/* Only reapply formatting if the count of table rows is different than it was previously */
this.TableRowCount = tempTableRowCount;
getConditions(false) /* Passing false reapplies loaded rules without re-querying the SharePoint list */
}
}, 1000)
}
}, "SP.JS");
</script>
You would then want to add a rule that looks like this:
That script handles the nitty gritty tasks of creating a list of conditional formatting rules, checking those rules against list view web parts on the page, and applying them when the page loads. So all you need to do then is add the rules!

Related

SpeechSynthesisUtterance script with play, pause, stop buttons and selection of language and voice

I would like to read the text of my pages with SpeechSynthesisUtterance.
I found this script: https://www.hongkiat.com/blog/text-to-speech/
Almost perfect, but the pause button doesn't seem to do much, and I wish I had the ability to set a language and maybe choose a voice.
I found the reference here: https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesisUtterance, but I'm not very knowledgeable in JavaScript.
For language, as far as I understand, should be used the lang parameter set in the html tag.
For the voice I have absolutely no idea of how to implement it in the code.
It would be important because I have texts in English, Spanish, French and Italian, and the result without voice and language settings sometimes sounds really weird.
Update
These days I fiddled a little, I managed (more or less) to combine two different scripts/examples.
This: https://www.hongkiat.com/blog/text-to-speech/
and this: https://developer.mozilla.org/en-US/docs/Web/API/SpeechSynthesis#Examples
The code that came out is this:
HTML
<html>
<head>
<link rel="stylesheet" href="style.css">
<script src="text-to-speech.js"></script>
</head>
<body>
<div class=buttons>
<button id=play></button>
<button id=pause></button>
<button id=stop></button>
</div>
<select id="voices">
</select>
<div id="description">
The SpeechSynthesis interface of the Web Speech API is the controller interface for the speech service; this can be used to retrieve information about the synthesis voices available on the device, start and pause speech, and other commands besides.
Questo è in italiano come viene?
</div>
</body>
</html>
CSS
#import url('https://fonts.googleapis.com/css?family=Crimson+Text');
.buttons {
margin-top: 25px;
}
button {
background: none;
border: none;
cursor: pointer;
height: 48px;
outline: none;
padding: 0;
width: 48px;
}
#play {
background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/play.svg);
}
#play.played {
background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/play1.svg);
}
#pause {
background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/pause.svg);
}
#pause.paused {
background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/pause1.svg);
}
#stop {
background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/stop.svg);
}
#stop.stopped {
background-image: url(https://rpsthecoder.github.io/js-speech-synthesis/stop1.svg);
}
JAVASCRIPT
onload = function() {
if ('speechSynthesis' in window) with(speechSynthesis) {
// select voices////
var synth = window.speechSynthesis;
var voiceSelect = document.querySelector('#voices');
var voices = [];
function 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';
}
option.setAttribute('data-lang', voices[i].lang);
option.setAttribute('data-name', voices[i].name);
voiceSelect.appendChild(option);
}
voiceSelect.selectedIndex = selectedIndex;
}
populateVoiceList();
if (speechSynthesis.onvoiceschanged !== undefined) {
speechSynthesis.onvoiceschanged = populateVoiceList;
}
//end select voices
var playEle = document.querySelector('#play');
var pauseEle = document.querySelector('#pause');
var stopEle = document.querySelector('#stop');
var flag = false;
playEle.addEventListener('click', onClickPlay);
pauseEle.addEventListener('click', onClickPause);
stopEle.addEventListener('click', onClickStop);
function onClickPlay() {
if (!flag) {
flag = true;
utterance = new SpeechSynthesisUtterance(document.querySelector('#description').textContent);
//utterance.voice = getVoices()[0];
//add voice//
var selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
for(i = 0; i < voices.length ; i++) {
//if(voices[i].name === 'Google UK English Female') {
if(voices[i].name === selectedOption) {
utterance.voice = voices[i];
break;
}
}
voiceSelect.onchange = function(){
onClickStop();
stopEle.className = '';
onClickPlay();
playEle.className = 'played';
}
//and add voice
utterance.onend = function() {
flag = false;
playEle.className = pauseEle.className = '';
stopEle.className = 'stopped';
};
playEle.className = 'played';
stopEle.className = '';
speak(utterance);
}
if (paused) { /* unpause/resume narration */
playEle.className = 'played';
pauseEle.className = '';
resume();
}
}
function onClickPause() {
if (speaking && !paused) { /* pause narration */
pauseEle.className = 'paused';
playEle.className = '';
pause();
}
}
function onClickStop() {
if (speaking) { /* stop narration */
/* for safari */
stopEle.className = 'stopped';
playEle.className = pauseEle.className = '';
flag = false;
cancel();
}
}
}
else { /* speech synthesis not supported */
msg = document.createElement('h5');
msg.textContent = "Detected no support for Speech Synthesis";
msg.style.textAlign = 'center';
msg.style.backgroundColor = 'red';
msg.style.color = 'white';
msg.style.marginTop = msg.style.marginBottom = 0;
document.body.insertBefore(msg, document.querySelector('div'));
}
}
Now I have the play, stop and pause buttons (pauses still does not work) and I can select one of the voices from those available in the device.
Seems to work fine with chrome, maybe a little less with Firefox, (but I'm using Linux LMDE, maybe it's my fault). And after a while on Chrome stops talking. I don't know why, but it seems to me that I've seen someone maybe understand why in some of the thousands of web pages I've opened these days, I'll have to reopen them all.
It would be nice if the selected voice was saved in a cookie, so if I open another page the script starts with the last voice I selected (I have no idea how to do it in JavaScript)
Update 2
I made some other small steps forward and simplified.
It almost seems to work, not always the pause button, the big doubt I have now is that with chrome it does not seem to stop when I update or change pages, and it is really bad that when you change page he keeps reading the previous page.
HTML
<div id="SpeechSynthesis">
<div>
<button id=play>play</button>
<button id=pause>pause</button>
<button id=stop>stop</button>
</div>
<select id="voices">
</select>
</div>
<p id="texttospeech">
The SpeechSynthesis interface of the Web Speech API is the controller interface for the speech service; this can be used to retrieve information about the synthesis voices available on the device, start and pause speech, and other commands besides.
Questo è in italiano come viene?
</p>
JAVASCRIPT
onload = function() {
if ('speechSynthesis' in window){
var synth = speechSynthesis;
var flag = false;
//stop when change page ???(not sure)
if(synth.speaking){ /* stop narration */
/* for safari */
flag = false;
synth.cancel();
}
/* references to the buttons */
var playEle = document.querySelector('#play');
var pauseEle = document.querySelector('#pause');
var stopEle = document.querySelector('#stop');
/* click event handlers for the buttons */
playEle.addEventListener('click', onClickPlay);
pauseEle.addEventListener('click', onClickPause);
stopEle.addEventListener('click', onClickStop);
// select voices////
//var synth = window.speechSynthesis;
var voiceSelect = document.querySelector('#voices');
var voices = [];
function 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';
}
option.setAttribute('data-lang', voices[i].lang);
option.setAttribute('data-name', voices[i].name);
voiceSelect.appendChild(option);
}
voiceSelect.selectedIndex = selectedIndex;
}
populateVoiceList();
if (speechSynthesis.onvoiceschanged !== undefined) {
speechSynthesis.onvoiceschanged = populateVoiceList;
}
//end select voices
function onClickPlay() {
if(!flag){
flag = true;
utterance = new SpeechSynthesisUtterance(document.querySelector('#texttospeech').textContent);
//utterance.voice = synth.getVoices()[0];
//add voice//
var selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
for(i = 0; i < voices.length ; i++) {
//if(voices[i].name === 'Google UK English Female') {
if(voices[i].name === selectedOption) {
utterance.voice = voices[i];
break;
}
}
voiceSelect.onchange = function(){
onClickStop();
onClickPlay();
}
//and add voice
utterance.onend = function(){
flag = false;
};
synth.speak(utterance);
//fix stop after a while bug
let r = setInterval(() => {
console.log(speechSynthesis.speaking);
if (!speechSynthesis.speaking) {
clearInterval(r);
} else {
speechSynthesis.resume();
}
}, 14000);
//end fix stop after a while bug
}
if(synth.paused) { /* unpause/resume narration */
synth.resume();
}
}
function onClickPause() {
if(synth.speaking && !synth.paused){ /* pause narration */
synth.pause();
}
}
function onClickStop() {
if(synth.speaking){ /* stop narration */
/* for safari */
flag = false;
synth.cancel();
}
}
}
else {
msg = document.createElement('h5');
msg.textContent = "Detected no support for Speech Synthesis";
msg.style.textAlign = 'center';
msg.style.backgroundColor = 'red';
msg.style.color = 'white';
msg.style.marginTop = msg.style.marginBottom = 0;
document.body.insertBefore(msg, document.querySelector('#SpeechSynthesis'));
}
}
Update 3
I tried to add a cookie with the last selected voice. I added a couple of functions to manage the cookies, and I set the cookie in the onClickPlay() function.
//add voice//
var selectedOption = voiceSelect.selectedOptions[0].getAttribute('data-name');
for(i = 0; i < voices.length ; i++) {
//if(voices[i].name === 'Google UK English Female') {
if(voices[i].name === selectedOption) {
utterance.voice = voices[i];
setCookie('SpeechSynthesisVoice',voices[i].name,30);
break;
}
}
Firefox sets the cookie without problems, chrome no (even if the file is on an online server).
Then I tried to set the voice saved in the cookie as "selected" in populateVoiceList() function:
//get cookie voice
var cookievoice = getCookie('SpeechSynthesisVoice');
//add selcted to option if if cookievoice
if (cookievoice === voices[i].name) {
option.setAttribute('selected', 'selected');
}
It works, I find the "selected" in the code, but it doesn't seem to be considered, it always starts talking with the first voice in the list, or the default one, I'm not sure, and not with the one that has the "selected".
The cookie functions I use:
//cookie functions
function setCookie(name, value, days) {
var expires = '',
date = new Date();
if (days) {
date.setTime(date.getTime() + (days * 24 * 60 * 60 * 1000));
expires = '; expires=' + date.toGMTString();
}
document.cookie = name + '=' + value + expires + '; path=/';
}
function getCookie(name) {
var cookies = document.cookie.split(';'),
length = cookies.length,
i,
cookie,
nameEQ = name + '=';
for (i = 0; i < length; i += 1) {
cookie = cookies[i];
while (cookie.charAt(0) === ' ') {
cookie = cookie.substring(1, cookie.length);
}
if (cookie.indexOf(nameEQ) === 0) {
return cookie.substring(nameEQ.length, cookie.length);
}
}
return null;
}
function eraseCookie(name) {
createCookie(name, '', -1);
}
I didn't receive much help, but somehow I managed to set up a small player that reads the text of a web page.
I did a little tutorial with a demo that explains what I did and how it works.
https://www.alebalweb-blog.com/85-text-to-speech-player-with-buttons-play-pause-stop-and-voice-choice.html
How about this line after the "for" loop?
voiceSelect.selectedIndex = selectedIndex;
If it's still here you're overriding your selection.
Try something like
if(cookievoice === voices[i].name) {
option.setAttribute('selected', 'selected');
selectedIndex = i;
}

'DOMException: Failed to execute 'querySelectorAll' on 'Element' when using an 'option:selected' selector

I'm running a page which throws an error at the following line:
var label = $select.find('option:selected').html() || $select.find('option:first').html() || "";
For the sake of completeness, here is the full jQuery function (country-select.js):
(function($) {
$.fn.countrySelect = function (callback) {
$(this).each(function(){
var $select = $(this);
var lastID = $select.data('select-id'); // Tear down structure if Select needs to be rebuilt
if (lastID) {
$select.parent().find('span.caret').remove();
$select.parent().find('input').remove();
$select.unwrap();
$('ul#select-options-'+lastID).remove();
}
// If destroying the select, remove the selelct-id and reset it to it's uninitialized state.
if(callback === 'destroy') {
$select.data('select-id', null).removeClass('initialized');
return;
}
var uniqueID = Materialize.guid();
$select.data('select-id', uniqueID);
var wrapper = $('<div class="select-wrapper"></div>');
wrapper.addClass($select.attr('class'));
var options = $('<ul id="select-options-' + uniqueID +'" class="dropdown-content select-dropdown country-select"></ul>'),
selectChildren = $select.children('option, optgroup'),
valuesSelected = [],
optionsHover = false;
var label = $select.find('option:selected').html() || $select.find('option:first').html() || "";
// Function that renders and appends the option taking into
// account type and possible image icon.
var appendOptionWithIcon = function(select, option, type) {
// Add disabled attr if disabled
var disabledClass = (option.is(':disabled')) ? 'disabled ' : '';
var optgroupClass = (type === 'optgroup-option') ? 'optgroup-option ' : '';
var classes = option.attr('class');
var data = option.data('phone-code');
var opt = '<li class="' + disabledClass + optgroupClass + '"><span>';
if (option.val() !== '') {
opt += '<b class="flag flag-' + option.val().toLowerCase() + '"></b>';
}
opt += '<span class="option-label">' + option.html() + '</span>';
if (data && data !== '') {
opt += '<small>' + data + '</small>';
}
opt += '</span></li>';
options.append($(opt));
};
/* Create dropdown structure. */
if (selectChildren.length) {
selectChildren.each(function() {
if ($(this).is('option')) {
appendOptionWithIcon($select, $(this));
} else if ($(this).is('optgroup')) {
// Optgroup.
var selectOptions = $(this).children('option');
options.append($('<li class="optgroup"><span>' + $(this).attr('label') + '</span></li>'));
selectOptions.each(function() {
appendOptionWithIcon($select, $(this), 'optgroup-option');
});
}
});
}
options.find('li:not(.optgroup)').each(function (i) {
$(this).click(function (e) {
// Check if option element is disabled
if (!$(this).hasClass('disabled') && !$(this).hasClass('optgroup')) {
var selected = true;
options.find('li').removeClass('active');
$(this).toggleClass('active');
$newSelect.val($(this).find('.option-label').text());
activateOption(options, $(this));
$select.find('option').eq(i).prop('selected', selected);
// Trigger onchange() event
$select.trigger('change');
if (typeof callback !== 'undefined') callback();
}
e.stopPropagation();
});
});
// Wrap Elements
$select.wrap(wrapper);
// Add Select Display Element
var dropdownIcon = $('<span class="caret">▼</span>');
if ($select.is(':disabled'))
dropdownIcon.addClass('disabled');
// escape double quotes
var sanitizedLabelHtml = label.replace(/"/g, '"');
var $newSelect = $('<input type="text" class="select-dropdown" readonly="true" ' + (($select.is(':disabled')) ? 'disabled' : '') + ' data-activates="select-options-' + uniqueID +'" value="'+ sanitizedLabelHtml +'"/>');
$select.before($newSelect);
$newSelect.before(dropdownIcon);
$newSelect.after(options);
// Check if section element is disabled
if (!$select.is(':disabled')) {
$newSelect.data('constrainwidth', false)
$newSelect.dropdown({'hover': false, 'closeOnClick': false});
}
// Copy tabindex
if ($select.attr('tabindex')) {
$($newSelect[0]).attr('tabindex', $select.attr('tabindex'));
}
$select.addClass('initialized');
$newSelect.on({
'focus': function (){
if ($('ul.select-dropdown').not(options[0]).is(':visible')) {
$('input.select-dropdown').trigger('close');
}
if (!options.is(':visible')) {
$(this).trigger('open', ['focus']);
var label = $(this).val();
var selectedOption = options.find('li').filter(function() {
return $(this).find('.option-label').text().toLowerCase() === label.toLowerCase();
})[0];
activateOption(options, selectedOption);
}
},
'click': function (e){
e.stopPropagation();
}
});
$newSelect.on('blur', function() {
$(this).trigger('close');
options.find('li.selected').removeClass('selected');
});
options.hover(function() {
optionsHover = true;
}, function () {
optionsHover = false;
});
// Make option as selected and scroll to selected position
var activateOption = function(collection, newOption) {
if (newOption) {
collection.find('li.selected').removeClass('selected');
var option = $(newOption);
option.addClass('selected');
options.scrollTo(option);
}
};
// Allow user to search by typing
// this array is cleared after 1 second
var filterQuery = [],
onKeyDown = function(e){
// TAB - switch to another input
if(e.which == 9){
$newSelect.trigger('close');
return;
}
// ARROW DOWN WHEN SELECT IS CLOSED - open select options
if(e.which == 40 && !options.is(':visible')){
$newSelect.trigger('open');
return;
}
// ENTER WHEN SELECT IS CLOSED - submit form
if(e.which == 13 && !options.is(':visible')){
return;
}
e.preventDefault();
// CASE WHEN USER TYPE LETTERS
var letter = String.fromCharCode(e.which).toLowerCase(),
nonLetters = [9,13,27,38,40];
if (letter && (nonLetters.indexOf(e.which) === -1)) {
filterQuery.push(letter);
var string = filterQuery.join(''),
newOption = options.find('li').filter(function() {
return $(this).text().toLowerCase().indexOf(string) === 0;
})[0];
if (newOption) {
activateOption(options, newOption);
}
}
// ENTER - select option and close when select options are opened
if (e.which == 13) {
var activeOption = options.find('li.selected:not(.disabled)')[0];
if(activeOption){
$(activeOption).trigger('click');
$newSelect.trigger('close');
}
}
// ARROW DOWN - move to next not disabled option
if (e.which == 40) {
if (options.find('li.selected').length) {
newOption = options.find('li.selected').next('li:not(.disabled)')[0];
} else {
newOption = options.find('li:not(.disabled)')[0];
}
activateOption(options, newOption);
}
// ESC - close options
if (e.which == 27) {
$newSelect.trigger('close');
}
// ARROW UP - move to previous not disabled option
if (e.which == 38) {
newOption = options.find('li.selected').prev('li:not(.disabled)')[0];
if(newOption)
activateOption(options, newOption);
}
// Automaticaly clean filter query so user can search again by starting letters
setTimeout(function(){ filterQuery = []; }, 1000);
};
$newSelect.on('keydown', onKeyDown);
});
function toggleEntryFromArray(entriesArray, entryIndex, select) {
var index = entriesArray.indexOf(entryIndex),
notAdded = index === -1;
if (notAdded) {
entriesArray.push(entryIndex);
} else {
entriesArray.splice(index, 1);
}
select.siblings('ul.dropdown-content').find('li').eq(entryIndex).toggleClass('active');
// use notAdded instead of true (to detect if the option is selected or not)
select.find('option').eq(entryIndex).prop('selected', notAdded);
setValueToInput(entriesArray, select);
return notAdded;
}
function setValueToInput(entriesArray, select) {
var value = '';
for (var i = 0, count = entriesArray.length; i < count; i++) {
var text = select.find('option').eq(entriesArray[i]).text();
i === 0 ? value += text : value += ', ' + text;
}
if (value === '') {
value = select.find('option:disabled').eq(0).text();
}
select.siblings('input.select-dropdown').val(value);
}
};
$(function() {
$('.js-country-select').countrySelect();
});
$(document).on('change', '[data-country-select]', function() {
var target = 'select' + $(this).data('country-select');
var val = $(this).val();
var label = 'State';
var options = [
'<option value="" selected="" disabled="">Select State</option>'
];
if (val !== '') {
var country = window.__COUNTRIES[val];
var subdivisions = country.subdivisions;
var keys = Object.keys(subdivisions);
label = country.subdivisionName;
options = [
'<option value="" selected="" disabled="">Select ' + label + '</option>'
];
keys = keys.sort(function(a, b) {
var valA = subdivisions[a].toLowerCase();
var valB = subdivisions[b].toLowerCase();
if (valA < valB) return -1;
if (valA > valB) return 1;
return 0;
});
keys.forEach(function(key) {
options.push('<option value="' + key + '">' + subdivisions[key] + '</option>');
});
$(target).removeAttr('disabled');
} else {
$(target).attr('disabled', 'disabled');
}
$(target).parents('.input-field').find('label').html(label);
$(target).val('').html(options);
$(target).select2();
});
})(jQuery);
Here is the exception that I see in debug mode:
From what I understand from Failed to execute 'querySelectorAll' on 'Element' in ExtJS 5, :selected is not part of the CSS specification.
How should I fix this? Should I use:
var label = $select.find('option').filter(':selected').html() || $select.find('option').filter(':first').html() || "";
?
Converting Phil's comment to an answer, my debugger was set to pause on all exceptions (including caught ones). I had to de-activate the 'stop sign' button shown below to make the debugger work normally again.

Js & Jquery:Understanding a search code with JSON request

i have a js search in my page that i don't get perfectly how does work because i don't know 100% js and jquery. As far as i think the code takes the input and search match with a link to a database that returns a JSON value depending on what name you put on the link (?name="the-input-name-here"), then, the code parse the json and determinates if the name of the input it's a valid surname and if it is the check if it has a running page, if it has redirects you to that page. If the input is a valid surname but doesn't have a running page it redirects you to "landing-page-yes.html". If the input isn't a valid surname it redirects you to "landing-page-no.html".
I need help to understand how the code does this in order to make a simplify version. How that call to another url database is parsed by the js ? How can i think something similar with a backend and ajax ? I need to understand 100% what this code does and i'm kinda lost.
THANKS !
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js"></script>
<input id="srchid" width="100" onkeypress="submitonenter(document.getElementById('srchid').value, event, this)" />
<input onclick="nameCheck(document.getElementById('srchid').value);" value="CLICK HERE" type="button" style="background-color:#990033; color:#fff;border-style:outset;">
<div id="nameresults"></div>
<script >
<!--
Array.prototype.contains = function(obj) {
var i = this.length;
while (i--) {
if (this[i] === obj) {
return true;
}
} return false;
}
function cursor_wait() {
document.body.style.cursor = 'wait';
}
// Returns the cursor to the default pointer
function cursor_clear() {
document.body.style.cursor = 'default';
}
function nameCheck(sName) {
sName = trim(sName);
if(sName == ""){
alert("Please enter a name!");
return false;
}
cursor_wait();
routeToNameLookup(sName);
cursor_clear();
}
function $(id){return document.getElementById(id);}
// Get JSONP
function getJSON(url){
var s = document.createElement('script');
s.setAttribute('src',url);
document.getElementsByTagName('head')[0].appendChild(s);
}
function testcb(data){
//alert(data[0]);
}
function loaded(data) {
var name = document.getElementById('srchid').value;
var xmlhttp2;
//Using innerHTML just once to avoid multi reflow
$("nameresults").innerHTML = data[0];
if($("nameresults").innerHTML == 1){
if(data[1] == 1){
//display name page with content
var sNewName = name.replace (/'/g, ""); //remove any '
sNewName = removeSpaces(sNewName);
sNewName = convertNonAscii(sNewName);
//redirect to name crest
var sUrl = "http://www.heraldicjewelry.com/" + sNewName.toLowerCase() + "-crest-page.html";
//getJSON("http://www.gohapp.com/updatenamesearch.php?id=" + data[2] + "&pageurl=" + sUrl + "&callback=testcb");
//postwith(sUrl,{'pname':name});
window.location=sUrl;
} else {
//post to yes page
//postwith("http://www.heraldicjewelry.com/landing-page-yes.html",{'pname':name});
window.location="http://www.heraldicjewelry.com/landing-page-yes.html";
}
} else {
//post to no page
//postwith("http://www.heraldicjewelry.com/landing-page-no.html",{'pname':name});
window.location="http://www.heraldicjewelry.com/landing-page-no.html";
}
$("nameresults").innerHTML = "";
}
function routeToNameLookup(sSrchName) {
var name = document.getElementById('srchid').value;
if(sSrchName==""){
alert("Please enter your family name.");
} else {
var rn=Math.floor(Math.random()*1000000000000001)
getJSON("http://www.gohapp.com/namesearch_new.php?name="+name+"&rec=1&callback=loaded&rn="+rn);
}
}
function trim (sStr) {
var str = sStr.replace(/^\s+/, '');
for (var i = str.length - 1; i >= 0; i--) {
if (/\S/.test(str.charAt(i))) {
str = str.substring(0, i + 1);
break;
}
}
return str;
}
function postwith (to,p) {
var myForm = document.createElement("form");
myForm.method="post" ;
myForm.action = to ;
for (var k in p) {
var myInput = document.createElement("input") ;
myInput.setAttribute("name", k) ;
myInput.setAttribute("value", p[k]);
myForm.appendChild(myInput) ;
}
document.body.appendChild(myForm) ;
myForm.submit() ;
document.body.removeChild(myForm) ;
}
function removeSpaces(string) {
return string.split(' ').join('');
}
var PLAIN_ASCII =
"AaEeIiOoUu" // grave
+ "AaEeIiOoUuYy" // acute
+ "AaEeIiOoUuYy" // circumflex
+ "AaOoNn" // tilde
+ "AaEeIiOoUuYy" // umlaut
+ "Aa" // ring
+ "Cc" // cedilla
+ "OoUu" // double acute
;
var UNICODE =
"\u00C0\u00E0\u00C8\u00E8\u00CC\u00EC\u00D2\u00F2\u00D9\u00F9"
+ "\u00C1\u00E1\u00C9\u00E9\u00CD\u00ED\u00D3\u00F3\u00DA\u00FA\u00DD\u00FD"
+ "\u00C2\u00E2\u00CA\u00EA\u00CE\u00EE\u00D4\u00F4\u00DB\u00FB\u0176\u0177"
+ "\u00C3\u00E3\u00D5\u00F5\u00D1\u00F1"
+ "\u00C4\u00E4\u00CB\u00EB\u00CF\u00EF\u00D6\u00F6\u00DC\u00FC\u0178\u00FF"
+ "\u00C5\u00E5"
+ "\u00C7\u00E7"
+ "\u0150\u0151\u0170\u0171"
;
// remove accentued from a string and replace with ascii equivalent
function convertNonAscii(s) {
if (s == null)
return null;
var sb = '';
var n = s.length;
for (var i = 0; i < n; i++) {
var c = s.charAt(i);
var pos = UNICODE.indexOf(c);
if (pos > -1) {
sb += PLAIN_ASCII.charAt(pos);
} else {
sb += c;
}
}
return sb;
}
function submitonenter(name, evt,thisObj) {
evt = (evt) ? evt : ((window.event) ? window.event : "")
if (evt) {
// process event here
if ( evt.keyCode==13 || evt.which==13 ) {
thisObj.blur();
nameCheck(name);
//alert("looking for " + name);
}
}
}
//-->
</script>

Changing the fontsize with javascript

The code below adds <font size="x">$text</font> to the WYSIWYG editor's textarea:
/**
* Set Size Context
*/
this.set_size_context = function(sizestate)
{
if (this.buttons['fontsize'])
{
if (typeof sizestate == 'undefined')
{
sizestate = this.editdoc.queryCommandValue('fontsize');
}
switch (sizestate)
{
case null:
case '':
{
if (is_moz)
{
sizestate = this.translate_fontsize(this.editdoc.body.style.fontSize);
}
}
break;
}
if (sizestate != this.sizestate)
{
this.sizestate = sizestate;
var i;
if (this.popupmode)
{
for (i in this.sizeoptions)
{
if (YAHOO.lang.hasOwnProperty(this.sizeoptions, i))
{
this.sizeoptions[i].style.display = (i == this.sizestate ? '' : 'none');
}
}
}
else
{
for (i = 0; i < this.buttons['fontsize'].options.length; i++)
{
if (this.buttons['fontsize'].options[i].value == this.sizestate)
{
this.buttons['fontsize'].selectedIndex = i;
break;
}
}
}
}
}
};
I replaced <font size tags with <span style="font-size tags in PHP side and everthing is working except the fontsize dropdown menu and the editor is still adding <font size when I choose a font size from the list. (it's correctly converted to <span style="font-size when the message is posted or previewed).
The question is, how the code above generates <font size tag and how can i replace it with <span style="font-size ?
Below are the other related sections to the fontsize in the JS:
this.build_fontsize_popup = function(obj, menu)
{
for (var n in sizeoptions)
{
if (YAHOO.lang.hasOwnProperty(sizeoptions, n))
{
var option = document.createElement('div');
option.innerHTML = '<span style="font-size:' + sizeoptions[n] + '">' + sizeoptions[n] + '</span>';
option.className = 'osize';
option.style.textAlign = 'center';
option.title = sizeoptions[n];
option.cmd = obj.cmd;
option.controlkey = obj.id;
option.editorid = this.editorid;
option.onmouseover = option.onmouseout = option.onmouseup = option.onmousedown = vB_Text_Editor_Events.prototype.menuoption_onmouseevent;
option.onclick = vB_Text_Editor_Events.prototype.formatting_option_onclick;
menu.appendChild(option);
}
}
}
and
this.translate_fontsize = function(csssize)
{
switch (csssize)
{
case '15px':
case '12px': return 1;
case '15px': return 2;
case '18px': return 3;
case '21px': return 4;
case '24px': return 5;
case '27px': return 6;
case '30px': return 7;
default: return '';
}
}
Here is the complete JS file: https://jsfiddle.net/07ttt9a7/
Wading though the full code, you need to fix the
case 'fontname':
{
this.wrap_tags('font', argument);
return;
}
to use 'span' instead of 'font'
or
modify the function beginning with
this.wrap_tags = function(tagname, useoption, selection)
{

Use javascript cookie to remember which div is shown

I've been trying to combine two javascript codes, one that makes other divs close when a new one is opened and one that uses cookies to remember whether a div was opened by a viewer.
As it is now it succeeds in remembering which div was open, but when I click to open the other div, it doesn't close the first div. If I click again to reopen the first div, it closes the second just like it's supposed to, and after that, if I click to open the second div it closes the first div like it's supposed to. And then it works perfectly fine after that. But I can't figure out why it won't close the first div on the initial click.
I'm very new to javascript, so I don't know much about how to manipulate it.
<body>
<script language="javascript">
function setCookie (name, value, expires, path, domain, secure) {
document.cookie = name + "=" + escape(value) +
((expires) ? "; expires=" + expires : "") +
((path) ? "; path=" + path : "") +
((domain) ? "; domain=" + domain : "") +
((secure) ? "; secure" : "");
}
function getCookie (name) {
var cookie = " " + document.cookie;
var search = " " + name + "=";
var setStr = null;
var offset = 0;
var end = 0;
if (cookie.length > 0) {
offset = cookie.indexOf(search);
if (offset != -1) {
offset += search.length;
end = cookie.indexOf(";", offset);
if (end == -1) {
end = cookie.length;
}
setStr = unescape(cookie.substring(offset, end));
}
}
if (setStr == 'false') {
setStr = false;
}
if (setStr == 'true') {
setStr = true;
}
if (setStr == 'null') {
setStr = null;
}
return(setStr);
}
function MyFunction2(divName){
setCookie('bookmark_state', false);
//hidden val
var hiddenVal = document.getElementById("tempDivName");
//hide old
if(hiddenVal.Value != undefined){
var oldDiv = document.getElementById(hiddenVal.Value);
oldDiv.style.display = 'none';
}
//show div
var tempDiv = document.getElementById(divName);
tempDiv.style.display = 'block';
//save div ID
hiddenVal.Value = document.getElementById(divName).getAttribute("id");
}
function MyFunction3(divName){
setCookie('bookmark_state', null);
//hidden val
var hiddenVal = document.getElementById("tempDivName");
//hide old
if(hiddenVal.Value != undefined){
var oldDiv = document.getElementById(hiddenVal.Value);
oldDiv.style.display = 'none';
}
//show div
var tempDiv = document.getElementById(divName);
tempDiv.style.display = 'block';
//save div ID
hiddenVal.Value = document.getElementById(divName).getAttribute("id");
}
function checkBookmark() {
if (getCookie('bookmark_state') == null) {
document.getElementById('bookmark').style.display = 'block';
}
if (getCookie('bookmark_state') == false) {
document.getElementById('bookmark2').style.display = 'block';
}
}
</script>
<input id="tempDivName" type="hidden"/>
<div id="bookmark" style="display:none"><a style="color:black" href="#" OnClick="MyFunction2('bookmark2'); return false;">*</a></div>
<div id="bookmark2" style="display:none"><a style="color:red" href="#" OnClick="MyFunction3('bookmark');">*</a></div>
<script>
checkBookmark();
</script>
</body>
Also, is there a way to use a single cookie to remember which of several divs is open (instead of just two divs)?
Yes, simply store the states of your open divs in an object and serialize it via JSON, e.g.
var states = {
"div1": true, // open
"div2": false // closed
}
setCookie("div_states", JSON.stringify(states));

Categories