HTML 5 pattern attribute - javascript

Is there a way in <select> list, for example, to make onClick activate a JavaScript function that will show the title of the element just as pattern in HTML 5 does?
I want to do that when you click on the <select>, it will activate a JavaScript function that under some condition (doesn’t matter—some if expression) will show a sentence (that I wrote) in a bubble like place (the place that the pattern shows the title when something isn’t according to the pattern (pattern in HTML5)).

You can set a custom validity error on a select element by calling the setCustomValidity method, which is part of the constraint validation API in HTML5 CR. This should cause an error to be reported, upon an attempt at submitting the form, in a manner similar to reporting pattern mismatches. Example:
<select onclick="this.setCustomValidity('Error in selection');
title="Select a good option">
(In practice, you would probably not want to use onclick but onchange. But the question specifically mentions onClick.)
There are problems, though. This only sets an error condition and makes the element match the :invalid selector, so some error indicator may happen, but the error message is displayed only when the form data is being validated due to clicking on a submit button or something similar. In theory, you could use the reportValidity method to have the error shown immediately, but browsers don’t support it yet.
On Firefox, the width of the “bubble” is limited by the width of the select element and may become badly truncated if the longest option text is short. There is a simple CSS cure to that (though with a possible impact on the select menu appearance of course).
select { min-width: 150px }
You might also consider the following alternative, which does not affect the select element appearance in the normal state but may cause it to become wider when you set the custom error:
select:invalid { min-width: 150px }
There is also the problem that Firefox does not include the title attribute value in the bubble. A possible workaround (which may or may not be feasible, depending on context) is to omit the title attribute and include all the text needed into the argument that you pass to setCustomValidity.
A possible use case that I can imagine is a form with a select menu such that some options there are not allowed depending on the user’s previous choices. Then you could have
<select onchange="if(notAllowed(this)) setCustomValidity('Selection not allowed')" ...>
where notAllowed() is a suitable testing function that you define. However, it is probably better usability to either remove or disable options in a select as soon as some user’s choices make them disallowed. Admittedly, it might mean more coding work (especially since you would need to undo that if the user changes the other data so that the options should become allowed again).

In my opinion Jukka's solution is superior however, its fairly trivial to do something approaching what you're asking for in JavaScript. I've created a rudimentary script and example jsFiddle which should be enough to get you going.
var SelectBoxTip = {
init : function(){
SelectBoxTip.createTip();
SelectBoxTip.addListeners();
},
addListeners : function(){
var selects = document.getElementsByTagName("select");
for (var i = 0; i < selects.length; i++){
var zis = selects[i];
if(zis.getAttribute('title')){//only if it has a title
zis.addEventListener("focus", SelectBoxTip.showTip, false);
zis.addEventListener("blur", SelectBoxTip.hideTip, false);
}
}
},
createTip : function(){
tip = document.createElement("div");
tip.id = "tip";
tip.style.position = "absolute";
tip.style.bottom = "100%";
tip.style.left = "0";
tip.style.backgroundColor = "yellow";
document.body.appendChild(tip);
},
showTip : function(e){
this.parentNode.appendChild(tip);
tip.innerHTML=this.title;
tip.style.display="block";
},
hideTip : function(e){
tip.style.display="none";
}
};
SelectBoxTip.init();

Related

Eliminate undefined TypeError in self-executing anonymous function

