Monday, October 29, 2012

SOIS Advisor Chat Code

Why Zoho?

We chose Zoho because it allows for multiple IM services to be integrated into a single web-based application where anyone can messange the account, and it wasn't bought by Google (like meebo.com). There is another alternative, Yahoo Ping Box, but it doesn't allow for other IM networks to be integrated in.

What other IM Networks? 

SOIS has advisor accounts setup on MSN, Yahoo, AIM, and Google Talk; allowing students to connect to SOIS from any device or service of choice. 

How do I setup an account with Zoho?

Simple, go to chat.zoho.com and register for a free account. For the basic chat code, you are going to want to setup a "Live Support" Box. Because the Zoho code uses an iframe it will not just work within the CommonSpot, but instead will have to be put into an HTML or CFM file and linked to the CMS via the Static HTML Element or the Custom Script element.

The Code: 

The School of Information Studies has implemented an advisor chat feature for many years now. Below is the code that we use for the popup window within the CommonSpot CMS, comments/notes are preceded by a #:

#formatted to be human readable, should all be on one line
<a
     href="
          javascript:HandleLink(
               # Auto generated ID by the CMS
               'cpe_3906026_0',
               'CPNEWWIN:SOIS_Advisor_Chat^
                    # position the window in the upper left corner of the window
                    top=10,
                    left=10,
                    # set the dimensions of the window
                    width=275,
                    height=450,
                    # disable the toolbar, location bar, status, URL, and scroll areas
                    toolbar=0,
                    location=0,
                   directories=0,
                   status=0,
                   menubar=0,
                   scrollbars=0,
                   # allow the window to be re-sizable
                   resizable=1
                   # set the URL for the script to call
                  @http://www4.uwm.edu/sois/assets/scripts/advischat_head.cfm
          ');"
      # set the window statuses to be equal to the location of the script
     onmouseout="return window.status=''; "
     onmouseover="return  window.status=
         'http://www4.uwm.edu/sois/assets/scripts/advischat_head.cfm';"
      #make it look nice
     class="newbutton button-smaller"
     # set the title (hover text) and regular text of the link
     title="Chat/IM a SOIS Advisor"> Advisor Chat
</a>

The styling of the Advisor chat button


a.button-smaller {
  1. border-radius4px 4px 4px 4px;
  2. font-size.917em;
  3. padding1px 7px;
  4. margin5px 0 0;
}



a.newbutton {
  1. colorblack;
  2. background-imageurl("/sois/assets/images/buttons/white-background.png");
  3. background-positionleft center;
  4. background-repeatrepeat-x;
  5. border2px solid #DAD8D8;
  6. border-radius7px 7px 7px 7px;
  7. cursorpointer;
  8. displayinline-block;
  9. font-size1.083em;
  10. font-weightbold;
  11. line-height18px;
  12. margin0;
  13. outlinemedium none;
  14. padding5px 10px;
  15. text-decorationnone;
  16. word-wrapnormal;
}

The Code for the advischat_head.cfm file

<html>
<head>
<title>IM @uwmsois</title>
</head>
<body>
<br>
<div style="height:275px;width:260px">
<iframe style="overflow:hidden;width:100%;height:100%;" frameborder="0" border="0" src="http://chat.zoho.com/mychat.sas?u=fdbbc009b4689cb7a1cb3fda6bea6b6c&amp;chaturl=SOIS%20Advisor&amp;V=000000-70a9e1-eff4f9-70a9e1-SOIS%20Advisor%20Chat">
</iframe>
</div>
<p>
Hours of Opperation<br>
Monday to Friday: 8AM to 4PM CST
</p>
<p>
Look for us on these other networks:<br>
<a href="aim:goaim?screenname=soisadvise"><img src="/sois/assets/images/im/aim.png" alt="AIM Icon"></a>
<a href="gtalk:chat?jid=soisadvisor@gmail.com"><img src="/sois/assets/images/im/google.png" alt="Google Talk Icon"></a>
<a href="msnim:chat?contact=soisadvisor"><img src="/sois/assets/images/im/msn.png" alt="MSN Messanger Icon"></a>
<a href="ymsgr:sendim?soisadvisor"><img src="/sois/assets/images/im/yahoo.png" alt="Yahoo Messanger Icon"></a>
</p>
</body>
</html>

Friday, October 7, 2011

Rotating Selectable Slideshow

This is the third post in the rotating content and tabs series that explores CSS, JavaScript, HTML and JQuery. This time we create a news rotator with slide index, next and previous buttons, auto forward, and a play/pause button. Moreover, it degrafes fairly nicely without JavaScript turned on, which should lend itself to decent accessibility by screen readers and other assistive technologies. It can currently be seen on this test page: https://cms.uwm.edu/letsci/chemistry/testslider.cfm.

The CSS:
#slideshow #slidesContainer 
{
  margin:0 auto;
  width:560px;
  height:263px;
  overflow:auto; /* allow scrollbar when no JS. you may want to add instead overflow-x:hidden; overflow-y: scroll;*/
  position:relative;
}

#slideshow #slidesContainer .slide 
{
  margin:0 auto;
  width:580px; /* reduce by 20 pixels to avoid horizontal scroll */
  height:150px;
}

.control 
{
  display:block;
  width:39px;
  height:263px;
  text-indent:-10000px;
  position:absolute;
  cursor: pointer;
}

#leftControl 
{
  top:0;
  left:0;
  background:transparent url(/letsci/assets/images/testprev.png) no-repeat 0 0;
}

#rightControl
{
  top:0;
  right:0;
  background:transparent url(/letsci/assets/images/testnext.png) no-repeat 0 0;
}

a.slidelinks, 
a.playpause
{
  color: #ff0505;
}

.slideDesc 
{
  position:relative;
  top:-20px;
  height:20px;
  background:black;
  opacity:0.7;
  filter:alpha(opactiy=70);
  color:white;
}

.slideindex 
{
  display: block;
  float: right;
  margin-right: 130px;
}
The HTML:
<div id="slideshow">
  <div id="slidesContainer">

    <div class="slide">
      <a href="http://jastreich.com/"><img src="images/1.png" alt="Image alt" /></a>
      <div class="slideDesc">Slide 1.
      <span class="slideindex">
        <b>1</b>
        <a class="slidelinks" href="javascript:" onclick="pause();gotoslide(1);">2</a>
        <a class="playpause" href="javascript:" onclick="toggle_pause();">Pause</a></span>
    </div>

    <div class="slide">
      <a href="http://slashdot.org/"><img src="images/2.png" alt="Image alt" /></a>
      <div class="slideDesc">Slide 2.
      <span class="slideindex">
        <a class="slidelinks" href="javascript:" onclick="pause();gotoslide(0);">1</a>
        <b>2</b>
        <a class="playpause" href="javascript:" onclick="toggle_pause();">Pause</a></span>
    </div>

  </div>
</div>
The JavaScript:

  var currentPosition = 0;
  var slideWidth = 600;
  var slides = $('.slide');
  var numberOfSlides = slides.length;
  var paused = false;

  // Remove scrollbar in JS
  $('#slidesContainer').css('overflow', 'hidden');

  // Wrap all .slides with #slideInner div
  slides
  .wrapAll('<div id="slideInner"></div>')

  // Float left to display horizontally, readjust .slides width
  .css({
    'float' : 'left',
    'width' : slideWidth
  });

  // Set #slideInner width equal to total width of all slides
  $('#slideInner').css('width', slideWidth * numberOfSlides);

  // Insert left and right arrow controls in the DOM
  $('#slideshow')
    .prepend('<span class="control" id="leftControl">Move left</span>')
    .append('<span class="control" id="rightControl">Move right</span>');

  // Hide left arrow control on first load
  manageControls(currentPosition);

  // Create event listeners for .controls clicks
  $('.control')
    .bind('click', function(){
    // Determine new position
      currentPosition = ($(this).attr('id')=='rightControl')
    ? currentPosition+1 : currentPosition-1;

      // Hide / show controls
      manageControls(currentPosition);
      // Move slideInner using margin-left
      $('#slideInner').animate({
        'marginLeft' : slideWidth*(-currentPosition)
      });
    });

  // Advance on time -- autoforward
  function timeForward()
  {
    if(!paused)
    {
      if(currentPosition + 1 < numberOfSlides)
      {
        gotoslide(currentPosition + 1);
      }
      else
      {
        gotoslide(0);
      }
      setTimeout("timeForward()",3000);
    }
  }

  // Swtich from play to pause
  function toggle_pause()
  {
    if(paused)
    {
      play();
    }
    else
    {
      pause();
    }
  }

  function pause()
  {
      //stop advance, switch button text.
      paused = true;
      $('.playpause').html('play');
  }

  function play()
  {
      //start advance, switch button text.
      paused = false;
      $('.playpause').html('Pause');
      timeForward();
  }

  // manageControls: Hides and shows controls depending on currentPosition
  function manageControls(position)
  {
    // Hide left arrow if position is first slide
    if(position==0){ $('#leftControl').hide() }
    else{ $('#leftControl').show() }
    // Hide right arrow if position is last slide
    if(position==numberOfSlides-1){ $('#rightControl').hide() }
    else{ $('#rightControl').show() }
  }

  // Go to a given slide.
  function gotoslide(i)
  {
    currentPosition = i;
    manageControls(currentPosition);
      $('##slideInner').animate({
        'marginLeft' : slideWidth*(-currentPosition)
      });
  }

  // Start auto advance.
  setTimeout("timeForward()",3000);

Monday, July 18, 2011

Rotating Content

Sorry for the delay in posting the second part of this series. I've been busy with meetings and coding and forgot to post the second and third parts. Here is the second, Rotating content. Again, minimal use of JQuery could be replaced with straight JavavScript to lighten the load times. Simple and clean.

The HTML:
<!--- The Container to rotate through --->
<div id="banner"><a href="#" class="bannerpane">
  <!--- Anything with the class bannerpane inside the banner will be looped through.  It doesn't have to be a link, it could a div containing just about anything. Order of children elements will be order they rotate. --->
  <img src="/letsci/images/pollen_1.png" alt="pollen" title="pollen" class="bannerpane"/>
  </a> <a class="bannerpane" href="/letsci/3"><img src="/letsci/images/starts.png" alt="stars" title="stars" />
</a></div>


The CSS:
/* Use a fixed hight and overflow hidden or at the point it rotates you'll see both stories for a short time.  The other solution is to position the .banner absolutely (which would yield a better transition. */
/* Black background was the best thing to fade to for the images I'm using, if you want to fade to white or another color, set the background here to your color of choice. */
#banner {height:156px;overflow:hidden;background:black;}


The JavaScript:
// To start hide them all except the first,
// you may want to do this with inline style instead of JS,
// in case the user doesn't have JavaScript enabled...  I didn't do that to this, yet.
$('.bannerpane').hide();
$('.bannerpane').first().show();

//function that does the swap.
function rotate() {
  //Basically fade out the current, move it to the bottom, fade in the the new top element.
  // The two 5000's control the length of the fade.  These can be adjusted to taste. 
    $("#banner .bannerpane").first().fadeIn(5000).appendTo('#banner').fadeOut(5000);

    // Recursively call this function again in 7000 microseconds
    // The 7000 can be adjusted to taste.
    setTimeout(rotate, 7000);
}

//Call it the first time.
rotate();

Monday, June 6, 2011

Tabs

This is a part one in a three part series. This post will cover simple tabs made with HTML, CSS and JavaScript. I don't use the JQuery UI library, but do use the core here. That said, everything I do here can easily be replaced with simple plain JavaScript. The JQuery just removes (or rather hides) a few simple loops. This will create the tabs that can be seen at the bottom of: http://cms.uwm.edu/letsci/index_860-a.cfm


You can place multiple sets of tabs on single page, reusing the JavaScript and the CSS without modification. Just make sure the containing div on each has a unique ID (Which it should anyway). The spans can be changed to anchor links with link to the individual blocks, which would make this work better when JavaScript is disabled with just minor changes.


The two follow up posts that are coming will be a rotating news banner that doesn't require Flash, and finally rotating tabs using the material from the two other posts.


The HTML:

  <!--- Change id of this outter div for each instance you place on a single page --->
  <div class="slider" id="slider1">
  <!--- The Tabs Note the rel attribute on each of the tabs.Used in the JavaScript --->
  <span class="slidebutton" rel="1">Student News</span>
  <span class="slidebutton" rel="2">Faculty News</span>
  <span class="slidebutton" rel="3">Research News</span> 
  <!--- A handle for a bit of javascript styling. --->
  <div class="posttabs">&nbsp;</div>
  <!--- 
    First news story, note the rel attribute matches the rel of the tab.
    Technically they don’t have to be numbers, they could be meaningful or descriptive.
  --->
  <div class="sliderpane" rel="1">
    <p class="storytext"><strong>Dilano Saldin, Physics</strong><br />
    Physics Professor Dilano Saldin is the lead author of "New light on disordered ensembles: Ab   
    initio structure determination of one particle from scattering fluctuations of many copies," an 
    article that was featured in the Viewpoint section of the journal, Physics.</p>
    <img src="http://cms.uwm.edu/letsci/images/dilano1.png" alt="professor Dilano Saldin" 
      height="140" width="130" /> 
    <div class="clear">&nbsp;</div>
  </div>
  <div class="sliderpane" rel="2">This is two. 
    <div class="clear">&nbsp;</div>
  </div>
  <div class="sliderpane" rel="3">This is three. 
    <div class="clear">&nbsp;</div>
  </div>
  <div class="sliderpane" rel="4">This is four. 
    <div class="clear">&nbsp;</div>
  </div>
</div>

The CSS:

.slidebutton 
{
  display: block;
  text-align:center;
  border:1px solid white;
  border-bottom:none;
  float:left;
  /* 
    One third is 33%, because we have three tabs.  removed the 3% for room on the right.
    If you had 4 tabs, you’d start with 25% and then remove some for breathing room.
  */
  width:30%;
  background: none repeat scroll 0% 0% #fcd204;
  /* CSS 3 rounded corners */
  border-radius:3px;
  -moz-border-radius:3px;
  -webkit-border-radius:3px;
  /* Line the first tab up with the news box bellow */
  position:relative;
  right:2px;
}
.active
{
  background: rgba(204,204,204,.7);
}
.sliderpane 
{
  font-size:12px;
  background: rgba(204, 204, 204,.7);
  height:140px;
/*
     Move the news box up to cover the tab bottoms, so it looks like 
    one piece and hides the lower rounded corners on 
  position:  relative;
  top:  -2px;
  /* CSS 3 rounded corners */
  border-radius: 5px;
  -moz-border-radius:5px;
  -webkit-border-radius:5px;
}
.clear {height:1px; width:100%;} 
/* 
  For CMS or other floats, so we don’t clear left nav or right hand column.  
  If that isn’t a consideration: 
  .clear {clear: both;} 
*/
.buttons {margin:3px;}
.storytext1 {float: right; width:428px;}
.storytext  {float: right; width:298px;}

Finally the JavaScript
<script type="text/javascript" src="http://ajax.aspnetcdn.com/ajax/jQuery/jquery-1.6.min.js"></script>
<script type="text/javascript">  
        //When the page loads, show only the first panel’s content.
        $(".sliderpane").css("display","none");
        $('.sliderpane[rel="1"]').css("display","block");

        //Change the tab of the first story to show that it is active.
        $('.slidebutton[rel="1"]').attr('class','slidebutton active');

        // Quick javascript formatting, not the right place to do it, but it works for I wanted.
        $('.posttabs').height($('.slidebutton').height()+2);

        // When a tab is clicked
        $(".slidebutton").click( function()
        {
          // Get ID of the parent div of the tab that was clicked
          // This allows the script to run multiple tab instances on a single page.
          // This does means the tabs and the panels (tab content) have to share the same parent. 
          id = $(this).parent().attr('id');
          // Get the rel, so we can show the proper panel. 
          num = $(this).attr('rel');
          // Change all tabs styled to look like they don’t have focus 
          // -- i.e. un-highlight the previous item
          $(".slidebutton").attr('class','slidebutton');
          // Highlight the new active tab
          $(this).attr('class','slidebutton active');
          // Hide all the panels -- i.e. hide the previous active item
          $('#' + id + ' .sliderpane').css("display","none");
          // Show the new active panel (tab content)
          $('#' + id + ' .sliderpane[rel="' + num + '"]').css("display","block");
        });
</script>

Friday, July 2, 2010

Simulate Slow Internet Connection

I came across this article today that describers how you can use Firefox Throttle to reduce your internet connection speed. Here is a quote for why you should test under these conditions.
Well the truth is that real world internet connections are much slower than you think. Your application end users may not always be broadband users but also people accessing your app through a dial-up connection, mobile sets, 3G or USB dongles. Most designers and developers forget to test their application on slower internet connections, resulting in a poor performing application.
Another good addon that can help you find the bottlenecks in your code and help optimize it is Google Page Speed.This addon allows you to see how your code could be optimized and will generate the suggested changes.

Friday, March 19, 2010

Create AJAX queue with jquery

1. Create a global variable for your ajax request
var ajax_request = null;
2. Disable client side caching 
 $.ajaxSetup ({ 
         cache: false 
    }); 
3. Before you start the ajax call, create an if statement that will abort any existing requests
   if (ajax_request) { // checks for an existing ajax request
        ajax_request.abort(); // aborts request
    }
 4. Finally set global variable to ajax request
    ajax_request = $.ajax({
     url: "some/service.cfm",
     type: "POST",
     data: { var1: someval1,
                var2: someval2},
     success: function(data) {
            alert("success");
        },
        error: function (XMLHttpRequest, textStatus, errorThrown) { // execute this if it all goes boom
            alert(textStatus + errorThrown);
            return false;
            }
    });