How to create a visual diff view like Stack Overflow does? - javascript

Stack Overflow's diff view is very good. I want to do this using javascript, but I don't know how to start, who can give some suggestion?
such as:

you can try google-diff-match-patch project ,this project offer robust algorithms to perform the operations required for synchronizing plain text.
Demo:http://jsfiddle.net/N6bAn/
Code:
<div class="test">
<div id="oldStr" class="text">the stackoverflow question and answer version control is very well,i want to do this use javascript,but i don't know how to start,who can give some suggestion?thanks</div>
<div id="newStr" class="text">Stack Overflow's diff view is very good. I want to do this using javascript,but i don't know how to start,who can give some suggestion?thanks</div>
</div>
<input type="button" value="GO" onclick="launch()" />
<div class="test">
<div class="text" id="outputOldStr"></div>
<div class="text" id="outputNewStr"></div>
</div>
<script type="text/javascript">
var dmp = new diff_match_patch();
function launch() {
var text1 = document.getElementById('oldStr').innerHTML;
var text2 = document.getElementById('newStr').innerHTML;
dmp.Diff_EditCost = 8;
var d = dmp.diff_main(text1, text2);
dmp.diff_cleanupEfficiency(d);
var oldStr = "", newStr = "";
for (var i = 0, j = d.length; i < j; i++) {
var arr=d[i];
if (arr[0] == 0) {
oldStr += arr[1];
newStr += arr[1];
} else if (arr[0] == -1) {
oldStr += "<span class='text-del'>" + arr[1] + "</span>";
} else {
newStr += "<span class='text-add'>" + arr[1] + "</span>";
}
}
document.getElementById('outputOldStr').innerHTML = oldStr;
document.getElementById('outputNewStr').innerHTML = newStr;
}
</script>

There are JavaScript libraries that does diff visualization. These are a few examples I found:
https://github.com/cemerick/jsdifflib
http://prettydiff.com/
I haven't tried any of them, so unfortunately I can't tell you which is most suited for you needs, but it might be worth checking them out.
Update
jsdifflib looks promising, there is a demo available that you could try.

Related

JS. How do I create a regex pattern by concatenation with variables

I am not able to fix the following:
<html>
<head>
<title>Test</title>
<script>
function myFunction(arr) {
var N = [0,1,2,3,4,5,6,7,8,9];
for (var s in N) {
var pattern = new RegExp('/^[A-z]et_[' + s + ']_\\d/');
// NOTE I get the following, is that how it should be?
// window.alert(pattern); => /\/^[A-z]et_[0]_\d\//
// NOTE: I checked that it works fine for a single digit case, say:
// var pattern = new RegExp(/^[A-z]et_[3]_\d/);
var newarr = arr.filter(elt => pattern.test(elt));
document.getElementById("demo").innerHTML = newarr;
}}
</script>
</head>
<body>
<div id="demo" onclick="myFunction(['aaaLet_0_0', 'Let_1_99', 'Let_2_', 'Let_3_99', 'Pet_2_', 'Pet_3_99', '_9_33']);">click here</div>
<hr>
<p>expected output: Let_1_99, Let_3_99, Pet_3_99</p>
</body>
</html>
I see many similar questions, but I have not been able to find out how to fix my code. It should be possible, shouldn't it?
EDIT
the following is what I need:
<html>
<head>
<title>Test</title>
<script>
var newarr = [];
function myFunction(arr) {
var N = [0,1,2,3,4,5,6,7,8,9];
for (var s in N) {
var pattern = new RegExp('^[A-z]et_' + s + '_\\d'); // NOTE: not /
var lnewarr = arr.filter(elt => pattern.test(elt));
if(typeof lnewarr !== 'undefined' && lnewarr.length > 0){newarr.push(lnewarr)};
}
document.getElementById("demo").innerHTML = newarr;
}
</script>
</head>
<body>
<div id="demo" onclick="myFunction(['aaaLet_0_0', 'Let_1_99', 'Let_2_', 'Let_3_99', 'Pet_2_', 'Pet_3_99', '_9_33']);">click here</div>
<hr>
<p>expected output: Let_1_99, Let_3_99, Pet_3_99</p>
</body>
</html>
(sorry if my post is mostly code. Hope it may helps somebody out there.)
Instead of for loop you can use a .join like this:
var pattern = new RegExp('^[A-Za-z]et_[' + N.join('') + ']_\\d');
//=> /^[A-Za-z]et_[0123456789]_\d/
This works for the case when you have singe character values in your array N.
For generic use you can use this expression:
var pattern = new RegExp('^[A-Za-z]et_(?:' + N.join('|') + ')_\\d');
//=> /^[A-Za-z]et_(?:0|1|2|3|4|5|6|7|8|9)_\d/
Using a for loop you can do this:
var N = [0,1,2,3,4,5,6,7,8,9];
var str='(?:';
for (var s in N)
str += s + '|';
str = str.replace(/\|$/, ')');
var pattern = new RegExp('^[A-Za-z]et_' + str + '_\\d');
//=> /^[A-Za-z]et_(?:0|1|2|3|4|5|6|7|8|9)_\d/