I have a script that gives me the following error: 'TypeError: clickables[ic] is undefined' when I'm checking it with Firebug/in browser consoles. I'm a javascript beginner, who is trying to learn how to do things in vanilla javascript, and so I'm looking specifically for a solution that is just that.
The question: How do I get rid of/silence the undefined TypeError?
What the script should be doing:
I'm using this to reveal hidden elements, whose display attribute is set to none. The script should be getting all the instances of a particular class in a document, .item-reveal, joining that with a unique ID that each item having that class is given, to form a new class to search for via getElementsByClassName. The items with the .item-reveal class are items that are clicked on, the item that is unhidden/revealed has the .ID-reveal-item class (the unique ID of the clickable element followed by the .item-reveal class name reversed, for a simple convention). The ID isn't used for stying at all, it's merely to create a unique class based on a naming convention that can be applied to any pair of elements: one that is clicked on, one that is unhidden/hidden via creating/changing a style for the display attribute.
What the script does:
Currently, the script actually reveals the items onclick, and hides them again on subsequent clicks, and it works with multiple items. So, it kind of, basically, works. I just can't figure out the 'TypeError: clickables[ic] is undefined' issue and how to get rid of it. I get it in several browsers when using developer tools.
The script is an attempt at a self-executing anonymous function sort of thing, so I know the convention is a bit different, but I'm wanting to stick with it so I can apply it to other uses down the road. The article that inspired it is found here:
http://esbueno.noahstokes.com/post/77292606977/self-executing-anonymous-functions-or-how-to-write
EXAMPLE:
HTML
<!-- Item to be clicked, with unique ID -->
<h3 class="item-reveal" id="plan-1">Click for special pricing!</h3>
<p>An introductory paragraph...</p>
<!-- Hidden item to be revealed, will always have a unique class -->
<p class="plan-1-reveal-item">Special, this month only: $49.99</p>
<h3 class="item-reveal" id="plan-b">Click for special pricing!</h3>
<p>An introductory paragraph...</p>
<p class="plan-b-reveal-item">Special, this month only: $29.99</p>
CSS
/* Init - hide/unhide onclicks */
.item-reveal {cursor:pointer;}
[class$="-reveal-item"] {display:none;}
/* Halt - hide/unhide onclicks */
javascript:
var clickables = document.querySelectorAll('.item-reveal');
var clickCount = clickables.length;
(function () {
var Reveal = {
swapThis: function () {
for (var ic = 0; ic <= clickCount; ic += 1) {
// Next line seems to create the error message.
clickables[ic].onclick = function (unhideHide) {
var hidden = this.id;
var findClass = hidden += '-reveal-item';
var revealSwap = document.getElementsByClassName(findClass);
for (rn = 0; rn < revealSwap.length; rn++) {
revealSwap[rn].style.display = (revealSwap[rn].style.display == 'block') ? 'none' : 'block';
}
}
}
}
}
Reveal.swapThis();
}) ();
The script is linked via a SCRIPT tag, just prior to the closing BODY tag. I have tried it with both Async and Defer attributes, with and without other scripts in an HTML document, and the result is the same. I tried adding an event handler to ensure it wasn't something with the DOM loading still ongoing, but I'm not sure how to really test for that to see if it was actually doing anything. Unit testing is something that I'm just starting to attempt familiarizing myself with.
I'm trying to knock the dust off skills after several years in a completely unrelated industry, so the last year has been all about catching up on web development technologies, learning responsive design and HTML5 data stuff, and trying to learn javascript. I've searched, read, and bought several ebooks/books, and this is one of the few times I've run into something I just can't figure out. I imagine it's probably something simple and obvious to someone with formal programming/scripting knowledge, but I was an eBusiness major and networking, marketing, server/systems support, cabling, HTML/CSS, etc., are where I'm comfortable. Any help is greatly appreciated, but keep in mind that I'm trying to implement this in an environment/project that will have no jQuery, by choice. Thanks!
You are going off the end of the list with this:
for (var ic = 0; ic <= clickCount; ic += 1)
Change it to this:
for (var ic = 0; ic < clickCount; ic += 1)
clickCount is the length of the list so since it's 0 based indexing, clickables[clickCount - 1] is the last element in the list. You were trying to access clickables[clickCount] which does not exist.

Read more opens 1st one all the time

