I'm trying to create a standard javascript popup widget to provide hints across my Rails application. I'm hoping to be able to create a single popup widget where the information contained inside changes whenever different hint buttons are clicked. All of the samples I seem to find use the javascript onclick, but this won't allow me to pass in different text values based on which button was clicked. Also, I keep seeing the popup being created using html rather than being done in the javascript.
This is working to call a javascript function
<%= f.label :name %><%= link_to image_tag("hint_link.jpeg", :size=>"13x13"), '#', :onclick => 'create_hint_widget("a"); return false;' %>
But I need to know how to create a popup widget from the called function, as
function hint_widget(hint_text) { create_popup_widget }
Maybe something like this?
$( "#draggable" ).draggable().html("<div id='draggable' class='ui-widget-content'><p>hint_text</p></div>");
This was the best solution I've been able to come up with, but there may be better solutions. I'm open for any advice/suggestions
This is the basics of how you would start to construct a tooltip system - however there are thousands of already available so it does not make much sense to write one unless you are doing it to learn.
$(function(){
# delegate a handler to elements that have a `data-tooltip` attribute.
$(document).on('click', 'a[data-tooltip]', function(){
var $el = $(this)
var $tooltip = $('<div class="tooltip-overlay">').text($el.data('tooltip'));
$el.append($tooltip);
# fade out and remove tooltip after 3s
$tooltip.delay(3000).fadeOut(100).remove();
return false;
});
# handle when user clicks a tooltip
$(document).on('click', '.tooltip-overlay', function(){
$(this).remove();
return false;
});
});
a[data-tooltip] {
position: relative;
display: inline-block;
}
.tooltip-overlay {
position: absolute;
background-color: yellow;
border: 1px solid black;
top: -140%;
padding: 3px;
}
<script src="https://ajax.googleapis.com/ajax/libs/jquery/2.1.1/jquery.min.js"></script>
<p>Link without tooltip</p>
<p>Link with tooltip</p>
http://foundation.zurb.com/sites/docs/v/5.5.3/components/tooltips.html
http://getbootstrap.com/javascript/#tooltips
https://jqueryui.com/tooltip/
Related
I am normally used to "window.open" to open a popup window into a new URL. How can open a window into a new URL, shadow out/grey out the current window, and on close remove the shadow background.
Is it best to use jQuery to do this? Could I use the default libraries without use jquery plugins?
I want to do something like this and then "disable" my shadow on unload. Hopefully that uses core jQuery libraries or standard javascript calls. I want to avoid using any plugins besides jQuery.
var popup = window.open('http://google.com', 'popup');
showShadow();
$(window).unload(function() {
if(!popup.closed) {
disableShadow();
}
});
Basically, you can open the popup and set that window the beforeunload. In short, something like this:
popup = window.open("", "name", "width=400, height=300")
popup.onbeforeunload = function() { $('#shadow').hide();}
I created a fiddle for you.
http://jsfiddle.net/DDksS/
So you want to build your own modal box using jQuery instead of using an existing plugin? ...OK, let's play (as it was already pointed out, using popups is not a user-friendly solution):
Your check list :
- the trigger
- the shadow layer
- the modal box size and position
- add content to modal and display it along the shadow
1) The trigger is a simple html link to open the content inside the modal
open url
... we will pass the size of the modal via data-width and data-height (HTML5) attributtes.
2) The shadow layer is the html structure that we will append to the body after the trigger. We can set the structure in a js variable
var shadow = "<div class='shadow'></div>";
3) As we mentioned, the size of the modal is set through some data-* attributes in the link. We would need to do some math
var modalWidth = $(this).data("width");
var modalHeight = $(this).data("height");
var modalX = (($(window).innerWidth()) - modalWidth) / 2; // left position
var modalY = (($(window).innerHeight()) - modalHeight) / 2; // top position
NOTE : $(this) is our trigger selector .myModal that we'll get inside an .on("click") method later on. BTW, the .on() method requires jQuery v1.7+
4) Now we need to create the modal's html structure and pass the content href. We'll create a function
function modal(url) {
return '<div id="modal"><a id="closeModal" title="close" href="javascript:;"><img src="http://findicons.com/files/icons/2212/carpelinx/64/fileclose.png" alt="close" /></a><iframe src="' + url + '"></iframe></div>';
}
... as you can see, our structure contains a close button to remove the modal and the shadow layer. The function also gets a parameter when is called (url) which allows to set the src attribute of the iframe tag.
NOTE : we have to use the iframe tag to open external urls, however we should always consider the same origin policy and other security restrictions when using iframes.
So now, we need to put together all the events after we click on our .myModal trigger, which are appending both the shadow and the modal box to the body and to remove them when we click on the close button so
$(".myModal").on("click", function(e) {
e.preventDefault();
// get size and position
modalWidth = $(this).data("width");
modalHeight = $(this).data("height");
modalX = (($(window).innerWidth()) - modalWidth) / 2;
modalY = (($(window).innerHeight()) - modalHeight) / 2;
// append shadow layer
$(shadow).prependTo("body").css({
"opacity": 0.7
});
// append modal (call modal() and pass url)
$(modal(this.href)).appendTo("body").css({
"top": modalY,
"left": modalX,
"width": modalWidth,
"height": modalHeight
});
// close and remove
$("#closeModal").on("click", function() {
$("#modal, .shadow").remove();
});
}); // on
STYLE : of course we will need some basic CSS style to make our modal elements work properly:
.shadow {width: 100%; height: 100%; position: fixed; background-color: #444; top: 0; left:0; z-index: 400}
#modal {z-index: 500; position: absolute; background: #fff; top: 50px;}
#modal iframe {width: 100%; height: 100%}
#closeModal {position: absolute; top: -15px; right: -15px; font-size: 0.8em; }
#closeModal img {width: 30px; height: 30px;}
* SEE DEMO *
BONUS : you could also bind a keyup event to close the modal using the escape key
$(document).keyup(function(event) {
if (event.keyCode === 27) {
$("#modal, .shadow").remove();
}
}); //keyup
LAST NOTE : the code is subject to many improvements and optimization but is a basic layout of what many lightboxes do. My last recommendation : use fancybox for more advanced functionality ... sometimes it doesn't worth the effort to re-invent the wheel ;)
Using Javascript to create new popup windows is so 1990's, not to mention not very user-friendly. What you're looking for, both UI-wise and looks-wise is a modal dialog; there's billions of examples and pre-packaged jquery snippets on how to create modal dialogs, and most client-side UI frameworks such as jQuery UI, YUI and Bootstrap have modal dialog functionality built-in. I'd recommend diving into those.
Try jquery plugins such as fancybox http://fancybox.net/
Basically, you need to attach an event listener to your new window to run the disableShadow() function in your webpage.
If you add this to your code I think it should work.
popup.unload(function() { disableShadow() });
Adapted From: Attach an onload handler on a window opened by Javascript
You should use the beforeUnload event of the window instance returned by the window.open() call, like this:
popup = window.open('relative_url', 'popup');
$(popup).bind('beforeunload', function() {
disableShadow();
});
Note that the URL must be on the same domain in order for the opener window to interact with the popup!
See the fiddle here: http://jsfiddle.net/hongaar/QCABh/
You can open a new window, and when it closes you can execute a function in the opener window.
I'll do a quick example by writing the script right into the new window, but you could also just include it in the HTML that is used for the new window if a link is supplied for the popup:
$("#popupBtn").on('click', openPopup); //using a button to open popup
function openPopup() {
$('#cover').fadeIn(400);
var left = ($(window).width()/2)-(200/2),
top = ($(window).height()/2)-(150/2),
pop = window.open ("", "popup", "width=400, height=300, top="+top+", left="+left),
html = '<!DOCTYPE html>';
html += '<head>';
html += '<title>My Popup</title>';
html += '<scr'+'ipt type="text/javascript">';
html += 'window.onbeforeunload = function() { window.opener.fadeoutBG(); }';
html += '</sc'+'ript>';
html += '</head>';
html += '<body bgcolor=black>';
html += '<center><b><h2 style="color: #fff;">Welcome to my most excellent popup!</h2></b></center><br><br>';
html += '<center><b><h2 style="color: #fff;">Now close me!</h2></b></center>';
html += '</body></html>';
pop.document.write(html);
}
window.fadeoutBG = function() { //function to call from popup
$('#cover').fadeOut(400);
}
Using a fixed cover that is faded in will also prevent any clicks on elements on the page, and you could even attach a click handler to the cover with pop.close() to close the popup if the cover is clicked, just like a modal would close if you clicked outside it.
One of the advantages of calling a function on the parent page from the popup is that values can be passed from the popup to the parent, and you can do a lot of stuff you otherwise could'nt.
FULLSCREEN_FIDDLE
FIDDLE
All you need is standard javascript function showModalDialog. Then your code will look like
var url = 'http://google.com';
showShadow();
var optionalReturnValue = showModalDialog(url);
//Following code will be executed AFTER you return (close) popup window/dialog
hideShadow();
UPDATE
As hongaar stated Opera does not like showModalDialog. And it does not fire on(before)unload when popup is closed either. To make workaround you need timer (window.setTimeout) to periodically check if window still exists. For further details look here
Why don't you just use jQuery UI? I know that you don't want another library but is rather extension of jQuery rather then another lib since it can live without it.
It have great deal of widget and every one of them can be changed,configured.
What is best that it can viewed with different themes, even you can create one with they're theme roller fast and easy, and it can be modularized. Just take what you need in current project.
Check this out:
http://jqueryui.com/dialog/#modal-form
It's really simple to use. With this you can open modal dialog with frame to different url. On close event you can do whatever you want.
Try ColorBox
its simple and easy to use
http://www.jacklmoore.com/colorbox
quick example:
<link rel="stylesheet" href="http://www.jacklmoore.com/colorbox/example1/colorbox.css" />
<script src="https://ajax.googleapis.com/ajax/libs/jquery/1.8.2/jquery.min.js"></script>
<script src="http://www.jacklmoore.com/colorbox/colorbox/jquery.colorbox.js"></script>
<script>
$(document).ready(function(){
//Examples of how to assign the ColorBox event to elements
$(".iframe").colorbox({iframe:true, width:"80%", height:"80%"});
});
</script>
<a class='iframe' href="http://google.com">Outside Webpage (Iframe)</a>
You can also try this out ...
http://fancyapps.com/fancybox/
Examples here
try http://thickbox.net/ in modal type, examples: http://thickbox.net/#examples
I've done this as well.
First off, some URLs simply WILL NOT WORK in an (iframe) modal window; I can't say if it'll work in the browser-supported native modal windows as I haven't tried this. Load google or facebook in an iframe, and see what happens.
Second, things like window onunload events don't always fire (as we've seen some people already).
The accepted answer version will also only work on a static page. Any reloading (even F5 on the page) will cause the shadow to hide. Since I can't comment on the accepted answer, I at least wanted this to be known for anyone else looking at these results.
I've taken a less technical approach to solving this problem in the past: polling.
http://jsfiddle.net/N8AqH/
<html>
<head>
<script type="text/javascript">
function openWindow(url)
{
var wnd = window.open(url);
var timer = null;
var poll = function()
{
if(wnd.closed) { alert('not opened'); clearInterval(timer); }
};
timer = setInterval(poll, 1000);
}
</script>
</head>
<body>
click me
</body>
</html>
See the link above for an example. I tested in IE, FF, and Chrome. My timer is every 1 second, but the effort on the browser is so low you could easily drop this down to 100 ms or so if you wanted it to feel more instant.
All you'd have to do in this example is, after calling window.open, call your "show shadow" function and instead of alerting when you close, call your "hide shadow" function and it should achieve what you're looking for.
I decided to use NicEdit on a project, because is lightweight.
So, now I have a variable number of instances in my page, loaded on click and removed on editor blur.
I need to know how to unbind events from this component. I tried to unbind it manually, but I didn't understand where they are linked!
$('.container').bind('click', function(){
var _form = $(this).parentsUntil('form').parent();
var textarea = _form.find('textarea.edit');
var ta_id = textarea.attr('id');
var ed = new nicEditor(niceditOptions).panelInstance(ta_id);
// Show Preview and update textarea and so on
ed.addEvent('blur', function() {
var _ed = nicEditors.findEditor(ta_id);
var ev_type, evt, events = this.eventList;
for (ev_type in events){
for (evt in ev_type){
if (this.removeEventListener){
this.removeEventListener(ev_type, events[ev_type][evt]);
}
else {
this.detachEvent('on' + ev_type, events[ev_type][evt]);
}
}
}
this.removeInstance(ta_id);
});
});
There are potentially other ways of going about your solution, but in this scenario I prefer to use one version of a nicEditor panel and bind all of my WYSIWYG instances. The reason for this is that I think its slightly tidier. I will assume that you know how to bind one editor to multiple editable instances.
On load my HTML would probably look something like this:
<div id="instance1">text</div>
...
<div id="instance2">text</div>
...
<div id="myNicPanel" style="display:none;position:relative;"></div>
So, once the page has completed it's load cycle, i should have two editable areas and a hidden editor. I would then use the following jQuery to reposition and show the editor when an instance is selected for editing:
$('#instance1 , #instance2').click(function () {
//Reposition the editor to just above the selected instance
$('#myNicPanel').css({
top: $(this).position().top,
left: $(this).position().left,
display: 'block',
width: $(this).width() - 2 //manual adjustment,
position: 'absolute'
});
//Make the width of the editor equal to that of the instance
$('#myNicPanel').css({
top: $(this).position().top - $('#myNicPanel').height()
});
});
You would of course already have initiated your editor and instances prior to this, and if you also want to have the editor hide again on blur, you could attach your hide() function to one of the nicEditor events.
I've got my mootools FX.slide working fine but I want the content to be hidden at the beginning instead of after they click on the link. I've done this with jquery and I usually just change the class to display:none; but it doesn't work the same with mootools.
How do I go about making the content hidden at first?
Here is a fiddle of what I've made:
http://jsfiddle.net/ajrdesign/seVM7/
Here's the code:
JS
var mySlide = new Fx.Slide('slider_content');
$('toggle').addEvent('click', function(e){
mySlide.toggle();
});
HTML
<li>
<h3>What can I do with Revu iPad?</h3>
<a id="toggle" href="#">Answer</a>
<div id="slider_content">
<p>Revu iPad includes some of the most popular features of Bluebeam Revu, enabling you to redline PDFs and collaborate with others on the go. Access PDFs through Dropbox, Box, iTunes, or WebDAV and redline PDFs with markup tools* including your existing tool sets. Additionally, collaborate with project partners across the globe in real time using Bluebeam Studio. </p>
<p>Revu iPad does not include all the features of Bluebeam Revu. Our app is designed to provide users with the features they need to document issues and collaborate in the field, without compromising speed.</p>
<p>*Measurement annotations are currently not supported.</p>
</div>
</li>
CSS
#slider_content {
padding: 10px;
margin: 20px;
border: 1px solid #e8e8e8;
border-radius: 4px;
}
Found a fix for the problem!
http://jsfiddle.net/ajrdesign/seVM7/1/
Basically added a little domready event:
var mySlide = new Fx.Slide('slider_content');
document.addEvent("domready", function() {
$('slider_content').slide('hide');
$('toggle').addEvent('click', function(e) {
e.stop();
mySlide.toggle();
});
});
I was looking for the same (i.e. setting the default state to 'hidden') and actually the solution is pretty simple and has been described here:
Just add .hide() to your line like so:
var mySlide = new Fx.Slide('slider_content').hide();
Add style="display:none" in HTML code to the element you're going to toggle();
Create Fx.Slide with onComplete callback:
var myFx = new Fx.Slide('slider_content', {
onComplete: function() {
if (this.wrapper.offsetHeight != 0)
this.wrapper.setStyle('height', 'auto');
}
});
Run some code before expanding div for the first time:
var e = $('slider_content');
if ( e.getStyle('display') != 'block' ) {
myFx.hide();
e.setStyle('display', 'block');
}
myFx.toggle();
Background
Modern browsers do away with the classic status bar and instead draw a small tooltip at the bottom of their windows that displays the link target on hover/focus.
An example of this (undesirable, in my case) behavior is illustrated in the following screenshot:
Questions
Is there a portable way to disable these tooltips?
Am I missing any obvious drawbacks to doing this in my particular situation?
Is my attempt (see below) a reasonable way of accomplishing this?
Reasoning
I am working on an intranet web application and would like to disable this behavior for some application-specific actions because quite frankly, https://server/# everywhere looks like an eye-sore and is obtrusive since in some instances my application draws its own status bar in that location.
My Attempt
I'm not a web-developer by trade, so my knowledge is still rather limited in this domain.
Anyway, here's my attempt with jQuery:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="utf-8">
<title>Target Tooltip Test</title>
<style>
a, span.a {
color: #F00;
cursor: pointer;
text-decoration: none;
}
a:hover, span.a:hover {
color: #00F;
}
a:focus, span.a:focus {
color: #00F;
outline: 1px dotted;
}
</style>
<script src="http://code.jquery.com/jquery-1.7.2.min.js"></script>
<script>
$(document).ready(function() {
patch();
});
function patch() {
$('a').each(function() {
var $this = $(this).prop('tabindex', 0);
if($this.prop('href').indexOf('#') == -1 || $this.prop('rel').toLowerCase() == 'external') {
return;
}
var $span = $('<span class="a" tabindex="0"></span>');
$span.prop('data-href', $this.prop('href'));
$span.text($this.text());
$this.replaceWith($span);
});
$('a[rel="external"]').click(function() {
window.open($(this).prop('data-href'));
return false;
});
$('span.a').click(function() {
location.href = $(this).prop('data-href');
}).keypress(function(event) {
if(event.keyCode == 13) {
location.href = $(event.target).prop('data-href');
}
}).focus(function() {
window.status = ''; // IE9 fix.
});
}
</script>
</head>
<body>
<ol>
<li>External Link</li>
<li>Action Foo</li>
<li>Action Bar</li>
<li>Action Baz</li>
<li>Email Support</li>
</ol>
</body>
</html>
patch() replaces all links containing # (i.e., application-specific actions in my case) with a span element, makes all "external" links open in a new tab/window and doesn't seem to break custom protocol handling.
Is there a portable way to disable these tooltips?
Nope, other than workarounds like your example above.
Am I missing any obvious drawbacks to doing this in my particular situation?
You seem to be missing the fact that the whole situation is awkward. Why have links at all if you're going to make them look like buttons? Just use buttons. For that matter, why bother with links if you end up switching them out with spans anyway? Just use spans.
Is my attempt (see below) a reasonable way of accomplishing this?
It's not really reasonable as a general approach, because you're removing those anchor elements from the document, so any attached event listeners, expandos, etc. will be lost. It may work for your specific situation, but a more sane approach would be to not use links in the first place (see above).
If you're still determined to do something like this, at least don't replace the a element. Just get rid of its href attribute and set up an event listener as you did in your example. Now it's no longer a link, so it won't show up in the status bar (but it's still the same element, at least).
<button onclick="window.open('yoururlhere.html','_self')">your link text here</button>
Note that this treats ctrl-clicks as ordinary clicks and disables right-clicking. I don't know about middle clicks.
You could also use "a" and merely replace the href with the onclick as in the code above, but when I tried that my "a:hover" styling stopped working. Apparently an "a" without an href is considered unhoverable, at least in Firefox. So I switched to "button" and "button:hover" styling and all was well.
I understand this solution will be considered bad practice, but in some situations, eg the site I'm making made up mainly of full screen photos, aesthetics trumps principles.
The tooltip provides an indication to the user where a link will take them if clicked. It's part of the standard browser user experience and will be expected by users of your site. Changing this expectation because you don't think it looks nice will probably lead to a poor user experience. Any content shown in that area will be visible as soon as the user stops hovering over a link tag.
I know that any link that doesn't tell me where it is going looks pretty suspicious to me.
try this
$(this).removeAttr("href");
$(this).click(function(){}).mouseover(function(){.........}).etc
This is what I do with jQuery:
//remove status bar notification...
$('a[href]').each(function(){
u = $(this).attr('href');
$(this).removeAttr('href').data('href',u).click(function(){
self.location.href=$(this).data('href');
});
});
After clicking a link with a common href (local page or web-site)
and the href is successfully loaded, both FF2 and IE7 will display
the link with a:visited styling.
For links with href="javascript:anyfunc()", IE7 works as above
while FF2 does not display a:visited styling. No change with any
DOCTYPE.
Q: Is either behaviour with JS links and :visited considered correct?
Q: Does FF2 leave anchor state unchanged after clicking a JS link?
Q: Without having to attach an onClick handler or modify classes/style
with JS, is there a concise way to tell FF2 to use :visted
styling independent of whether href is another page or a JS link?
Example follows:
<html>
<head>
<style>
div.links { font-size: 18px; }
div.links a { color: black; text-decoration: none; }
div.links a:visited { background-color: purple; color: yellow; }
div.links a:hover { background-color: yellow; color: black; }
</style>
<script>
function tfunc(info) { alert("tfunc: info = " + info) }
</script>
</head>
<body>
<div class="links">
JS Link 1<br>
JS Link 2<br>
Common href, google
</div>
</body>
</html>
It would be difficult to style these sorts of links... whilst they may have the same href, they could potentially do anything through JS (which may make it seem that visiting it would not).
Is there a way to link to something such as a HTML page and attach event handlers to the link (and return false to stop the link clicking through)? And if the links are in fact JS hooks, I would use an element such as a <button> and style it accordingly... remember to add cursor: pointer so the end user knows it is clickable.
Using inline javascript:function(something) in a href is bad practice. Try unobtrusive event handlers.
a:hover MUST come after a:link and a:visited in the CSS definition in order to be effective!
Here's my take:
Q: Is either behaviour with JS links and :visited considered correct?
The purpose of a link is to retrieve a resource. If your link doesn't go anywhere, what are you "visiting"? The behavior is correct from this perspective in my opinion.
Q: Does FF2 leave anchor state unchanged after clicking a JS link?
It seems as though it doesn't change the state of the link to :visited unless it points to an element in the page (which means the link points to the current page which is implicitly visited) or to another resource which as already been accessed.
Q: Without having to attach an onClick handler or modify classes/style with JS, is there a concise way to tell FF2 to use :visted styling independent of whether href is another page or a JS link?
I don't think so. You can probably get the visited effect if you point the href of the link to "#" and use the onclick handler for your JavaScript needs.
I have encountered the issue I believe this question is asking. Consider this simple example:
style sheet:
#homebox { display: none;}
#contactbox { display: none; }
html:
<a id="#home"></a>
Show Home
<div id="homebox">Your home</div>
<a id="#contact onclick="return showHideDiv(this);"></a>
<div id="contactbox">Contact Info</div>
script:
function showHideDiv(elem) {
if( elem.style.display && elem.style.display == "none"; ) elem.style.display = "block";
else if( elem.style.display && elem.style.display == "block"; ) elem.style.display = "none";
return true;
}
Although not the most beautiful code, it points out some issues which can develop when using javascript onlick within a href. The reason you might want to do something like this, is to create dynamic content changes without reload which show a visited style. The a links would be handier than buttons, so the visited status of the links is maintained, even though internal. However, I have noticed some issues with browsers triggering visited status on internal links, let alone internal links with javascript onclick event handlers. A button would require coding a function to control visited styles.
I agree with Alex, a link should be a link to something, not a JS trigger - a button would much more effective here.
If you do want to attach some JS function to a link, you should definitely use some unobtrusive JS to attach that function to the click event.
EG using jQuery:
$("#myLinkID").click(function () {
//function stuff
});