javascript Bubble sort problems (probably very easy)

<html>
<script>
var tal;
var array = [];
var element=parseIFloat();
function bubbleSort(A){
var swapped,
len = A.length;
if(len === 1) return;
do {
swapped = false;
for(var i=1;i<len;i++) {
if(A[i-1] > A[i]) {
var b = A[i];
A[i] = A[i-1];
A[i-1] = b;
swapped = true;
}
}
}
while(swapped)
}
function insertnumber(){
var element=document.getElementById("element").value;
insert (element,array);
}
function insert(element, array) {
array.push(element);
alert(array);
bubbleSort(array);
alert(array);
}
</script>
<body>
<input type="button" value="Mata in" onclick="insertnumber()" id="resultat">
tal<input type="number" id="element" autofocus>
</body>
</html>
This my code but i really dont know how to get it working again, my problem is that i cant get it to read numbers correctly, trying to use "var element=parseIFloat(); " but that doesnt seem to work..
Thanks :)
Sure, var element=parseIFloat();
was meant to be var element=parseFloat();
and put between
var element=document.getElementById("element").value;
and
insert (element,array);

function is not working in my code

my problem is that text3 is undefined in my codes in here:
t += text2 + "Case #" + i + ":" + "<br>" + text3 + "<br>";
but it is here:
$('#pass').keyup(function (e) {
var strong = new RegExp("^(?=.{11,})(((?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[a-z])(?=.*\\W))|((?=.*[a-z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]))).*$", "g");
var normal = new RegExp("^(?=.{4,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[a-z])(?=.*\\W))|((?=.*[0-9])(?=.*\\W))).*$", "g");
if (strong.test($(this).val())) {
text3 = "strong";
} else if (normal.test($(this).val())) {
text3 = "normal";
} else {
text3 = "weak";
}
return true;
});
here is all of my code:
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<p><input placeholder="number of tests" type="text" name="numbers" id="x"/></p>
<div id="passdiv"></div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$('#x').keyup(function (e) {
var i;
var text2 = '';
var t = "";
var x = document.getElementById("x").value;
for (i = 1; i <= x; i++) {
text2 = '<p><input placeholder="test NO. ' + i + '" type="password" id="pass" /></p>';
t += text2 + "Case #" + i + ":" + "<br>" + text3 + "<br>";
}
document.getElementById("passdiv").innerHTML = t;
return true;
});
$('#pass').keyup(function (e) {
var strong = new RegExp("^(?=.{11,})(((?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[a-z])(?=.*\\W))|((?=.*[a-z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]))).*$", "g");
var normal = new RegExp("^(?=.{4,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[a-z])(?=.*\\W))|((?=.*[0-9])(?=.*\\W))).*$", "g");
if (strong.test($(this).val())) {
text3 = "strong";
} else if (normal.test($(this).val())) {
text3 = "normal";
} else {
text3 = "weak";
}
return true;
});
</script>
</body>
</html>
what is the problem?
please help
Looks like $('#x').keyup() is being called before $('#pass').keyup()
Your call $('#x').keyup(function (e) { is creating the first event listener so on keyup you will always endup with text3 is undefined because the $('#pass').keyup(function (e) { will be triggered always later.
EDIT:
Your second keyup handler will never work because it will grab the #pass element only once (during document parse). You need to create some defered listener to fix it.
// Anyway this won't fix your text3 is undefined problem.
What you need to do is define it first before the two .keyup handlers.
NOTE:
But please avoid setting global variables anyway ;)
Put everything into a closure or something.
Last but not least DO NOT create many elements with the same ID this is a major bug.
Look, even after fixing the code to get it to work it makes very little sense. Using roryok's jsFiddle, it'll only work if the value you're entering is a number and doing so just spawns the paragraph elements for the number you entered. You can enter as many numbers as you'd like (before your browser crashes), it'll always return as "weak".
If it's a simple password strength meter you're after, unless you can explain the logic you're trying to achieve more by forcing it to stick to numbers, I'd dump most of the JavaScript code and reduce it to
$('#x').keyup(function (e) {
document.getElementById("passdiv").innerHTML = strength($(this).val());
return true;
});
function strength(val) {
var strong = new RegExp("^(?=.{11,})(((?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[a-z])(?=.*\\W))|((?=.*[a-z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]))).*$", "g");
var normal = new RegExp("^(?=.{4,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[a-z])(?=.*\\W))|((?=.*[0-9])(?=.*\\W))).*$", "g");
if (strong.test(val)) {
t = "strong";
} else if (normal.test(val)) {
t = "normal";
} else {
t = "weak";
}
return t;
}
This will then validate the whole input each time you enter a character, which the user can then submit once it's "strong".
Here's my jsFiddle: http://jsfiddle.net/xqooj482/
text3 is not set as a variable in your code, therefore it's always going to be undefined. You need to set it before your two functions.
Note: I also put things inside a jQuery ready function.
For some reason I'm being downvoted, but I tested this and it works
<!DOCTYPE html>
<html>
<head>
<meta charset="UTF-8">
</head>
<body>
<p><input placeholder="number of tests" type="text" name="numbers" id="x"/></p>
<div id="passdiv"></div>
<script src="http://ajax.googleapis.com/ajax/libs/jquery/1.11.1/jquery.min.js" type="text/javascript"></script>
<script type="text/javascript">
$(function(){
// set text3 in here first
var text3 = "";
$('#x').keyup(function (e) {
var i;
var text2 = '';
var t = "";
var x = document.getElementById("x").value;
for (i = 1; i <= x; i++) {
text2 = '<p><input placeholder="test NO. ' + i + '" type="password" id="pass" /></p>';
t += text2 + "Case #" + i + ":" + "<br>" + text3 + "<br>";
}
document.getElementById("passdiv").innerHTML = t;
return true;
});
$('#pass').keyup(function (e) {
var strong = new RegExp("^(?=.{11,})(((?=.*[A-Z])(?=.*[a-z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[a-z])(?=.*\\W))|((?=.*[a-z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[0-9])(?=.*\\W))|((?=.*[A-Z])(?=.*[a-z])(?=.*[0-9]))).*$", "g");
var normal = new RegExp("^(?=.{4,})(((?=.*[A-Z])(?=.*[a-z]))|((?=.*[A-Z])(?=.*[0-9]))|((?=.*[a-z])(?=.*[0-9]))|((?=.*[a-z])(?=.*\\W))|((?=.*[0-9])(?=.*\\W))).*$", "g");
if (strong.test($(this).val())) {
text3 = "strong";
} else if (normal.test($(this).val())) {
text3 = "normal";
} else {
text3 = "weak";
}
return true;
});
});
</script>
</body>
</html>
Also here's a fiddle of it working
http://jsfiddle.net/gsuy4t27/

HTML5 Javascript, Updating a text using arrays

Dont mind my code, it is probably very terrible in the eyes of professionals aha but anyway
i am coding a game where the user has to answer a question with 3 options, the question, the 3 answers are all set in arrays [1] to [10]. My problem is that when the question is asked, the question wont update on the website.
<head>
<script type="text/javascript">
var Question = new Array(10);
var Answer1 = new Array(10);
var Answer2 = new Array(10);
var Answer3 = new Array(10);
var i = 1;
(example of one question)
Question[1] = "What time is it?";
Answer1[1] = "1.I dont know";
Answer2[1] = "2.Party Time";
Answer3[1] = "3.None of your business";
</script>
(my function that writes the questions/answers)
<script type="text/javascript">
function displayQuestions() {
document.write(Question[i].toString());
document.write("\n <br>" + Answer1[i].toString());
document.write("\n <br>" + Answer2[i].toString());
document.write("\n <br>" + Answer3[i].toString());
}
</script>
</head>
<body>
<div>My Question Game!</div>
<div id="Question"><script type="text/javascript">displayQuestions();</script></div>
<button onclick="answerGet()">Answer</button>
<script type="text/javascript">
function answerGet()
{
var answer = 0;
answer = parseInt(prompt("Please enter your answer (1 - 3) "));
if (answer < 4 && answer > 0) {
} else if (isNaN(answer)) {
parseInt(prompt("It is not a number. Please enter a number from 1 to 3", ""));
} else {
parseInt(prompt("Your number (" + answer + ") is above 3. Please enter a number from 1 to 3"));
if ((answer() === CorrectAnswer[i])) {
score = score + 50;
}
i = i + 1;
alert(i);
Question = Question[i];
Answer1 = Answer1[i];
Answer2 = Answer2[i];
Answer3 = Answer3[i];
CorrectAnswer = Correctanswer[i];
}
To make your program a bit more slick, you should use jquery.
Sans that to fix your immediate problem, try calling your displayQuestions function after the correct answer is given, like the following:
Answer1 = Answer1[i];
Answer2 = Answer2[i];
Answer3 = Answer3[i];
CorrectAnswer = Correctanswer[i];
displayQuestions();
Your code isn't that bad. Here is how you can update the questions:
In your answerGet() function, add the following to the if ((answer() === CorrectAnswer[i])) block
var question = document.getElementById('question');
question.innerHTML = displayQuestions();
This will get the text from displayQuestions() and put it inside the question div. But there is still a problem, the displayQuestions() function actually prints to the screen. We want it to return text instead, like this:
function displayQuestions() {
var text = Question[i].toString();
text += "\n <br>" + Answer1[i].toString())
text += "\n <br>" + Answer2[i].toString();
text += "\n <br>" + Answer3[i].toString();
return text;
}
Now one final problem: the code that prints the first question is now wrong because the displayQuestions() function doesn't print anything, just returns the text. Lets fix that:
<div id="Question"><script type="text/javascript">document.write(displayQuestions());</script><div>
That should do it. Let me know if you have any trouble implementing that.

struggling with creating asterisks in Javascript

I've been struggling with this for some time now. What I wanted to create is to output a triangle of asterisks based on user's input. Let say user entered size 5, it would look something like this:
*
**
***
****
*****
My HTML looks like:
<p>
Size: <input type="text" id="size">
<input type="button" value="Draw" onclick="draw()">
</p>
<pre id="output">
</pre>
In my Javascript, I have:
function draw()
{
var size = customJS.get ( "size" ); //I have a custom library where it get the Id from HTML
var theTriangle = makeTriangle( size.value ); //sending in the size
customJS.set ("output", theTriangle); //will set theTriangle to display to "output" in HTML
}
function makeTriangle( theSize )
{
var allLines = ""; // an empty string to hold the entire triangle
for ( var i = 0; i <= size; i++) // this loop size times
{
var oneLine = createLine ( i <= size ); // amount of asterisks for this line
allLines += oneLine;
}
return allLines;
}
function createLine ( length )
{
var aLine = ""; // an empty string to hold the contents of this one line
for ( var j = 0; j <= i; j++ ) //this loop length times
{
aLine += '*';
}
return aLine + "<br>";
}
anyone have any tip on how I go about this? thank you so much!
Newlines in HTML normally display as spaces, but you want them to show as newlines. The pre tag makes newlines actually appear as new lines, so wrap the output in a pre tag:
customJS.set ("output", "<pre>" + theTriangle + "</pre>");
Also, you're calling createLine like this:
var oneLine = createLine ( i <= size );
i <= size yields a boolean (true or false) rather than a number. You probably mean to just pass it i:
var oneLine = createLine ( i );
Additionally, you're setting size like this:
var size = customJS.get = ( "size" );
You probably want to drop the second equals, since as is, it sets the variable size to the string "size".
And finally, you've got a few variables wrong: in makeTriangle, you're looping size times, but size is undefined; you probably meant theSize. In createLine, you're looping i times, but i is undefined; you probably meant length.
With all that, it works.
There were several bugs in your code. For example using theSize instead size as parameter in the function makeTriangle(), using i instead of length in the createLine() function in the for loop condition.
Another one was:
use
return aLine + "<br/>";
instead of
return aLine + "\n";
The working solution for your code can be found in this jsFiddle: http://jsfiddle.net/uwe_guenther/wavDH/
And below is a copy of the fiddle:
index.html
<!DOCTYPE html>
<html>
<head>
<title></title>
</head>
<body>
<p>Size:
<input type="text" id="sizeTextField">
<input id='drawButton' type="button" value="Draw">
<div id='output'></div>
</p>
<script src='main.js'></script>
</body>
</html>
main.js
(function (document) {
var drawButton = document.getElementById('drawButton'),
sizeTextField = document.getElementById('sizeTextField'),
output = document.getElementById('output');
function makeTriangle(size) {
var allLines = '';
for (var i = 0; i <= size; i++) {
var oneLine = createLine(i); // amount of asterisks for this line
allLines += oneLine;
}
return allLines;
}
function createLine(length) {
var aLine = '';
for (var j = 0; j <= length; j++) {
aLine += '*';
}
return aLine + "<br/>";
}
drawButton.onclick = function () {
output.innerHTML = makeTriangle(sizeTextField.value);
};
})(document);
You can leverage some JavaScript tricks to make the code a bit more terse:
<div style="text-align: center">
<label>Size:
<input type="text" id="size" value="5">
</label> <pre id='output'></pre>
</div>
<script>
var size = document.getElementById('size'),
output = document.getElementById('output');
function update() {
var width = +size.value, // Coerce to integer.
upsideDown = width < 0, // Check if negative.
width = Math.abs(width), // Ensure positive.
treeArray = Array(width).join('0').split('0') // Create an array of 0s "width" long.
.map(function(zero, level) { // Visit each one, giving us the chance to change it.
return Array(2 + level).join('*'); // Create a string of *s.
});
upsideDown && treeArray.reverse(); // If width was negative, stand the tree on its head.
output.innerHTML = treeArray.join('\n'); // Join it all together, and output it!
}
size.onkeyup = update;
update();
size.focus();
</script>
http://jsfiddle.net/mhtKY/4/

Categories

Resources