Showing posts with label jquery. Show all posts
Showing posts with label jquery. Show all posts

06 August 2015

Nice jQuery plugin for "Read more" text truncating

Spent some time researching options to do "Read more" functionality for text on a web page. Many were based on a preset height in pixel, which cut the text in mid-sentence, without adding any ellipsis. In addition, those which did truncate with ellipsis lacked a flexible animation. Then I found jTruncate from jMar's blog. It does the trick on any number of elements on the page via jQuery; it also includes options for animation and more/less link text.

19 October 2011

IE7 and "Error: Expected identifier, string or number"

IE7 (and earlier versions) have trouble with errant commas in array declarations. Take this code, provided by James Messinger on Stack Overflow:
<script type="text/javascript">
// Replace the normal jQuery getScript function with one that supports
// debugging and which references the script files as external resources
// rather than inline.
jQuery.extend({
   getScript: function(url, callback) {
      var head = document.getElementsByTagName("head")[0];
      var script = document.createElement("script");
      script.src = url;

      // Handle Script loading
      {
         var done = false;

         // Attach handlers for all browsers
         script.onload = script.onreadystatechange = function(){
            if ( !done && (!this.readyState ||
                  this.readyState == "loaded" || this.readyState == "complete") ) {
               done = true;
               if (callback)
                  callback();

               // Handle memory leak in IE
               script.onload = script.onreadystatechange = null;
            }
         };
      }

      head.appendChild(script);

      // We handle everything using the script element injection
      return undefined;
   }, // <-- Unneeded comma which blows up IE7.
});
</script>
IE7 blows up with this error:
Error: Expected identifier, string or number
It took quite a bit of debugging and Google searches to finally understand where the problem was. Note the last comma, after the next-to-last closing curly brace "}," -- this is unnecessary. Modern browsers can handle this, but IE7 chokes. Simply remove the comma and you're good to go. More on this problem on Stack Exchange.

How to hide/show table rows in IE7

If you need to hide a table row (TR), you'd usually use the following:
.hide-tr { display:none; }
The problem develops when you later wish to show the row; simply setting the display to block is insufficient, as the individual cells in the row lose their positions and often get bunched next to each other. Using display:table-row works on most modern browsers, but IE7 ignores that and prefers display:inline-block. So the solution? There are a few ways to fix the problem, as indicated on Stack Exchange. The problem with using visibility:hidden is that the row still takes up space on the page and shrinking its height is a non-trivial task. Another solution involves a method less recommended, using browser and version detection via jQuery. However, it does fix the issue:
if ($.browser.msie && jQuery.browser.version == '7.0'){
  $('.hide-tr').css('display','inline-block');
}
else {
  $('.hide-tr').css('display','table-row');
}
Not a clean solution but it gets the job done :)

Update: An even easier solution: Simply call the jQuery show() method on the object and it's smart enough to apply the appropriate CSS to the object.

02 October 2011

SharePoint: Create an easy "Share page with friend" button

In SharePoint, it's useful to have an email icon that allows users to email the page to friends. Though we could build a popup box, we can also go with a simpler solution that uses the person's email client to do the heavy lifting. In another post, I covered how to fetch some of the server-side variables into a JavaScript array needed for generating this email. Now, let's use the variables and see how we send the email. One key to this feature is to keep it simple; this means, we'll leave the To field of the email blank and use the commonplace "mailto:" HREF attribute. So, let's get to the code:
function generateEmailTo(){
  var body = currentElements.currentUserName + ' has shared a page with you on the intranet.%0A%0APage Title: %22' +
    currentElements.currentTitle  + '%22%0A' + $(location).attr('href').replace('#',''); 
  var subject = currentElements.currentUserName + ' has shared an intranet page with you';
  var mailto = 'mailto: ?body=' + body + '&subject=' + subject;
  var anchor = '<a href="' + mailto + '"></a>';

  $("#send-email").wrap(anchor);
}
We can pass the body, subject, and mailto for the mail message. The ?body= and the &subject= allow the main message and the subject to be passed in the querystring. To provide line breaks, we use %0A hex values; so for two line breaks, we use %0A%0A in the querystring value. To pass quotes, we use %22. To pass a blank mailto:, we leave a space in front of it, before the ?body=. More notes on mailto, setting its cc, bcc, and special characters can be found here.

