Changing the color of a selected link that is embedded in a table - hyperlink

I'm trying to use class names to change the color of a link after it has been selected, so that It will remain the new color, but only until another link is selected, and then it will change back.
I'm using this code that was posted by Martin Kool in this question:
<html>
<head>
<script>
document.onclick = function(evt) {
var el = window.event? event.srcElement : evt.target;
if (el && el.className == "unselected") {
el.className = "selected";
var siblings = el.parentNode.childNodes;
for (var i = 0, l = siblings.length; i < l; i++) {
var sib = siblings[i];
if (sib != el && sib.className == "selected")
sib.className = "unselected";
}
}
}
</script>
<style>
.selected { background: #f00; }
</style>
</head>
<body>
One
Two
Three
</body>
It works fine until I try to out the links in a table. Why is this? Be easy, I'm a beginner.
There is no error, the links are changing to the "selected" class, but when another link is selected, the old links are keeping the "selected" class instead of changing to "unselected". Basically, as far as I can tell, it's functioning like a vlink attribute, which is not what I'm going for.
And yes, the links are all in different cells, how would you suggest I change the code so that it works correctly?
OK, actually, I spoke too soon.
document.onclick = function(evt)
{
var el = window.event? event.srcElement : evt.target;
if (el && el.className == 'unselected')
{
var links = document.getElementsByTagName('a');
for (var i = links.length - 1; i >= 0; i--)
{
if (links[i].className == 'selected')
links[i].className = 'unselected';
}
el.className = 'selected';
}
return false;
}
This code you gave me works great, visually, it does exactly what I want it to do. However, It makes my links stop working... They change color, but dont link to anything, and then when I remove the script, they work fine. What am I doing wrong/what do I have to change to make this work?
Also, I want to do the same thing somewhere else in my website, where the links are all in one <div> tag, separated by <p> tags. How can I make this work?

You're looping through the siblings. If the links are in separate <td>'s then they're no longer siblings.
You can loop through all the links like this:
document.onclick = function(evt)
{
var el = window.event? event.srcElement : evt.target;
if (el && el.className == 'unselected')
{
var links = document.getElementsByTagName('a');
for (var i = links.length - 1; i >= 0; i--)
{
if (links[i].className == 'selected')
links[i].className = 'unselected';
}
el.className = 'selected';
}
return false;
}
I've also added a return false; at the end of the function to stop you going to '#'

Is there an error or is there just nothing happening? A good first step if you are a javascript beginner is to use a tool like Firebug so you see detailed error messages, and you can add in console.log statements to see what's going on while you run your code.

By ‘in tables’ do you mean putting each link in its own cell? Because that would make this line:
var siblings = el.parentNode.childNodes;
fail to select other links outside of the cell. You'd have to find another way to signal which element is the link container.

Related

Rails 4 and Foundation 5 - Sticky Footer?

So I was using static pages until I decided to migrate over to Rails for use in my web app.
I was able to effectively create a sticky footer with the following codePen:
http://codepen.io/aetles/pen/jAdzw
$(function(){ $(document).foundation(); });
window.onload = function() {
stickyFooter();
};
function checkForDOMChange() {
stickyFooter();
}
//check for resize event if not IE 9 or greater
window.onresize = function() {
stickyFooter();
}
//lets get the marginTop for the <footer>
function getCSS(element, property) {
var elem = document.getElementsByTagName(element)[0];
var css = null;
if (elem.currentStyle) {
css = elem.currentStyle[property];
} else if (window.getComputedStyle) {
css = document.defaultView.getComputedStyle(elem, null).
getPropertyValue(property);
}
return css;
}
function stickyFooter() {
console.log("sticky footer is firing");
if (document.getElementsByTagName("footer")[0].getAttribute("style") != null) {
document.getElementsByTagName("footer")[0].removeAttribute("style");
}
if (window.innerHeight != document.body.offsetHeight) {
var offset = window.innerHeight - document.body.offsetHeight;
var current = getCSS("footer", "margin-top");
if (isNaN(current) == true) {
document.getElementsByTagName("footer")[0].setAttribute("style","margin-top:0px;");
current = 0;
} else {
current = parseInt(current);
}
if (current+offset > parseInt(getCSS("footer", "margin-top"))) {
document.getElementsByTagName("footer")[0].setAttribute("style","margin-top:"+(current+offset)+"px;");
}
}
}
However, when I deploy it into a real-time application utilizing Rails, the event itself is getting fired (I tested with console.log messages) but it doesn't actually edit the position of the footer.
(view console in the following page)
https://still-plains-7660.herokuapp.com/
Because I'm using a partial for the footer itself, could it be that Rails doesn't know what to actually move? The source code on the rendered page looks as it should.
Is there a more elegant gem or solution I can utilize to have a sticky footer that does not have a fixed height? (I need it responsive).
Considering it works fine on a static page, I'm sure there is something I can just tweak but I can't seem to figure out why it won't stick in a Rails deployment.
I cannot remember what exactly I did when I created sticky footer using Foundation. But I think I found some solution for you.
https://github.com/coreysyms/foundationStickyFooter
http://foundation.zurb.com/forum/posts/629-sticky-footer

Getting next sibling with class in zepto

Normally this would not be a problem, but this time I don't control the dom. Anyway
<dt>foo</dt>
<dd>bar</dd>
<dd>bar
<div id="myElem">baz</div>
</dd>
<dd>bar</dd>
<dd>bar</dd>
<dd class="moo">bar</dd> <-- I want to get this one
<dd>bar</dd>
<dd>bar</dd>
<dd class="moo">bar</dd>
<dd>bar</dd>
<dd>bar</dd>
Here is what I have tried
$('#myElem').closest('dd').next('.moo').something();
$('#myElem').closest('dd').nextUntil('.moo').something();
However non of these get the next sibling with the class.
Anyone know how to traverse this?
Try
$('#myElem').closest('dd').nextAll('.moo:first').something();
or
$('#myElem').closest('dd').nextUntil('.moo').next().something();
I don't know zepto but from a quick check of the docs it doesn't look like you can do it with a simple chain. Try
var $dd = $('#myElem').closest('dd');
var $moo = $dd.next();
while (!$moo.is('.moo')){
$moo = $moo.next();
if ($moo.length == 0) break;
}
DEMO
You can accomplish by creating a simple new method:
/**
* Get the next element of a particular class, relative to a different element.
*/
var nextOfClass = function(relativeTo, className) {
var el = relativeTo, nextEl;
// Leading period will confuse Zepto.
if (className[0] === '.') className = className.slice(1);
while (el.next()) {
// If target element is found, stop
if (el.hasClass(className)) return el;
nextEl = el.next();
if (nextEl.length === 0) {
// No more siblings. Go up in DOM and restart loop to check parent
el = el.parent();
continue;
}
el = nextEl;
// End of doc. Give up.
if (el.parent().length === 0) return false;
}
};
Then you can simply use the following method:
var moo = nextOfClass($("#myElem"), '.moo');

JQM - How to detect if item is shown on screen

I'm using JQuery mobile and I would like to raise an event when the listview is scrolled and a specific item is shown on screen.
Is there an event for this?! what are my options?!
Thanks.
AFAIK there are no events in jQM to do this, but you could combine ideas from some other solutions on StackOverflow to do this.
This question provides some code to determine if an item is visible, i.e.:
function isScrolledIntoView(elem)
{
var docViewTop = $(window).scrollTop();
var docViewBottom = docViewTop + $(window).height();
var elemTop = $(elem).offset().top;
var elemBottom = elemTop + $(elem).height();
return ((elemBottom >= docViewTop) && (elemTop <= docViewBottom)
&& (elemBottom <= docViewBottom) && (elemTop >= docViewTop) );
}
You can combine this with the scrollstop event. Say you are monitoring a <li> item defined as
<li id="myiditem">
I'm being watched!!
</li>
Then in $(document).ready you can do
var watchitem;
$(document).ready(function(){
watchitem = document.getElementById ('myiditem');
/* Bind to scroll event */
$(window).bind('scrollstop', function () {
if (isScrolledIntoView( watchitem )) {
alert('monitored li item was scrolled into view');
}
});
});
Here is a jsFiddle example.

PrettyPhoto annd youtube videos overlay

I have a webpage with prettyPhoto and a youtube video inside the web page.
With jquery I do:
$("#youtubevideo embed").attr("wmode", "opaque");
also tried $("#youtubevideo embed").attr("wmode", "transparent");
In firefox image is over the youtube video, but the corners of pretty photo are missing. Not really missing because if I scroll up ad down they are shown. But still they don't appear correctly.
In Chrome video is still on top of the images :( Is there a way to fix this? Thanks
after 2 days of searching the web for the answer i've found a pure JS function that fix it in all browsers!
there you go:
function fix_flash() {
// loop through every embed tag on the site
var embeds = document.getElementsByTagName('embed');
for (i = 0; i < embeds.length; i++) {
embed = embeds[i];
var new_embed;
// everything but Firefox & Konqueror
if (embed.outerHTML) {
var html = embed.outerHTML;
// replace an existing wmode parameter
if (html.match(/wmode\s*=\s*('|")[a-zA-Z]+('|")/i))
new_embed = html.replace(/wmode\s*=\s*('|")window('|")/i, "wmode='transparent'");
// add a new wmode parameter
else
new_embed = html.replace(/<embed\s/i, "<embed wmode='transparent' ");
// replace the old embed object with the fixed version
embed.insertAdjacentHTML('beforeBegin', new_embed);
embed.parentNode.removeChild(embed);
} else {
// cloneNode is buggy in some versions of Safari & Opera, but works fine in FF
new_embed = embed.cloneNode(true);
if (!new_embed.getAttribute('wmode') || new_embed.getAttribute('wmode').toLowerCase() == 'window')
new_embed.setAttribute('wmode', 'transparent');
embed.parentNode.replaceChild(new_embed, embed);
}
}
// loop through every object tag on the site
var objects = document.getElementsByTagName('object');
for (i = 0; i < objects.length; i++) {
object = objects[i];
var new_object;
// object is an IE specific tag so we can use outerHTML here
if (object.outerHTML) {
var html = object.outerHTML;
// replace an existing wmode parameter
if (html.match(/<param\s+name\s*=\s*('|")wmode('|")\s+value\s*=\s*('|")[a-zA-Z]+('|")\s*\/?\>/i))
new_object = html.replace(/<param\s+name\s*=\s*('|")wmode('|")\s+value\s*=\s*('|")window('|")\s*\/?\>/i, "<param name='wmode' value='transparent' />");
// add a new wmode parameter
else
new_object = html.replace(/<\/object\>/i, "<param name='wmode' value='transparent' />\n</object>");
// loop through each of the param tags
var children = object.childNodes;
for (j = 0; j < children.length; j++) {
try {
if (children[j] != null) {
var theName = children[j].getAttribute('name');
if (theName != null && theName.match(/flashvars/i)) {
new_object = new_object.replace(/<param\s+name\s*=\s*('|")flashvars('|")\s+value\s*=\s*('|")[^'"]*('|")\s*\/?\>/i, "<param name='flashvars' value='" + children[j].getAttribute('value') + "' />");
}
}
}
catch (err) {
}
}
// replace the old embed object with the fixed versiony
object.insertAdjacentHTML('beforeBegin', new_object);
object.parentNode.removeChild(object);
}
}
}
now you can just run in when the page loads with jQuery:
$(document).ready(function () {
fix_flash();
}
Also you can add ?wmode=transparent to each youtube link
So if you have code like:
<iframe src="http://www.youtube.com/embed/aoZbiS20HGI">
</iframe>
You need to change it to:
<iframe src="http://www.youtube.com/embed/aoZbiS20HGI?wmode=transparent">
</iframe>

Default All Day Event to Check/Yes

Thanks for the great help. Another question. How do I set my "All Day Event" field on the calendar to default to "Checked/Yes?" If we can set the default on All Day Event to Yes, is there a way to hide the time fields (keep the date fields - just no time fields)? I'd also like to hide the "Workspace" field as well (if possible).
Thank You
Dave M
If you have access to run code on your server, I've run this from a console application and it worked like a charm:
using(SPSite site = new SPSite("http://yoursite"))
{
using(SPWeb web = site.OpenWeb())
{
SPList list = web.Lists["your list name"];
SPContentType ct = list.ContentTypes["Event"];
SPFieldLink fieldLink = ct.FieldLinks["fAllDayEvent"];
Type type = typeof(SPFieldLink);
PropertyInfo pi = type.GetProperty("Default", BindingFlags.NonPublic | BindingFlags.Instance);
pi.SetValue(fieldLink, "1", null);
ct.Update();
}
}
Source: http://pholpar.spaces.live.com/blog/cns!2CD45589973F2849!131.entry
Only modification we had to make was the SPFieldLink, the examples uses All Day Event, our lists used fAllDayEvent.
The only other way I've seen work is to modify the list's CAML (Example).
Oh, and we hid the Workspace field using Javascript:
<script language="javascript" type="text/javascript">
_spBodyOnLoadFunctionNames.push("hideFields");
function fc(FieldName) {
var arr = document.getElementsByTagName("!");
for (var i=0;i < arr.length; i++ ) {
if (arr[i].innerHTML.indexOf(FieldName) > 0) { return arr[i]; }
}
}
function hideFields() {
control = fc("Workspace");
control.parentNode.parentNode.style.display="none";
}
</script>
Source: http://sharepointsherpa.com/2008/08/26/sharepoint-2007-hiding-fields-on-newformaspx-and-editformaspx-the-easy-way/

Resources