jQuery show / hide notification if read - javascript

I'm trying to show/hide the .notification indicator when all of the .activity__item is marked as read. They can be marked read by clicking each individual item's .activity__button, or by clicking the button to mark all item's as read.
Using the function below I tried identifying whether each item has received the read state (getting the .activity__button--read class) and then hiding the notification if all of the items have been read. This doesn't seem to work here.
Is there an efficient way to show/ hide the notification indicator when all items have been read either by
Clicking them individually or
Marking all as read by clicking
the button?
$(function() {
if (!$(".activity__button").not(".activity__button--read").length) {
$(this).closest(".activity__header").find(".notification").hide();
} else {
$(this).closest(".activity__header").find(".notification").show();
} });
var open = 'fas fa-envelope-open';
var close = 'fas fa-envelope';
$(".activity__button[data-status]").off().on('click', function() {
var status = $(this).data('status');
if (status == 'unread') {
$(this).data('status', 'read').empty().html('<i class="' + open + '"></i>').addClass('activity__button--read');
$(this).closest(".activity__item").addClass('activity__item--read');
} else {
$(this).data('status', 'unread').empty().html('<i class="' + close + '"></i>').removeClass('activity__button--read');
$(this).closest(".activity__item").removeClass('activity__item--read');
}
});
$('.mark').off().on('click', function() {
var status = $(this).data('status');
if (!status || status == 'unread') {
$(this).closest(".activity__header").find(".notification").hide();
$(this).html('Mark all unread').data('status', 'read');
$(".activity__button[data-status]").each(function() {
$(this).data('status', 'read').empty().html('<i class="' + open + '"></i>').addClass('activity__button--read');
$(this).closest(".activity__item").addClass('activity__item--read');
});
} else {
$(this).html('Mark all read').data('status', 'unread');
$(this).closest(".activity__header").find(".notification").show();
$(".activity__button[data-status]").each(function() {
$(this).data('status', 'unread').empty().html('<i class="' + close + '"></i>').removeClass('activity__button--read');
$(this).closest(".activity__item").removeClass('activity__item--read');
$(this).closest(".activity__header").find(".notification").show();
});
}
});
$(function() {
if (!$(".activity__button").not(".activity__button--read").length) {
$(this).closest(".activity__header").find(".notification").hide();
} else {
$(this).closest(".activity__header").find(".notification").show();
}
});
.activity__header {
display: flex;
}
.activity__item {
position: relative;
height: 100px;
width: 300px;
border: 1px solid whitesmoke;
margin-top: -1px;
}
.activity__button {
cursor: pointer;
padding: 1rem;
font-size: 21px;
}
.activity__button svg {
color: #f8971d;
}
.activity__button.activity__button--read svg {
color: #47a877;
}
.activity__item--read {
background: #fafafa !important;
}
button {
padding: 12px;
margin: 1rem;
}
.notification {
width: 10px;
height: 10px;
border-radius: 50%;
background-color: #cb6f74;
color: #fff;
font-size: 10px;
font-weight: 600;
}
<script src="https://pro.fontawesome.com/releases/v5.8.1/js/all.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div class="activity__header">
<button class="mark" data-status="unread">Mark as Read</button>
<div class="notification"></div>
</div>
<div>
<div class="activity__item">
<div class="activity__button" data-status="unread"><i class="fas fa-envelope"></i>
</div>
</div>
<div class="activity__item">
<div class="activity__button" data-status="unread"><i class="fas fa-envelope"></i>
</div>
</div>
<div class="activity__item activity__item--read">
<div class="activity__button activity__button--read" data-status="read">
<i class="fas fa-envelope-open"></i>
</div>
</div>
<div class="activity__item">
<div class="activity__button" data-status="unread">
<i class="fas fa-envelope"></i>
</div>
</div>
</div>
</div>
data-status"read"`?

One way would be to check the state of all items each time they are updated
You could use a function like this
function updateNotificationIcon(){
var $activity_items = $('.activity__item'),
all_read = true;
// Loop through each .activity__item
$activity_items.each(function(){
// If item does NOT have the "read" class, set all_read to false
if(!$(this).hasClass('activity__item--read')){
all_read = false;
}
});
if(all_read){
$('.notification').hide();
}else{
$('.notification').show();
}
}
Then just run that function after each change to one of the item's "read" state
In your case I would update your javascript as so:
var open = 'fas fa-envelope-open';
var close = 'fas fa-envelope';
$(".activity__button[data-status]").off().on('click', function() {
var status = $(this).data('status');
if (status == 'unread') {
$(this).data('status', 'read').empty().html('<i class="' + open + '"></i>').addClass('activity__button--read');
$(this).closest(".activity__item").addClass('activity__item--read');
} else {
$(this).data('status', 'unread').empty().html('<i class="' + close + '"></i>').removeClass('activity__button--read');
$(this).closest(".activity__item").removeClass('activity__item--read');
}
// Add here
updateNotificationIcon();
});
$('.mark').off().on('click', function() {
var status = $(this).data('status');
if (!status || status == 'unread') {
$(this).closest(".activity__header").find(".notification").hide();
$(this).html('Mark all unread').data('status', 'read');
$(".activity__button[data-status]").each(function() {
$(this).data('status', 'read').empty().html('<i class="' + open + '"></i>').addClass('activity__button--read');
$(this).closest(".activity__item").addClass('activity__item--read');
});
} else {
$(this).html('Mark all read').data('status', 'unread');
$(this).closest(".activity__header").find(".notification").show();
$(".activity__button[data-status]").each(function() {
$(this).data('status', 'unread').empty().html('<i class="' + close + '"></i>').removeClass('activity__button--read');
$(this).closest(".activity__item").removeClass('activity__item--read');
$(this).closest(".activity__header").find(".notification").show();
});
}
// Add here
updateNotificationIcon();
});
$(function() {
if (!$(".activity__button").not(".activity__button--read").length) {
$(this).closest(".activity__header").find(".notification").hide();
} else {
$(this).closest(".activity__header").find(".notification").show();
}
});
function updateNotificationIcon() {
var $activity_items = $('.activity__item'),
all_read = true;
// Loop through each .activity__item
$activity_items.each(function() {
// If item does NOT have the "read" class, set all_read to false
if (!$(this).hasClass('activity__item--read')) {
all_read = false;
}
});
if (all_read) {
$('.notification').hide();
} else {
$('.notification').show();
}
}

Related

Why is my text output from next() and prev() toggle incorrect?

When clicking the arrows to change the displayed option, the incorrect options is shown.
The user should be able click on the option menu to toggle it open/cosed and be able to click on a option to select it. Alternatively, the arrows could be used to toggle through the options instead.
This is the problematic code:
<script>
$("#arrow_left_physics").click(function() {
var $selected = $(".left_menu_option_selected").removeClass("left_menu_option_selected");
var divs = $("#left_menu__variant_physics").children();
divs.eq((divs.index($selected) - 1) % divs.length).addClass("left_menu_option_selected");
$("#left_menu_open .button-text").text($($selected).text());
});
$("#arrow_right_physics").click(function() {
var $selected = $(".left_menu_option_selected").removeClass("left_menu_option_selected");
var divs = $selected.parent().children();
divs.eq((divs.index($selected) + 1) % divs.length).addClass("left_menu_option_selected");
$("#left_menu_open .button-text").text($($selected).text());
});
</script>
$("#menu_open").click(function() {
$("#menu").toggle();
});
$(".menu_option").click(function() {
if ($(this).hasClass(".menu_option_selected")) {} else {
$(".menu_option").removeClass("menu_option_selected");
$(this).addClass("menu_option_selected");
$("#menu_open .button_text").text($(this).text());
}
});
$("#arrow_left").click(function() {
var $selected = $(".menu_option_selected").removeClass("menu_option_selected");
var options = $("#menu").children();
options.eq((options.index($selected) - 1) % options.length).addClass("menu_option_selected");
$("#menu_open .button_text").text($($selected).text());
});
$("#arrow_right").click(function() {
var $selected = $(".menu_option_selected").removeClass("menu_option_selected");
var options = $("#menu").children();
options.eq((options.index($selected) + 1) % options.length).addClass("menu_option_selected");
$("#menu_open .button_text").text($($selected).text());
});
.menu_open {
Cursor: pointer;
}
.menu {
display: none;
position: absolute;
border: 1px solid;
}
.menu_option {
Cursor: pointer;
Padding: 5px;
}
.menu_option:hover {
Background-Color: black;
Color: white;
}
.menu_option_selected {
color: green;
Background-color: #00ff0a4d;
}
.menu_option_selected:hover {
color: green;
}
.arrow {
Cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<input class="arrow" type="button" id="arrow_left" value="❮" />
<input class="arrow" type="button" id="arrow_right" value="❯" />
</div>
<div>
<button class="menu_open" id="menu_open">
<span class="button_text">option1</span>
</button>
</div>
<div class="menu" id=menu>
<div class="menu_option menu_option_selected">option1</div>
<div class="menu_option">option2</div>
<div class="menu_option">option3</div>
<div class="menu_option">option4</div>
<div class="menu_option">option5</div>
<div class="menu_option">option6</div>
</div>
-It seems that the first click of the arrows isn't working and that the index function is incorrect somewhere.
The problem is this line:
$("#menu_open .button_text").text($($selected).text());
$($selected) is the option that was previously selected, so you're showing the text of the previous option, not the current option. (BTW, there's no need to wrap $selected in $(), since it's already a jQuery object.)
You should use $(".menu_option_selected").text() instead of $($selected).text() to get the current option.
You should also make the initial text of the button option1, so it matches the selected option.
$("#menu_open").click(function() {
$("#menu").toggle();
});
$(".menu_option").click(function() {
if ($(this).hasClass(".menu_option_selected")) {} else {
$(".menu_option").removeClass("menu_option_selected");
$(this).addClass("menu_option_selected");
$("#menu_open .button_text").text($(this).text());
}
});
$("#arrow_left").click(function() {
var $selected = $(".menu_option_selected").removeClass("menu_option_selected");
var options = $("#menu").children();
options.eq((options.index($selected) - 1) % options.length).addClass("menu_option_selected");
$("#menu_open .button_text").text($(".menu_option_selected").text());
});
$("#arrow_right").click(function() {
var $selected = $(".menu_option_selected").removeClass("menu_option_selected");
var options = $("#menu").children();
options.eq((options.index($selected) + 1) % options.length).addClass("menu_option_selected");
$("#menu_open .button_text").text($(".menu_option_selected").text());
});
.menu_open {
Cursor: pointer;
}
.menu {
display: none;
position: absolute;
border: 1px solid;
}
.menu_option {
Cursor: pointer;
Padding: 5px;
}
.menu_option:hover {
Background-Color: black;
Color: white;
}
.menu_option_selected {
color: green;
Background-color: #00ff0a4d;
}
.menu_option_selected:hover {
color: green;
}
.arrow {
Cursor: pointer;
}
<script src="https://cdnjs.cloudflare.com/ajax/libs/jquery/3.3.1/jquery.min.js"></script>
<div>
<input class="arrow" type="button" id="arrow_left" value="❮" />
<input class="arrow" type="button" id="arrow_right" value="❯" />
</div>
<div>
<button class="menu_open" id="menu_open">
<span class="button_text">option1</span>
</button>
</div>
<div class="menu" id=menu>
<div class="menu_option menu_option_selected">option1</div>
<div class="menu_option">option2</div>
<div class="menu_option">option3</div>
<div class="menu_option">option4</div>
<div class="menu_option">option5</div>
<div class="menu_option">option6</div>
</div>
Just another version, refactoring your javascript code with some Arrow functions.
const setButtonText = () => {
$("#menu_open .button_text").text(
$(".menu_option_selected").text()
);
}
const moveSelection = direction => {
var selected = $(".menu_option_selected")
var options = $("#menu").children()
var newIndex;
if (direction == 'right') {
newIndex = (options.index(selected) + 1) % options.length
} else {
newIndex = (options.index(selected) - 1) % options.length
}
selected.removeClass("menu_option_selected")
options.eq(newIndex).addClass("menu_option_selected")
setButtonText()
}
// inizilize menu button_text
setButtonText()
$("#arrow_left").click(() => moveSelection('left'));
$("#arrow_right").click( () => moveSelection('right'));
$("#menu_open").click( () => $("#menu").toggle());
$(".menu_option").click( function() {
$(".menu_option_selected").removeClass("menu_option_selected")
$(this).addClass("menu_option_selected")
setButtonText()
});

why my h1 title hides behind input box when slideUp executes

I have the following page, which is a wikisearch page that queries multiple wikipidia pages for the search term. The page has the title and input box somewhere around the middle; however, when I click on the botton, the title slides up, and so the input box. But the input box slides all way up covering the title. I think!... how can I prevent the inputbox from covering the title? or make the title stays at the top of page? Thanks
$(document).ready(function() {
//bringing focus to search box
window.load = function() {
document.getElementById("search-box").focus();
};
//listener for search button
$("#search").click(function() {
$("#title").slideUp(3000);
// $("#title").css("text-align", "left");
search();
});
function search() {
//grabbing the id of search result div
var srchResult = document.getElementById("results");
//string entered by user for search
var searchStr = document.getElementById("search-box").value;
//replace space with _ in search query
searchStr = searchStr.replace(" ", "_");
console.log(searchStr);
$.ajax({
url: "https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=" + searchStr + "&prop=info&inprop=url&utf8=&format=json",
dataType: "jsonp",
success: function(response) {
if (response.query.searchinfo.totalhits === 0) {
showError(searchStr);
} else {
displayResults(response);
}
},
error: function() {
alert("Something went wrong.. <br>" +
"Try again!");
}
});
function displayResults(response) {
console.log(response.query);
var search = response.query.search;
var srchLength = response.query.search.length;
srchResult.innerHTML = "";
// console.log(srchResult.innerHTML);
//pulling title and searchbox to top
// $("#title").css("margin-top:", "10px !important");
for (var i = 0; i < srchLength; i++) {
srchResult.innerHTML += '<div class="output"><h4>' + search[i].title + ' </h4><p>' + search[i].snippet + '</p></div>';
}
}
return false;
}
function showError(search) {
srchResult.innerHTML = '<div class="output text-center"><h4>No Search result for: ' + search + '</h4></div>';
}
});
body {
background-color: #495444;
}
search-input {
width: 90%;
}
center {
align-left: auto;
align-right: auto;
text-align: center;
}
.output {
background-color: white;
border-color: black;
border-width: 1px;
border-style: solid;
opacity: 0.5;
margin-top: 10px;
}
h1 {
margin-top: 200px;
color: #1484e5;
font-family: 'Josefin Sans', sans-serif;
font-size: 50px;
padding-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Josefin+Sans" rel="stylesheet">
<div class="container ">
<h1 id="title" class="text-center"><strong>WikiSearch</strong></h1>
<div id="input" class="input-group col-lg-8 offset-lg-2 col-md-8 offset-md-2 col-xs-12">
<input id="search-box" type="text" class="form-control" placeholder="Search Wikipidia Pages!..." />
<button id="search" class="btn btn-primary" onclick="#">Search</button>
</div>
<div id="results" class="col-lg-8 offset-lg-2">
</div>
</div>
Insted of using $('#title').slideUp(3000) try use $('#title').animate({'margin-top': '0'}, 3000);
Then the title will remain.
Also, you might want to remove onclick="#" from <button id="search" class="btn btn-primary" onclick="#">Search</button>
Example below.
$(document).ready(function() {
//bringing focus to search box
window.load = function() {
document.getElementById("search-box").focus();
};
//listener for search button
$("#search").click(function() {
$('#title').animate({'margin-top': '0'}, 3000);
//$("#title").slideUp(3000);
// $("#title").css("text-align", "left");
search();
});
function search() {
//grabbing the id of search result div
var srchResult = document.getElementById("results");
//string entered by user for search
var searchStr = document.getElementById("search-box").value;
//replace space with _ in search query
searchStr = searchStr.replace(" ", "_");
$.ajax({
url: "https://en.wikipedia.org/w/api.php?action=query&list=search&srsearch=" + searchStr + "&prop=info&inprop=url&utf8=&format=json",
dataType: "jsonp",
success: function(response) {
if (response.query.searchinfo.totalhits === 0) {
showError(searchStr);
} else {
displayResults(response);
}
},
error: function() {
alert("Something went wrong.. <br>" +
"Try again!");
}
});
function displayResults(response) {
var search = response.query.search;
var srchLength = response.query.search.length;
srchResult.innerHTML = "";
// console.log(srchResult.innerHTML);
//pulling title and searchbox to top
// $("#title").css("margin-top:", "10px !important");
for (var i = 0; i < srchLength; i++) {
srchResult.innerHTML += '<div class="output"><h4>' + search[i].title + ' </h4><p>' + search[i].snippet + '</p></div>';
}
}
return false;
}
function showError(search) {
srchResult.innerHTML = '<div class="output text-center"><h4>No Search result for: ' + search + '</h4></div>';
}
});
body {
background-color: #495444;
}
search-input {
width: 90%;
}
center {
align-left: auto;
align-right: auto;
text-align: center;
}
.output {
background-color: white;
border-color: black;
border-width: 1px;
border-style: solid;
opacity: 0.5;
margin-top: 10px;
}
h1 {
margin-top: 200px;
color: #1484e5;
font-family: 'Josefin Sans', sans-serif;
font-size: 50px;
padding-bottom: 5px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<link href="https://fonts.googleapis.com/css?family=Josefin+Sans" rel="stylesheet">
<div class="container ">
<h1 id="title" class="text-center"><strong>WikiSearch</strong></h1>
<div id="input" class="input-group col-lg-8 offset-lg-2 col-md-8 offset-md-2 col-xs-12">
<input id="search-box" type="text" class="form-control" placeholder="Search Wikipidia Pages!..." />
<button id="search" class="btn btn-primary">Search</button>
</div>
<div id="results" class="col-lg-8 offset-lg-2">
</div>
</div>
Add this to the h1 class
h1 {
z-index: 1000;
}
Now let's say you needed something to then go on top of the header, you'd give that element's class a z-index of something higher than 1,000, so maybe 1,001! If you needed something to go behind, simply make it 999 or lower. Using 1,000 gives you a lot of free range in either direction (+/-) to work with.

Notification alerts not working

I need to setup notification alerts for my website. I'm using this simple notification script. I have test it on my website like this.
<div id="notifications">
<div class="alert alert-danger" role="alert">
<a class="button close" style="padding-left: 10px;" href="#">×</a>
<i class="fa fa-info-circle "></i>
Thanks
</div>
</div>
Styles
#notifications {
cursor: pointer;
position: fixed;
right: 0;
z-index: 9999;
bottom: 0;
margin-bottom: 22px;
margin-right: 15px;
max-width: 300px;
}
Script
$( document ).ready(function() {
Notify = function(text, callback, close_callback, style) {
var time = '10000';
var $container = $('#notifications');
var icon = '<i class="fa fa-info-circle "></i>';
if (typeof style == 'undefined' ) style = 'warning'
var html = $('<div class="alert alert-' + style + ' hide">' + icon + " " + text + '</div>');
$('<a>',{
text: '×',
class: 'button close',
style: 'padding-left: 10px;',
href: '#',
click: function(e){
e.preventDefault()
close_callback && close_callback()
remove_notice()
}
}).prependTo(html)
$container.prepend(html)
html.removeClass('hide').hide().fadeIn('slow')
function remove_notice() {
html.stop().fadeOut('slow').remove()
}
var timer = setInterval(remove_notice, time);
$(html).hover(function(){
clearInterval(timer);
}, function(){
timer = setInterval(remove_notice, time);
});
html.on('click', function () {
clearInterval(timer)
callback && callback()
remove_notice()
});
}
});
The notification is appearing correctly because of css styling. But the script is not working. If I click close icon on notification, it's not closing. When I reload the page, it stays on the(auto closing is also not working) What ami I missing in my script?
Your requirements are a bit difficult to understand. You refer to the "notification" appearing correctly, but the only thing I see appearing is x Thanks in the bottom-right corner. However, that's not a notification, it's coming from your markup. It has no event associated with it, so nothing will happen when it is clicked.
Your main issue seems to be that you are defining something called Notify, but then not doing anything with it. To help you resolve this, please see the snippet below. It's probably not exactly what you want, but I think it's a lot closer.
$( document ).ready(function() {
Notify = function(text, callback, close_callback, style) {
var time = '10000';
var $container = $('#notifications');
var icon = '<i class="fa fa-info-circle "></i>';
if (typeof style == 'undefined' ) style = 'warning';
var html = $('<div class="alert alert-' + style + ' hide">' + icon + " " + text + '</div>');
$('<a>', {
text: '×',
class: 'button close',
style: 'padding-left: 10px;',
href: '#',
click: function(e) {
e.preventDefault();
e.stopPropagation();
close_callback();
remove_notice();
}
}).prependTo(html);
$container.prepend(html);
html.removeClass('hide').hide().fadeIn('slow');
function remove_notice() {
// html.stop().fadeOut('slow').remove()
html.fadeOut('slow', function() {
$(this).remove();
});
}
var timer = setInterval(remove_notice, time);
$(html).hover(function() {
setMessage('You hovered over me.');
clearInterval(timer);
}, function(){
if (parseInt(html.css('opacity')) === 1 ) {
// element is not currently being faded out
setMessage('You stopped hovering over me.');
timer = setInterval(remove_notice, time);
}
});
html.on('click', function() {
clearInterval(timer);
callback && callback();
remove_notice();
});
}
var notification = new Notify('This is a notification.', function() {
setMessage('You clicked my text.');
}, function() {
setMessage('You clicked my "x".');
});
});
function setMessage(messageText) {
$('#testMessage').text(messageText);
}
#notifications {
cursor: pointer;
position: fixed;
right: 0;
z-index: 9999;
bottom: 0;
margin-bottom: 22px;
margin-right: 15px;
max-width: 300px;
}
#testMessage {
position: fixed;
right: 0;
z-index: 9999;
top: 0;
margin-top: 22px;
margin-right: 15px;
max-width: 300px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/notify/0.4.2/notify.min.js"></script>
<div id="testMessage"></div>
<div id="notifications">
<!-- <div class="alert alert-danger" role="alert">
<a class="button close" style="padding-left: 10px;" href="#">×</a>
<i class="fa fa-info-circle "></i>
Thanks
</div> -->
</div>

Connect two div by line with jquery function

I have two groups of quiz.
The first group is correct but the second group is not showing the line between two points.
The users click the point on the left and click the point on the right, then JavaScript creates a "canvas" line from the first element to the second element.
(I apologise for my english, it's my second language)
(function($) {
$.fn.connect = function(param) {
var _canvas;
var _ctx;
var _lines = new Array(); //This array will store all lines (option)
var _me = this;
var _parent = param || document;
var _lengthLines = $(_parent + ' .group1 .node').length;
var _selectFirst = null;
//Initialize Canvas object
_canvas = $('<canvas/>')
.attr('width', $(_me).width())
.attr('height', $(_me).height())
.css('position', 'absolute');
$(_parent).prepend(_canvas);
//$(_canvas).insertBefore(_parent);
this.drawLine = function(option) {
//It will push line to array.
_lines.push(option);
this.connect(option);
};
this.drawAllLine = function(option) {
/*Mandatory Fields------------------
left_selector = '.class',
data_attribute = 'data-right',
*/
if (option.left_selector != '' && typeof option.left_selector !== 'undefined' && $(option.left_selector).length > 0) {
$(option.left_selector).each(function(index) {
var option2 = new Object();
$.extend(option2, option);
option2.left_node = $(this).attr('id');
option2.right_node = $(this).data(option.data_attribute);
if (option2.right_node != '' && typeof option2.right_node !== 'undefined') {
_me.drawLine(option2);
}
});
}
};
//This Function is used to connect two different div with a dotted line.
this.connect = function(option) {
_ctx = _canvas[0].getContext('2d');
//
_ctx.beginPath();
try {
var _color;
var _dash;
var _left = new Object(); //This will store _left elements offset
var _right = new Object(); //This will store _right elements offset
var _error = (option.error == 'show') || false;
/*
option = {
left_node - Left Element by ID - Mandatory
right_node - Right Element ID - Mandatory
status - accepted, rejected, modified, (none) - Optional
style - (dashed), solid, dotted - Optional
horizantal_gap - (0), Horizantal Gap from original point
error - show, (hide) - To show error or not
width - (2) - Width of the line
}
*/
if (option.left_node != '' && typeof option.left_node !== 'undefined' && option.right_node != '' && typeof option.right_node !== 'undefined' && $(option.left_node).length > 0 && $(option.right_node).length > 0) {
//To decide colour of the line
switch (option.status) {
case 'accepted':
_color = '#0969a2';
break;
case 'rejected':
_color = '#e7005d';
break;
case 'modified':
_color = '#bfb230';
break;
case 'none':
_color = 'grey';
break;
default:
_color = 'grey';
break;
}
//To decide style of the line. dotted or solid
switch (option.style) {
case 'dashed':
_dash = [4, 2];
break;
case 'solid':
_dash = [0, 0];
break;
case 'dotted':
_dash = [4, 2];
break;
default:
_dash = [4, 2];
break;
}
/*
console.log($(option.left_node));
$(option.left_node)
$(option.right_node).data('connect',true);
*/
//If left_node is actually right side, following code will switch elements.
$(option.right_node).each(function(index, value) {
_left_node = $(option.left_node);
_right_node = $(value);
_left_node.attr('data-connect', true);
_right_node.attr('data-connect', true);
if (_left_node.offset().left >= _right_node.offset().left) {
_tmp = _left_node
_left_node = _right_node
_right_node = _tmp;
}
//Get Left point and Right Point
_left.x = _left_node.offset().left + _left_node.outerWidth();
_left.y = _left_node.offset().top + (_left_node.outerHeight() / 2);
_right.x = _right_node.offset().left;
_right.y = _right_node.offset().top + (_right_node.outerHeight() / 2);
//Create a group
//var g = _canvas.group({strokeWidth: 2, strokeDashArray:_dash});
//Draw Line
var _gap = option.horizantal_gap || 0;
_ctx.moveTo(_left.x, _left.y);
if (_gap != 0) {
_ctx.lineTo(_left.x + _gap, _left.y);
_ctx.lineTo(_right.x - _gap, _right.y);
}
_ctx.lineTo(_right.x, _right.y);
if (!_ctx.setLineDash) {
_ctx.setLineDash = function() {}
} else {
_ctx.setLineDash(_dash);
}
_ctx.lineWidth = option.width || 2;
_ctx.strokeStyle = _color;
_ctx.stroke();
});
//option.resize = option.resize || false;
} else {
if (_error) alert('Mandatory Fields are missing or incorrect');
}
} catch (err) {
if (_error) alert('Mandatory Fields are missing or incorrect');
}
//console.log(_canvas);
};
//It will redraw all line when screen resizes
$(window).resize(function() {
console.log(_me);
_me.redrawLines();
});
$(_parent + ' .group1 .node span').click(function() {
//console.log($(this).attr('data-connect'));
//[data-use="false"]
_this = this;
if ($(_this).attr('data-connect') != 'true' && $(_this).attr('data-use') == 'false') {
$(_parent + ' .group1 .node span').attr('data-use', 'false');
$(_this).attr('data-use', 'true');
_selectFirst = _this;
} else if ($(_this).attr('data-connect') == 'true') {
//console.log($(this).attr('data-id'));
//console.log(entry);
_lines.forEach(function(entry, index) {
if ($(_this).attr('data-id') == entry.id_left) {
$(entry.left_node).attr('data-use', 'false').attr('data-connect', 'false')
$(entry.right_node).attr('data-use', 'false').attr('data-connect', 'false')
_lines.splice(index, 1)
}
});
_me.redrawLines();
}
});
$(_parent + ' .group2 .node span[data-use="false"]').click(function() {
if ($(_parent + ' .group1 .node span[data-use="true"]').length == 1 && _selectFirst != null) {
if ($(this).attr('data-connect') != 'true') {
_me.drawLine({
id_left: $(_selectFirst).attr('data-id'),
id_right: $(this).attr('data-id'),
left_node: _selectFirst,
right_node: this,
horizantal_gap: 10,
error: 'show',
width: 1,
status: 'accepted'
});
$(_selectFirst).attr('data-use', 'false');
$(_selectFirst).attr('data-connect', 'true');
$(this).attr('data-use', 'false');
$(this).attr('data-connect', 'true');
}
}
});
this.redrawLines = function() {
_ctx.clearRect(0, 0, $(_me).width(), $(_me).height());
_lines.forEach(function(entry) {
entry.resize = true;
_me.connect(entry);
});
};
return this;
};
}(jQuery));
.clearfix {
clear: both;
}
body {
padding: 0px;
margin: 0px;
}
.nodes {
width: 500px
}
.node {
width: 100px;
background: #ddd;
color: #fff;
margin-bottom: 10px;
}
.group1 span {
background: #666;
border-radius: 50%;
width: 10px;
height: 10px;
margin-top: 5px;
}
.group2 span {
border: 1px solid #666;
border-radius: 50%;
width: 10px;
height: 10px;
margin-top: 5px;
}
.node span:hover {
background: #ff0000;
cursor: pointer;
}
.group1 {
float: left;
}
.group2 {
float: right;
}
.group2 .node span {
float: left;
position: relative;
left: -15px;
}
.group1 .node span {
float: right;
position: relative;
right: -15px;
}
.node span[data-connect=true] {
background: #ff00ff !important;
}
.node span[data-use=true] {
background: #ff0000 !important;
}
<div id="parentNodes_11">
<div class="nodes">
<div class="group1">
<div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="group2">
<div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="clearfix"></div>
</div>
</div>
<br>
<div id="parentNodes_12">
<div class="nodes">
<div class="group1">
<div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="group2">
<div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="clearfix"></div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#parentNodes_11 .nodes').connect('#parentNodes_11');
$('#parentNodes_12 .nodes').connect('#parentNodes_12');
});
</script>
This is due to the use of absolute coordinates for lines instead of relative ones, so your lines doesn't fit on the canvas.
You can just do the parent offset adjustment and it will work like this:
(function($) {
$.fn.connect = function(param) {
var _canvas;
var _ctx;
var _lines = new Array(); //This array will store all lines (option)
var _me = this;
var _parent = param || document;
var _lengthLines = $(_parent + ' .group1 .node').length;
var _selectFirst = null;
//Initialize Canvas object
_canvas = $('<canvas/>')
.attr('width', $(_me).width())
.attr('height', $(_me).height())
.css('position', 'absolute');
$(_parent).prepend(_canvas);
//$(_canvas).insertBefore(_parent);
this.drawLine = function(option) {
//It will push line to array.
_lines.push(option);
this.connect(option);
};
this.drawAllLine = function(option) {
/*Mandatory Fields------------------
left_selector = '.class',
data_attribute = 'data-right',
*/
if (option.left_selector != '' && typeof option.left_selector !== 'undefined' && $(option.left_selector).length > 0) {
$(option.left_selector).each(function(index) {
var option2 = new Object();
$.extend(option2, option);
option2.left_node = $(this).attr('id');
option2.right_node = $(this).data(option.data_attribute);
if (option2.right_node != '' && typeof option2.right_node !== 'undefined') {
_me.drawLine(option2);
}
});
}
};
//This Function is used to connect two different div with a dotted line.
this.connect = function(option) {
_ctx = _canvas[0].getContext('2d');
//
_ctx.beginPath();
try {
var _color;
var _dash;
var _left = new Object(); //This will store _left elements offset
var _right = new Object(); //This will store _right elements offset
var _error = (option.error == 'show') || false;
/*
option = {
left_node - Left Element by ID - Mandatory
right_node - Right Element ID - Mandatory
status - accepted, rejected, modified, (none) - Optional
style - (dashed), solid, dotted - Optional
horizantal_gap - (0), Horizantal Gap from original point
error - show, (hide) - To show error or not
width - (2) - Width of the line
}
*/
if (option.left_node != '' && typeof option.left_node !== 'undefined' && option.right_node != '' && typeof option.right_node !== 'undefined' && $(option.left_node).length > 0 && $(option.right_node).length > 0) {
//To decide colour of the line
switch (option.status) {
case 'accepted':
_color = '#0969a2';
break;
case 'rejected':
_color = '#e7005d';
break;
case 'modified':
_color = '#bfb230';
break;
case 'none':
_color = 'grey';
break;
default:
_color = 'grey';
break;
}
//To decide style of the line. dotted or solid
switch (option.style) {
case 'dashed':
_dash = [4, 2];
break;
case 'solid':
_dash = [0, 0];
break;
case 'dotted':
_dash = [4, 2];
break;
default:
_dash = [4, 2];
break;
}
/*
console.log($(option.left_node));
$(option.left_node)
$(option.right_node).data('connect',true);
*/
//If left_node is actually right side, following code will switch elements.
$(option.right_node).each(function(index, value) {
_left_node = $(option.left_node);
_right_node = $(value);
_left_node.attr('data-connect', true);
_right_node.attr('data-connect', true);
if (_left_node.offset().left >= _right_node.offset().left) {
_tmp = _left_node
_left_node = _right_node
_right_node = _tmp;
}
//Get Left point and Right Point
_left.x = _left_node.offset().left + _left_node.outerWidth();
_left.y = _left_node.offset().top + (_left_node.outerHeight() / 2) - _left_node.parents('.nodes').offset().top;
_right.x = _right_node.offset().left;
_right.y = _right_node.offset().top + (_right_node.outerHeight() / 2) - _right_node.parents('.nodes').offset().top;
//Create a group
//var g = _canvas.group({strokeWidth: 2, strokeDashArray:_dash});
//Draw Line
var _gap = option.horizantal_gap || 0;
_ctx.moveTo(_left.x, _left.y);
if (_gap != 0) {
_ctx.lineTo(_left.x + _gap, _left.y);
_ctx.lineTo(_right.x - _gap, _right.y);
}
_ctx.lineTo(_right.x, _right.y);
if (!_ctx.setLineDash) {
_ctx.setLineDash = function() {}
} else {
_ctx.setLineDash(_dash);
}
_ctx.lineWidth = option.width || 2;
_ctx.strokeStyle = _color;
_ctx.stroke();
});
//option.resize = option.resize || false;
} else {
if (_error) alert('Mandatory Fields are missing or incorrect');
}
} catch (err) {
if (_error) alert('Mandatory Fields are missing or incorrect');
}
//console.log(_canvas);
};
//It will redraw all line when screen resizes
$(window).resize(function() {
console.log(_me);
_me.redrawLines();
});
$(_parent + ' .group1 .node span').click(function() {
//console.log($(this).attr('data-connect'));
//[data-use="false"]
_this = this;
if ($(_this).attr('data-connect') != 'true' && $(_this).attr('data-use') == 'false') {
$(_parent + ' .group1 .node span').attr('data-use', 'false');
$(_this).attr('data-use', 'true');
_selectFirst = _this;
} else if ($(_this).attr('data-connect') == 'true') {
//console.log($(this).attr('data-id'));
//console.log(entry);
_lines.forEach(function(entry, index) {
if ($(_this).attr('data-id') == entry.id_left) {
$(entry.left_node).attr('data-use', 'false').attr('data-connect', 'false')
$(entry.right_node).attr('data-use', 'false').attr('data-connect', 'false')
_lines.splice(index, 1)
}
});
_me.redrawLines();
}
});
$(_parent + ' .group2 .node span[data-use="false"]').click(function() {
if ($(_parent + ' .group1 .node span[data-use="true"]').length == 1 && _selectFirst != null) {
if ($(this).attr('data-connect') != 'true') {
_me.drawLine({
id_left: $(_selectFirst).attr('data-id'),
id_right: $(this).attr('data-id'),
left_node: _selectFirst,
right_node: this,
horizantal_gap: 10,
error: 'show',
width: 1,
status: 'accepted'
});
$(_selectFirst).attr('data-use', 'false');
$(_selectFirst).attr('data-connect', 'true');
$(this).attr('data-use', 'false');
$(this).attr('data-connect', 'true');
}
}
});
this.redrawLines = function() {
_ctx.clearRect(0, 0, $(_me).width(), $(_me).height());
_lines.forEach(function(entry) {
entry.resize = true;
_me.connect(entry);
});
};
return this;
};
}(jQuery));
.clearfix {
clear: both;
}
body {
padding: 0px;
margin: 0px;
}
.nodes {
width: 500px
}
.node {
width: 100px;
background: #ddd;
color: #fff;
margin-bottom: 10px;
}
.group1 span {
background: #666;
border-radius: 50%;
width: 10px;
height: 10px;
margin-top: 5px;
}
.group2 span {
border: 1px solid #666;
border-radius: 50%;
width: 10px;
height: 10px;
margin-top: 5px;
}
.node span:hover {
background: #ff0000;
cursor: pointer;
}
.group1 {
float: left;
}
.group2 {
float: right;
}
.group2 .node span {
float: left;
position: relative;
left: -15px;
}
.group1 .node span {
float: right;
position: relative;
right: -15px;
}
.node span[data-connect=true] {
background: #ff00ff !important;
}
.node span[data-use=true] {
background: #ff0000 !important;
}
<div id="parentNodes_11">
<div class="nodes">
<div class="group1">
<div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="group2">
<div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="clearfix"></div>
</div>
</div>
<br>
<div id="parentNodes_12">
<div class="nodes">
<div class="group1">
<div class="node">1<span class="node1" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">2 <span class="node2" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">3 <span class="node3" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="group2">
<div class="node">A <span class="node4" data-connect="false" data-id="0" data-use="false"></span></div>
<div class="node">B <span class="node5" data-connect="false" data-id="1" data-use="false"></span></div>
<div class="node">C <span class="node6" data-connect="false" data-id="2" data-use="false"></span></div>
</div>
<div class="clearfix"></div>
</div>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.11.0/jquery.min.js"></script>
<script src="http://ajax.googleapis.com/ajax/libs/jqueryui/1.10.4/jquery-ui.min.js"></script>
<script type="text/javascript">
$(document).ready(function() {
$('#parentNodes_11 .nodes').connect('#parentNodes_11');
$('#parentNodes_12 .nodes').connect('#parentNodes_12');
});
</script>

Javascript is adding active class but not remove when click other button

function grid_view() {
grid_view_result();
grid_view_button();
}
function grid_view_active() {
if (document.getElementById("grid_view").className == "fa fa-th-large m-l-5") {
document.getElementById("grid_view").className = "fa fa-th-large m-l-5 active";
}
}
function grid_view_inactive() {
if (document.getElementById("grid_view").className == "fa fa-th-large m-l-5 active") {
document.getElementById("grid_view").className = "fa fa-th-large m-l-5";
}
}
function grid_view_button() {
if (document.getElementById("cooking_result").className == "recipes grid") {
grid_view_active();
return;
}
if (document.getElementById("cooking_result").className = "recipes list") {
grid_view_inactive();
return;
}
}
function grid_view_result() {
if (document.getElementById("cooking_result").className == "recipes list") {
document.getElementById("cooking_result").className = "recipes grid";
}
}
function list_view() {
list_view_result();
list_view_button();
}
function list_view_active() {
if (document.getElementById("list_view").className == "fa fa-th-list m-l-5") {
document.getElementById("list_view").className = "fa fa-th-list m-l-5 active";
}
}
function list_view_inactive() {
if (document.getElementById("list_view").className == "fa fa-th-list m-l-5 active") {
document.getElementById("list_view").className = "fa fa-th-list m-l-5";
}
}
function list_view_button() {
if (document.getElementById("cooking_result").className == "recipes list") {
list_view_active();
return;
}
if (document.getElementById("cooking_result").className = "recipes grid") {
list_view_inactive();
return;
}
}
function list_view_result() {
if (document.getElementById("cooking_result").className == "recipes grid") {
document.getElementById("cooking_result").className = "recipes list";
}
}
.active{text-decoration:underline;}
.recipes.grid li{float:left;width:50%;height:50px;background:red;}
.recipes li:nth-child(2){background:blue !important;}
.recipes.list li{float:left;width:100%;height:50px;background:red;}
<i id="grid_view" onclick="grid_view();" class="fa fa-th-large m-l-5">Grid</i>
<i id="list_view" onclick="list_view();" class="fa fa-th-list m-l-5">List</i>
<ul id="cooking_result" class="recipes grid">
<li></li>
<li></li>
</ul>
I can add class="active" to i tag but I can't remove when I click to other i tag. May you help me to fix it?
Also, If possible, may you simplify to javascript? I think it's too long for this functionality :)
Here is a tidied up solution.
The main changes I've made:
I've fixed the underline disappear/reappear issue, using classList.toggle;
I've shortened the .js quite a lot;
I've added a cosmetic change to the CSS, using pointer:
I've removed the inline .js events from the HTMLand made the .js unobtrusive
Please ask questions in the comments below if there is anything that doesn't immediately seem clear to you.
var gridView = document.getElementById("grid_view");
var listView = document.getElementById("list_view");
function grid_view() {
var cookingResult = document.getElementById("cooking_result");
var gridView = document.getElementById("grid_view");
var listView = document.getElementById("list_view");
if (cookingResult.className === "recipes list") {
cookingResult.className = "recipes grid";
gridView.classList.toggle('active');
listView.classList.toggle('active');
}
}
function list_view() {
var cookingResult = document.getElementById("cooking_result");
var gridView = document.getElementById("grid_view");
var listView = document.getElementById("list_view");
if (cookingResult.className === "recipes grid") {
cookingResult.className = "recipes list";
gridView.classList.toggle('active');
listView.classList.toggle('active');
}
}
gridView.addEventListener('click',grid_view,false);
listView.addEventListener('click',list_view,false);
.active {
text-decoration: underline;
}
.recipes.grid li {
float: left;
width: 50%;
height: 50px;
background: red;
}
.recipes.list li {
float: left;
width: 100%;
height: 50px;
background: red;
}
.recipes li:nth-of-type(2) {
background: blue;
}
#grid_view, #list_view {
cursor: pointer;
}
#grid_view.active, #list_view.active {
cursor: text;
}
<i id="grid_view" class="fa fa-th-large m-l-5 active">Grid</i>
<i id="list_view" class="fa fa-th-list m-l-5">List</i>
<ul id="cooking_result" class="recipes grid">
<li></li>
<li></li>
</ul>

Categories