Once we've concatenated the various elements, we pass the anchor variable to the jQuery wrap() function, called on the email icon img tag (with ID of send-email). We call the above generateEmailTo() in the document.ready function. When you click the link, it produces something like this in the generated email (Outlook, Thunderbird, etc.):
Alex C has shared a page with you on the intranet. 

Page Title: "My Page Title" 
http://mysite.org/Pages/mypage.aspx
The subject, not shown, will be "Alex C has shared an intranet page with you". Note that the URL will appear as a clickable link in most email clients. Also note that we can't pass HTML to the body of the message, only plain text.

Hope you find this useful.

Update: Here's the IMG tag that is being referenced in the code above:
<img id="infoweb-email" title="Send this page to a friend." 
  src="<%= baseUrl %>/SiteAssets/media/icons/email-icon.gif"/>
The baseUrl server-side variable is set in the page layout's OnLoad event handler:
<script type="text/c#" runat="server">
protected override void OnLoad(EventArgs e)
{
  base.OnLoad(e); // Required for the SharePoint ribbon bar, etc., to work correctly.
  Microsoft.SharePoint.SPContext context = Microsoft.SharePoint.SPContext.GetContext(HttpContext.Current);
  baseUrl = context.Site.Url;
  // Other code...
}
</script>
For the page layout to allow code blocks, we must make the following change to the Web.config file:
<PageParserPaths>
   <PageParserPath VirtualPath="/_catalogs/masterpage/*" 
       CompilationMode="Always" 
       AllowServerSideScript="true" IncludeSubFolders="true"/>
</PageParserPaths>
Note that this allows all files in the masterpage folder to contain code blocks. If we use Firebug to examine the element in Firefox, we'll see this is the HTML generated by our server- and client-side code:
<a href="mailto: ?body=Alex%20C has shared a page with you on the intranet.%0A%0APage Title: %22My%20Page%20Title%22%http://mysite.org/Pages/mypage.aspx&subject=Alex%20C has shared a page with you on the intranet.">
<img id="send-email" src="http://mysite.org/SiteAssets/media/icons/email-icon.gif" title="Send this page to a friend.">
</a>
So the IMG element has been wrapped by an anchor tag which has the properties we set in JavaScript.

28 August 2011

SharePoint: Remove link from list view title

Links can't be easily removed from list view titles (or web part titles, for that matter). That's where jQuery comes in handy:
$(document).ready(function () {

// Remove the link from the web part title and set its cursor to normal.
$('.ms-WPTitle > a').contents().unwrap().css('cursor','default');
$('.ms-WPTitle').css('cursor','default');
});
This is thanks to a tip from this post on StackOverflow.com. Note also that the code sets the cursor to default (instead of "hand").

01 April 2011

Create a new window using custom jQuery function

For my current project, I needed to pop up a new window from specific anchor tags on the page. This provided the perfect opportunity to write some custom jQuery to handle this. I started with some research into creating jQuery function; Jeremy Martin's blog post got me started. Next, I got some inspiration from this popup window generator, though I could never get it working for my site.

So the jQuery function looks like this:
/*
* Add a function to jQuery to automate popup windows.
*/
(function($){
$.fn.popWindow = function(options) {

// Declare some default values.
var defaults = {
width: 729,
height: 529,
left: 19,
top: 19,
location: 0,
directories: 0,
status: 0,
toolbar: 0,
menubar: 0,
resizable: 1,
scrollbars: 1,
url: '',
name: 'cms_win',
center: 0
};

// Merge the defaults with the options parameter.
var options = $.extend(defaults, options);

// For each of these objects...
return this.each(function(){
// Get a handle to this HTML object.
obj = $(this);

// Set the left and top if we're centering.
if (options.center){
options.left = (screen.width - options.width)/2;
options.top = (screen.height - options.height)/2;
}

// If user provided a URL, use that; otherwise use the HREF.
var url = (!jQuery(options.url).isEmpty()) ?
options.url : obj.attr("href");

// Concatenate the window.open() function's options.
var features = "width="+options.width+",height="+
options.height+",left="+options.left+",top="+
options.top+",location="+options.location+
",directories="+options.directories+",status="+
options.status+",toolbar="+options.toolbar+
",menubar="+options.menubar+",scrollbars="+
options.scrollbars+",resizable="+
options.resizable;

// Add an onClick() handler to this object.
obj.click(function(){
// On click, open a new window with these arguments.
window.open(url,options.name,features);
return false;
});
});
}
})(jQuery);