I've a page with about 10 short articles.
Each of them as a "Read More" button which when pressed displays hidden text
The issues I have at the moment is when I press the "Read More" on any of the 10 button it shows the 1st articles hidden content and not the selected one.
I think I need to set a unique ID to each article.. and the read more button be linked to it.. But I don't know how to set it.
I looked at this but couldn't get it working how to give a div tag a unique id using javascript
var WidgetContentHideDisplay = {
init:function() {
if ($('#content-display-hide').size() == 0) return;
$('.triggerable').click(function(e){
var element_id = $(this).attr('rel');
var element = $('#'+element_id);
element.toggle();
if (element.is(':visible')) {
$('.readmore').hide();
} else {
$('.readmore').show();
}
return false;
});
}
}
var div = documentElemnt("div");
div.id = "div_" + new Date().gettime().toString;
$(document).ready(function(){ WidgetContentHideDisplay.init(); });
OP Edit: Sorry, the original code wasn't in caps. I kept getting errors when trying to post, so I copied the code into Dreamweaver and it made it all caps for some reason.
Instead of selecting the element to toggle with an ID (i.e. $('#'+ELEMENT_ID)) you could setup a class for your item and use the class selection (e.g. $('.DETAILED-ARTICLE)') to select the child (or the brother, etc. depending how you built the HTML page).
In theory each ID should point to a single element but each class can be put to as many elements as you want.
If you're getting errors, read the errors and see what they are. Off of a quick read of your code, here are a couple things I noticed that will probably cause issues:
"documentElemnt" is misspelled, which will render it useless. Also, documentElement is a read-only property, not a function like you're using it.
toString is a function, not a property, without the parentheses (.toString()) it isn't going to function like you want it to.
Run the code, look at the errors in the console, and fix them. That's where you start.

casperjs, might need another click method?

I am new to casperjs, and as far as I have learned so far, there are only two click methods that can trigger a mouse action:
click() requires a selector
clickLabel() requires "label" between tags
The website I am dealing with right now has dynamic "tabs", by clicking each tab, a javascript submit is triggered, there is no "class", "id" or "label" associated with each tab, except for "pic" element:
<a href="javascript:submitTab('search6')" tabindex="6">
<img src="image6off.gif" name="imag6" height="6" hspace="0" vspace="0" border="0" onmouseover="nbGroup('over','imag6','image6on.gif','image6on.gif',1);" onmouseout="nbGroup('out');" onclick="nbGroup('down','group1','imag6','image6off.gif',1); submitTab('search6')" alt="New Search">
</a>
I tried to use clickLabel() but failed.
YES, I can use XPath, however the problem is the number of tabs is dynamic depending on the available information for each record, so in this case "new search" could be tab 6 for this record but tab 4 in another, tab 8 in yet another.
YES, I could try to write a "loop" to loop through all available tabs, potentially, however, if there is one method of click which combine the
waitForResource()
that would be great, since I can use the "image6on.gif" to tell the program which image or tab to click, apparently, for this website, I found out that each different javascript submit tab program is uniquely associated with one "image#on/off.gif"
I hope some contributor for casperjs can easily implement this method to deal this kind of situation.
Not entirely sure if this is what you want, but you can get the tab based on the tabindex attribute with:
casper.click("a[tabindex='6']");
Edit: Hack I threw together based on your comment below:
casper.thenEvaluate(function() {
var attr = document.querySelector('img[alt="New Search"]').parentNode.getAttribute('tabindex');
__utils__.click('a[tabindex="' + attr + '"]');
});
casper.thenEvaluate() allows you to execute javascript on the remote page.
__utils__ is injected into each page loaded as an extra set of functions that you can use.
I'm not a contributor to CasperJS. From my point of view the clickLabel function is already too much. I cannot remember that I actually used it, because most of the time there is something that prevents an exact string match.
You are right, it is a valid argument to add a new click function to CasperJS. In my opinion it is better to use the provided XPath capability to do that. You can even create the function for your use:
casper.clickByImg = function(imgRes){
var x = require('casper').selectXPath;
this.click(x("//a/img[contains(#href,"+imgRes+")]/.."));
return this;
};
See: minimal overhead.
You can even go this far as to match the image by a regular expression with more overhead.
casper.clickByImgRegexp = function(regexp){
var hrefs = this.getElementsAttribute("a > img", "href");
for(var i = 0; i < hrefs.length; i++) {
if (hrefs[i].match(regexp)) {
this.clickByImg(hrefs[i]);
break;
}
}
return this;
};

jQuery hide - how to know if element has started to hide but still visible?

I have form where are inputs. Answers and visibility of the inputs may affect visibility of other inputs which are located below it.
I have javascript function which is called when value of some of the inputs have changed. The function is going through every input and checking it’s visibility and answer. Based on that information it may hide or show some other inputs. One loop is enough, because visibility of the element can’t affect visibility of previous elements.
$(".test_this").each(function() {
var id_number = $(this).attr("id").split("_")[1];
var tested_id = parseInt(id_number) + 1;
if ($(this).find("input:checked").val() != 1 || $(this).is(":hidden")) {
if ($("#element_"+tested_id).is(":visible")) {
$("#element_"+tested_id).hide();
}
}
else {
if ($("#element_"+tested_id).is(":hidden")) {
$("#element_"+tested_id).show(500);
}
}
});
My code is working well, but I would like to add duration to hide-function, but then my visibility check fails. Is it possible to know if some element has started to hide but is still visible?
I don’t want to use callback function, because it is executed after the delay. Second, I don’t want to change values of hidden inputs. One solution is to add some extra class which existence would be possible to check, but is there some better way to do this?
My code in Fiddle: http://jsfiddle.net/nmUPj/3/
For the further information, my actual code is lot more complicated and getting information about form from MySQL and generating form and javascript code with PHP.
You can check if the element is still animating by:
$("#element_"+tested_id).is(":animated")
Alternatively, you can give a callback function to your show(),
$("#element_"+tested_id).show(5000, function(){
alert('animation completed');
});

Tracking changes in web application

I have an application in which the user needs to see the changes that have been made during the latest edit.
By changes I mean, the changes made in all inputs like a textarea, dropdowns.
I am trying to implement this by showing a background image on the right top and then when the user clicks this background image, a popup is shown which shows the difference.
I am using prototype 1.7.0.
My First question would be:-
1. What would be the best approach to implement this functionality?
2. Can I put a onClick on the background image?
There some functions in the jQuery library that I believe would be helpful to you. If you are using prototype, I would guess that there is some similar functionality you may utilize.
I would suggest writing some code like this:
var $input = $('input').add('textarea').add('select');
$input.each(function() {
var id = $(this).attr('id');
var value = $(this).val();
var hiddenId = 'hidden' + id;
var newHiddenInput = $("<input type='hidden'").val(value).attr('id',hiddenId);
$(this).after(newHiddenInput);
});
The above code will create a new hidden input for each input, textarea, and select on your page. It will have the same value as the input it duplicates. It will have an id equivalent to prepending the id with the word 'hidden'.
I don't know if you can attach a click handler to a background image. If your inputs are enclosed inside a <div>, you may be able to get the result you want by attaching the click handler to your div.
In any case, you should now have the old values where you can easily compare them to the user's input so that you can prepare a summary of the difference.
Prototype gives us the Hash class which is almost perfect for this but lacks a way of calculating the difference with another hash, so let's add that...
Hash.prototype.difference = function(hash)
{
var result = this.clone();
hash.each(function(pair) {
if (result.get(pair.key) === undefined)
// exists in hash but not in this
result.set(pair.key, pair.value);
else if (result.get(pair.key) == pair.value)
// no difference so remove from result
result.unset(pair.key);
// else exists in this but not in hash
});
return result;
};
This is no way to tell if an element was clicked on just it's background image - you can find out the coordinates where it was clicked but that is not foolproof, especially since CSS3 adds complications like multiple backgrounds and transitions. It is better to have an absolutely positioned element to act as a button.
$('button-element').observe('click', function() {
var form_values = $H($('form-id').serialize(true));
if (old_values) {
var differences = old_values.difference(form_values);
if (differences.size()) {
showDiffPopup(differences);
}
}
window.old_values = form_values;
});
// preset current values in advance
window.old_values = $H($('form-id').serialize(true));
All that remains is to implement showDiffPopup to show the calculated differences.

Categories