Why this space crashes the javascript function? - javascript

I have this code, which works perfectly to replace stuff in some divs (the example is actually at http://wiki-es.guildwars2.com/wiki/Reemplazador_Wiki, click on the red "AQUI" to see a live demonstration).
$("#SaeReplacerButton").dblclick(function () {
document.getElementById("SaeReplacerResult").innerHTML = "Error";
var TextoInicial = document.getElementById("SaeReplacerInput").innerHTML;
var Reemplazos = {
quemadura: "{{quemadura}}",
incapacitar: "{{incapacitar}}",
inmovilizar: "{{inmovilizar}}",
égida: "{{égida}}",
furia: "{{furia}}",
poder: "{{poder}}",
protección: "{{protección}}",
regeneración: "{{regeneración}}",
represalia: "{{represalia}}",
celeridad: "{{celeridad}}",
vigor: "{{vigor}}",
Primordus: "[[Primordus]]",
Kralkatorrik: "[[Kralkatorrik]]",
Guerrero: "{{guerrero}} [[Guerrero]]",
Guardián: "{{guardián}} [[Guardián]]",
Retornado: "{{retornado}}[[Retornado]]",
Elementalista: "{{elementalista}} [[Elementalista]]",
Guardabosques: "{{guardabosques}} [[Guardabosques]]",
Ingeniero: "{{ingeniero}} [[Ingeniero]]",
Nigromante: "{{nigromante}} [[Nigromante]]",
Ladrón: "{{ladrón}} [[Ladrón]]",
Hipnotizador: "{{hipnotizador}} [[Hipnotizador]]"
}
for (key in Reemplazos) {
var TextoInicial = TextoInicial.replace(key, Reemplazos[key]);
};
document.getElementById("SaeReplacerResult").innerHTML = TextoInicial;
});
However the problem starts if I change:
Retornado:"{{retornado}}[[Retornado]]",
for this:
Retornado:"{{retornado}} [[Retornado]]",
As you can see, I just added an space, which shouldn't matter at all because all the other arrays replacement works. However when I add that space to the Retornado one, the entire function stops working.
The question is: Why?

Related

Perform text animation by splitting text, but retain line breaks

I have created a function that maps over a sentence (provided by a CMS) and adds containers to each word. Splitting each word at spaces.
Now, some words will require line breaks, but my function is wiping them out, and I am not quite sure how I am going to retain line breaks in this case.
The demo below displays the issue I am having. The second one, although originally having a line break, has it removed when the function runs.
The breaks are coming from WP WYSIWYG, using a return. The field is using ACF and using the 'Automatically add ' option for new lines. Dev tools interprets/displays the original output as
<h1>This Is<br>Line Broken</h1>
Any ideas or advice of how to retain the breaks will be appreciated. For the purpose of my animations, each word will require the markup in the return value of $reformatedText
let $textAreaContent;
let $splitText;
let $reformatedText;
let $delayTime;
let $delayValue;
let $textAreas = document.querySelectorAll('.stagger-text');
function setDelayValue(curCount) {
$delayTime = 0.075;
return parseFloat(curCount * $delayTime).toFixed(3);
}
function createStaggerContainers($textArea) {
$textAreaContent = $textArea;
$splitText = $textAreaContent.innerText.split(/\s|<br>/g);
$reformatedText = $splitText.map((item, i, arr) => {
$delayValue = setDelayValue(i);
return `<span class="stagger__container">
<span class="stagger__text" style="animation-delay: ${$delayValue}s">${arr.length - 1 === i ? item : `${item} `}</span>
</span>`;
}).join('');
$textAreaContent.innerText = '';
$textAreaContent.innerHTML = $reformatedText;
}
if ($textAreas && $textAreas.length) {
$textAreas.forEach(($textArea) => {
createStaggerContainers($textArea);
});
}
<div class="stagger-text">Some text here</div>
<div class="stagger-text">This has line<br> breaks</div>

Add event listener to element after DOMContentLoaded

I have some trouble with adding event listener to element after DOM updating.
I have some page, that sort two lists and save the stage.
I can move elements between this lists by d&d and by clicking special button. And it work fine for me.
https://jsfiddle.net/bmj32ma0/2/
But, I have to save stage of this lists, and after reloading I have to extract stage, so I write code below.
function saveFriendsLists(e) {
if(e.target.classList.contains("b--drugofilter--save-button")){
var vkFriends = document.querySelector('.b--friends-from-vk .js--friends-container').innerHTML;
var choosenFriends = document.querySelector('.b--friends-choosen .js--friends-container').innerHTML;
localStorage.setItem('vkFriends', vkFriends);
localStorage.setItem('choosenFriends', choosenFriends);
}
}
function loadFriensListFromStorage() {
if(localStorage&&localStorage.choosenFriends&&localStorage.vkFriends){
document.querySelector('.b--friends-from-vk .js--friends-container').innerHTML = localStorage.vkFriends;
document.querySelector('.b--friends-choosen .js--friends-container').innerHTML = localStorage.choosenFriends;
}
}
document.addEventListener("DOMContentLoaded", loadFriensListFromStorage);
But after adding this, the preview functionality like D&D doesn't work. And I can't provide you valid jsfidle because, as I can understand, localStoradge reason or something.
When I tried to move my addEventListener to loadFriensListFromStorage function, like this:
function loadFriensListFromStorage() {
if(localStorage&&localStorage.choosenFriends&&localStorage.vkFriends){
document.querySelector('.b--friends-from-vk .js--friends-container').innerHTML = localStorage.vkFriends;
document.querySelector('.b--friends-choosen .js--friends-container').innerHTML = localStorage.choosenFriends;
}
[].forEach.call(friends, function(friend) {
friend.addEventListener('dragstart', handleDragStart, false);
});
}
But that doesn't have any effect.
How can I fix this issue? Thx.

Making editable table work cross-browser

I've been working on an ASP.NET page containing a ListView. When the user clicks a row, the content of the last (visible) column of this (once parsed) HTML table is replaced with a textbox (by means of jQuery), making the value editable.
So far, this works like a charm in Chrome but no joy in IE10.
In this jsfiddle, the value becomes editable but then the Save button doesn't work as expected.
In IE the textbox doesn't appear. Funny detail: if I comment out the four vars (invNr, newInvNr, oldHtml and spanWidth), the input element DOES appear in IE10 but of course I have no data to work with. Really REALLY weird.
The jQuery:
$(document).ready(function () {
$('tr[id*="itemRow"]').click(function () {
$clickedRow = $(this);
//this makes sure the input field isn't emptied when clicked again
if ($clickedRow.find('input[id$="editInvNr"]').length > 0) {
return;
}
var invNr = $clickedRow.find('span[id$="InvoiceNumber"]').text(),
newInvNr = '',
oldHtml = $clickedRow.find('span[id$="InvoiceNumber"]').html(),
spanWidth = $clickedRow.find('span[id$="InvoiceNumber"]').width();
$clickedRow.find('span[id$="InvoiceNumber"]').parent('td').html('<input type="text" ID="editInvNr"></input>');
$clickedRow.find('input[id="editInvNr"]').val(invNr).focus().on('input propertychange', function () {
$clickedRow.find('span[id$="SaveResultMsg"]').hide();
$clickedRow.find('td[id$="SaveOption"]').show();
$clickedRow.find('input[id*="btnSaveInvNrFormat"]').show();
newInvNr = $(this).val();
if (newInvNr == $clickedRow.find('span[id$="InvoiceNumber"]').text()) {
$clickedRow.find('td[id$="SaveOption"]').hide();
}
});
});
$('tr[id*="itemRow"]').focusout(function () {
$rowLosingFocus = $(this);
var previousValue = $rowLosingFocus.find('input[id$="editInvNr"]').val();
$rowLosingFocus.find('input[id$="editInvNr"]').closest('td').html('<asp:Label ID="lblInvoiceNumber" runat="server" />');
$rowLosingFocus.find('span[id$="InvoiceNumber"]').text(previousValue);
});
});
function UpdateInvoiceNrFormat(leButton) {
$buttonClicked = $(leButton);
$buttonClicked.focus();
var companyName = $buttonClicked.closest('tr').find('span[id$="lblCompanyName"]').text(),
invoiceType = $buttonClicked.closest('tr').find('span[id$="lblInvoiceType"]').text(),
invNrFormat = $buttonClicked.closest('tr').find('span[id$="lblInvoiceNumber"]').text();
PageMethods.UpdateInvoiceNumberFormat(companyName, invoiceType, invNrFormat, onSuccess, onError);
function onSuccess(result) {
$buttonClicked.hide();
$buttonClicked.siblings('span[id$="SaveResultMsg"]').text(result).show();
}
function onError(result) {
$buttonClicked.hide();
$buttonClicked.siblings('span[id$="SaveResultMsg"]').text('Error:' + result).show();
}
}
I've tried various combinations of jQuery statements, chaining and avoiding chaining, placing it at the bottom of the page as someone suggested, commenting out various parts of the code out of sheer desperation. Still nada.
There was no way to make the html() method replace the html correctly in IE10, although I never did find out exactly why. I ended up writing both elements into the table cell, set style="display:none" for one of them and use show() / hide() and that's good enough for me (and apparently for IE10 as well).
For anyone encountering the same issue: this is a workaround, not a solution in the strictest sense.

adding class to array elements through loop

I need the loop that checks input fields from 'inputs' array, and if there are empty fields, special dialog need to be displayed near them, and after the dialog is displayed I need class 'style' to be added to the input field near which the dialog was displayed, then dialog should go to the next emppty field and add class 'style' to it. And so on until all empty inputs have class 'style'.
The problem is, in my loop after the dialog is displayed class 'style' is added only to the last element from the array, but it should be added to every empty element with delays in between.
This is my loop, but as I said it is not working properly:
for(i=0;i<inputs.length;i++){
var now = inputs[i];
var top = inputs[i].attr('top');
if(!now.val()){
if(dialog.css('display')=='none'){now.addClass('style');dialog.css('top',top).fadeIn(200);}
else{dialog.delay(300).animate({"top": top}, 500, function(){now.addClass('style');});
}else{now.removeClass('style');}}
P.S. Sorry for my English.
This is happening because the function that is calling 'addClass' is happening after the 300 millisecond animation. By that time, the value of the 'i' variable has changed because the for loop will continue to run.
You may just be able to have the 'now.addClass' call before the 'animate' and delay. Otherwise, you will have to break the loop and continue after the animation is complete to prevent the variable from being overwritten.
Here is an example of what I was talking about. The code below will process 1 input at a time and not continue to the next until the current one is finished processing (this code has not been tested):
var offset = -1;
var inputs = (something goes here)
iterateInputs();
function iterateInputs()
{
offset++;
if (typeof inputs[offset] != 'undefined')
{
eachInput();
}
else
{
// all done!
}
}
function eachInput()
{
var now = inputs[offset];
var top = inputs[offset].attr('top');
if (!now.val())
{
if (dialog.css('display')=='none')
{
now.addClass('style');
dialog.css('top', top).fadeIn(200, function(){
iterateInputs();
});
}
else
{
dialog.delay(300).animate({"top": top}, 500, function(){
now.addClass('style');
iterateInputs();
});
}
}
else
{
now.removeClass('style');
iterateInputs();
}
}

IE javascript error - possibly related to setAttribute?

I am using Safalra's javascript to create a collapsible list. The script works across several browsers with no problem. However, when I apply the javascript to my own list, it fails to act as expected when I use IE (I'm using 7 at the moment). It simply writes the list, without the expand and contract images.
I copied the Safalra's javascript precisely, so I assume the error must be in my own list. This is how I generated my list:
<body onLoad="makeCollapsible(document.getElementById('libguides'));">
<ul id="libguides">
<script type="text/javascript" src="http://api.libguides.com/api_subjects.php?iid=54&more=false&format=js&guides=true&break=li"></script>
</ul>
(Yes, I do close the body tag eventually.) When I run this in IE, it tells me that line 48 is causing the problem, which appears to be:
node.onclick=createToggleFunction(node,list);
Here's the entire function:
function makeCollapsible(listElement){
// removed list item bullets and the sapce they occupy
listElement.style.listStyle='none';
listElement.style.marginLeft='0';
listElement.style.paddingLeft='0';
// loop over all child elements of the list
var child=listElement.firstChild;
while (child!=null){
// only process li elements (and not text elements)
if (child.nodeType==1){
// build a list of child ol and ul elements and hide them
var list=new Array();
var grandchild=child.firstChild;
while (grandchild!=null){
if (grandchild.tagName=='OL' || grandchild.tagName=='UL'){
grandchild.style.display='none';
list.push(grandchild);
}
grandchild=grandchild.nextSibling;
}
// add toggle buttons
var node=document.createElement('img');
node.setAttribute('src',CLOSED_IMAGE);
node.setAttribute('class','collapsibleClosed');
node.onclick=createToggleFunction(node,list);
child.insertBefore(node,child.firstChild);
}
I confess I'm too much of a javascript novice to understand why that particular line of code is causing the error. I looked at some of the other questions here, and was wondering if it might be a problem with setAttribute?
Thanks in advance.
Edited to add:
Here's the code for the createToggleFunction function. The whole of the script is just these two functions (plus declaring variables for the images).
function createToggleFunction(toggleElement,sublistElements){
return function(){
// toggle status of toggle gadget
if (toggleElement.getAttribute('class')=='collapsibleClosed'){
toggleElement.setAttribute('class','collapsibleOpen');
toggleElement.setAttribute('src',OPEN_IMAGE);
}else{
toggleElement.setAttribute('class','collapsibleClosed');
toggleElement.setAttribute('src',CLOSED_IMAGE);
}
// toggle display of sublists
for (var i=0;i<sublistElements.length;i++){
sublistElements[i].style.display=
(sublistElements[i].style.display=='block')?'none':'block';
}
}
}
Edited to add (again):
Per David's suggestion, I changed all instances of setAttribute & getAttribute...but clearly I did something wrong. IE is breaking at the 1st line (which is simply the doctype declaration) and at line 49, which is the same line of code where it was breaking before:
node.onclick=createToggleFunction(node,list);
Here's the first function as written now:
function makeCollapsible(listElement){
// removed list item bullets and the sapce they occupy
listElement.style.listStyle='none';
listElement.style.marginLeft='0';
listElement.style.paddingLeft='0';
// loop over all child elements of the list
var child=listElement.firstChild;
while (child!=null){
// only process li elements (and not text elements)
if (child.nodeType==1){
// build a list of child ol and ul elements and hide them
var list=new Array();
var grandchild=child.firstChild;
while (grandchild!=null){
if (grandchild.tagName=='OL' || grandchild.tagName=='UL'){
grandchild.style.display='none';
list.push(grandchild);
}
grandchild=grandchild.nextSibling;
}
// add toggle buttons
var node=document.createElement('img');
node.src = CLOSED_IMAGE;
node.className = 'collapsibleClosed';
node.onclick=createToggleFunction(node,list);
child.insertBefore(node,child.firstChild);
}
child=child.nextSibling;
}
}
And here's the second function:
function createToggleFunction(toggleElement,sublistElements){
return function(){
// toggle status of toggle gadget
// Use foo.className = 'bar'; instead of foo.setAttribute('class', 'bar');
if (toggleElement.className == 'collapsibleClosed') {
toggleElement.className = 'collapsibleOpen';
toggleElement.src = OPEN_IMAGE;
} else {
toggleElement.className = 'collapsibleClosed';
toggleElement.src = CLOSED_IMAGE;
}
// toggle display of sublists
for (var i=0;i<sublistElements.length;i++){
sublistElements[i].style.display=
(sublistElements[i].style.display=='block')?'none':'block';
}
}
}
Internet Explorer (until version 8, and then only in best standards mode) has a very broken implementation of setAttribute and getAttribute.
It effectively looks something like this:
function setAttribute(attribute, value) {
this[attribute] = value;
function getAttribute(attribute, value) {
return this[attribute];
}
This works fine iif the attribute name matches the property name, and the property takes a string value.
This isn't the case for the class attribute, where the matching property is className.
Use foo.className = 'bar'; instead of foo.setAttribute('class', 'bar');
node.onclick=createToggleFunction(node,list);
That is probably not what you want. Does createToggleFunction return a function? If it doesn't, then I bet you meant this:
node.onClick = function() { createToggleFunction(node, list); };
If my guess is right then the way you have it will set the onClick event handler to be the result of createToggleFunction, not a function like it needs to be.

Categories

Resources