/*
* Add a function to jQuery to check null/undefined/blank
* status of object.
*/
(function($){
$.fn.isEmpty = function(){
return (typeof $(this) === "undefined" ||
$(this) === null ||
$(this) === "") ? true : false;
}
})(jQuery);
Note the helper function isEmpty() which serves to check for null, undefined, or blank variables. The folks on StackOverflow.com helped with that function. To use the popWindow() function, ensure you've included the latest jQuery library on your page; add the above code in a script tag; then set the style class on your anchor tag or add an ID so you can reference the object; finally, call it on your page like this:
jQuery(document).ready(function(){
// Set all the objects with pop class to open in new window.
jQuery(".pop").popWindow({
center: 1
});
});
In this case, I'm also taking advantage of the built-in center functionality to center the new window.

02 February 2011

Dynamically replace HTML5 video with Flash in Fancybox

For my current project, I needed to dynamically (based on whether the device supported HTML5 or not) replace HTML5 video tags with a Flash player. What made this more challenging was that the video player needed to be in a Fancybox.

A day's worth of coding resulted in the following JavaScript function. It's heavily commented so it should be self-explanatory. Drop me a comment if something doesn't make sense. You need to include the latest jQuery library for this to work.

function flashPopup(){
// Declare some variables.
var el = "";
var vidFileName = "";
var posterPath = "";
var placeHolderPosterPath = "";
var replacement = "";
var imgTitle = "";
var videoTag = "";
var boxId = "";
var flashId = "";
var dotPosition = "";
var swf = ""

// Loop over each video tag.
$("video").each(function(){
// Reset the variables to empty.
el = "";
vidFileName = "";
posterPath = "";
imgTitle = "";
placeHolderPosterPath = "";
replacement = "";
videoTag = "";
flashId = "";
swf = "";

// Get a reference to the current object.
el = $(this);

// Set some values we'll use shortly.
boxId = this.id + "_flashBox";
flashId = this.id + "_flashPlayer";

/*
Set the ID attribute of the first DIV in this element's parent's
parent. This "box" will have the Fancybox attached to it.
*/
el.parent().parent().find("div:first").attr("id",boxId);


/*
Fetch the MP4/M4V video from the <source> tags. Need to go to the
parent of the current tag to find them.
*/
el.parent().find("source").each(function(){
if ($(this).attr("src").indexOf("m4v") != -1 ||
$(this).attr("src").indexOf("mp4") != -1){
vidFileName = $(this).attr("src").substring($(this).attr("src").lastIndexOf("/")+1);
}
});

/*
IE (< 9) and older browsers use the Flash player, which overlays a 'Play' button
on the poster image by default; so we use a poster image that doesn't have
a play button. Otherwise we'd end up with a play button on top of a play
button.

We have an img tag inside the <video> tag which we'll use (by adding "-ie" to the
filename) for the Flash player's image attribute. The next two lines find the file
and its path.
*/
dotPosition = el.parent().find("img").attr("src").lastIndexOf(".");
posterPath = el.parent().find("img").attr("src").substring(0,dotPosition) + "-ie" + el.parent().find("img").attr("src").substring(dotPosition);

/*
Use the same image but this time don't add "-ie" to its name. This will be for the
main placeholder linked image; when the user clicks it, the Fancybox pops up with
the Flash player.
*/
placeHolderPosterPath = el.parent().find("img").attr("src");

/*
Fetch the image's title attribute, which we'll use for the linked image's title.
This will appear as the title on the Fancybox.
*/
imgTitle = el.parent().find("img").attr("title");

/*
Concatenate the linked image that will take the place of the <video> tag.
*/
replacement = "<a title='" + imgTitle + "' id='" + boxId + "' href='javascript:;'><img src='" +
placeHolderPosterPath + "' style='float:left; padding-left:5px; '/></a>"

// Replace the parent of the current element with the linked image HTML.
el.parent().replaceWith(replacement);

/*
The swfobject library can't be used with Fancybox (as far as I know). but
we can pass a Flash player of our own design into the Fancybox as its content.
Here, we concatenate the Flash player and point to the swfobject player.swf
file. We'll still use that player, but build our own OBJECT and EMBED tags.
*/
swf = "<object id='" + flashId + "' classid='clsid:D27CDB6E-AE6D-11cf-96B8-444553540000' width='372' height='209'>" +
"<param name='movie' value='global/vid/player.swf' />" +
"<param name='quality' value='high' />" +
"<param name='wmode' value='opaque' />" +
"<param name='swfversion' value='6.0.65.0' />" +
"<param name='expressinstall' value='global/vid/expressInstall.swf' />" +
"<!--[if !IE]>--> " +
"<object type='application/x-shockwave-flash' data='global/vid/player.swf' width='372' height='209'> " +
"<!--<![endif]--> " +
"<param name='quality' value='high' /> " +
"<param name='wmode' value='opaque' /> " +
"<param name='swfversion' value='6.0.65.0' /> " +
"<param name=flashvars value='file=" + vidFileName + "&autostart=false&image=" + posterPath + "'>" +
"<param name='expressinstall' value='global/vid/expressInstall.swf' />" +
"<div>" +
"<h4>Content on this page requires a newer version of Adobe Flash Player.</h4>" +
"<p><a href='http://www.adobe.com/go/getflashplayer'><img src='http://www.adobe.com/images/shared/download_buttons/get_flash_player.gif' alt='Get Adobe Flash player' width='112' height='33' /></a></p>" +
"</div>" +
" <!--[if !IE]>--> " +
" </object> " +
" <!--<![endif]--> " +
" </object> ";

/*
Now attach a Fancybox to this item and set its attributes. Note that
we need to disable the autoDimensions for SWF files or you'll get a
long, narrow box showing. We then set the width and height (which
usually requires some trial-and-error).

The two functions for onComplete and onClosed are custom code that
stop/start the AnythingSlider when the user opens the Fancybox and
closes it, respectively.

This entire function acts as an onClick handler for the object to
which it's attached (hence the "end click function" comment).
*/
$("[id="+boxId+"]").fancybox(
{
'content' : swf,
'autoDimensions' :false,
'height' :236,
'width' :375,
'padding' : 5,
'showCloseButton' : true,
'enableEscapeButton': true ,
'titlePosition' : 'outside',
'onComplete' : function() {stopSlider()},
'onClosed' : function() {startSlider()}
}
); // end click function
});
}

Update: A few requests have come in for a version of the code to allow HTML5 videos on a page to be placed into a Fancybox. Here's the demo, with a very special thanks to Pipsqueak.

Here's the HTML code, with the JavaScript followed a little further down:
<!doctype html>
<html lang="en">
<head>
<meta charset="utf-8">
<meta http-equiv="X-UA-Compatible" content="IE=edge,chrome=1">
<title>Fancybox HTML5 Video</title>
<meta name="description" content="">
<meta name="author" content="alex cougarman">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<link rel="stylesheet" href="js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.css" type="text/css" />
<!--
In addition to the stylesheet for the Fancybox
component, the following styles control the
look of the page and the linked image.
-->
<style type="text/css">
body {
margin:50px 0px; padding:0px;
text-align:center;
font:11px verdana, arial, helvetica, sans-serif;
}

#main {
width:500px;
margin:0px auto;
text-align:left;
padding:15px;
border:1px dashed #333;
background-color:#eee;
}
.img-link
{
border:1px solid #999;
padding:5px
}
</style>
<!--
Include the jQuery library, followed by the
Fancybox and the Easing libraries.
-->
<script type="text/javascript" src="js/jquery.fancybox-1.3.4/jquery-1.4.3.min.js"></script>
<script type="text/javascript" src="js/jquery.fancybox-1.3.4/fancybox/jquery.fancybox-1.3.4.pack.js"></script>
<script type="text/javascript" src="js/jquery.fancybox-1.3.4/fancybox/jquery.easing-1.3.pack.js"></script>

<!-- Add inline script code here. -->

</head>
<body>
<div id="main">
<h3>HTML5 Video in a Fancybox</h3>
<div>
<video id="vid-1" width="480" height="360" poster="btf.jpg" controls preload>
<source src="btf.mp4" type="video/mp4">
<source src="btf.ogv" type='video/ogg; codecs="theora, vorbis"'>
</video>
</div>
</div>
</body>
</html>
Replace the line above in the HTML that says "Add inline script code here." with this JavaScript:
<script type="text/javascript">
$(document).ready(function(){
fancyPopup(); // Replace the video tags.
});

/*
Function finds the video tags on the page. For each,
it fetches the video tag's HTML and replaces it with
a linked image that, when clicked, pops up a Fancybox
containing the HTML5 video.
*/
function fancyPopup() {
// Declare some variables.
var el = "";
var posterPath = "";
var replacement = "";
var videoTag = "";
var fancyBoxId = "";
var posterPath = "";
var videoTitle = "";

// Loop over each video tag.
$("video").each(function () {
// Reset the variables to empty.
el = "";
posterPath = "";
replacement = "";
videoTag = "";
fancyBoxId = "";
posterPath = "";
videoTitle = "";

// Get a reference to the current object.
el = $(this);

// Set some values we'll use shortly.
fancyBoxId = this.id + "_fancyBox";
videoTag = el.parent().html(); // This gets the current video tag and stores it.
posterPath = el.attr("poster");
videoTitle = "Play Video " + this.id;

// Concatenate the linked image that will take the place of the <video> tag.
replacement = "<a title='" + videoTitle + "' id='" + fancyBoxId + "' href='javascript:;'><img src='" +
posterPath + "' class='img-link'/></a>"

// Replace the parent of the current element with the linked image HTML.
el.parent().replaceWith(replacement);

/*
Now attach a Fancybox to this item and set its attributes.

This entire function acts as an onClick handler for the object to
which it's attached (hence the "end click function" comment).
*/
$("[id=" + fancyBoxId + "]").fancybox(
{
'content': videoTag,
'title': videoTitle,
'autoDimensions': true,
'padding': 5,
'showCloseButton': true,
'enableEscapeButton': true,
'titlePosition': 'outside',
}); // end click function
});
}
</script>
Replace the two videos (btf.mp4 and btf.ogv) with your own HTML5-compatible videos and try it. Demo, with a very special thanks to Pipsqueak.

Update: The good folks at Long Tail Video provide a great HTML5 video tag reference.

31 January 2011

jQuery Mobile: Touch-Optimized Web Framework for Smartphones & Tablets

"A unified user interface system across all popular mobile device platforms, built on the rock-solid jQuery and jQuery UI foundation. Its lightweight code is built with progressive enhancement, and has a flexible, easily themeable design."

27 August 2010

Multiple $(document).ready()

A page can contain multiple jQuery calls to the $(document).ready() function. This comes in handy if you're generating code at run-time or mixing static JavaScript with code generated via PHP or other server-side language. In addition, you can abbreviate the call to:
$(function() {
// do something on document ready
});

How to find element based on a string

Say you're looking for a string in the HTML and wish to get the parent element(s) that contains it. This Stackoverflow.com thread covers the technique, using a wildcard ("*") for all page elements. You can narrow it down by using a specific element type ("div" for example) instead of the wildcard.

40 New JavaScript Tutorials with Helping Techniques

http://www.tutoriallounge.com/2010/08/40-new-javascript-tutorials-with-helping-techniques/

jQuery loading remote/external javascript files using getScript()

http://colourgray.wordpress.com/2008/09/22/jquery-loading-external-javascript-files-using-getscript/

Slideshowify: Ken Burns Slideshow Effect as a jQuery Plugin

http://www.subchild.com/2010/06/10/ken-burns-effect-as-a-jquery-plugin-slideshowify/

Extensible Autocomplete

http://blog.jqueryui.com/2010/08/extensible-autocomplete/

Sortable, Resizable, Editable HTML Table With TableKit

http://www.greepit.com/2010/08/sortable-resizable-editable-html-table-with-tablekit/