/*
Author: Jacob Gable, May 2011.
License: Ms-PL; No Attribution Required; Other licenses retained where applicable...
*/
// Do this first so we can minimize funky textbox display;
function updateWidths() {
// page width - 10 for left offset;
var newWidth = $('.page').width() - 10;
$('footer, header').width(newWidth);
};
updateWidths();
// hack for fixing the width when resizing the browser.
$(window).resize(function() {
updateWidths();
});
// usage: log('inside coolFunc', this, arguments);
// paulirish.com/2009/log-a-lightweight-wrapper-for-consolelog/
window.log = function() {
log.history = log.history || []; // store logs to an array for reference
log.history.push(arguments);
if (this.console) console.log(Array.prototype.slice.call(arguments));
};
// Placeholder support for IE9
if (!('placeholder' in document.createElement('input'))) {
$('[placeholder]').each(function() {
var self = $(this);
var p = 'placeholder';
self.data('empty', self.val() == '');
self.focus(function() {
if (self.data('empty') && self.val() == self.attr(p)) {
self.val('').removeClass(p);
}
}).blur(function() {
if (self.data('empty')) {
self.val(self.attr(p)).addClass(p);
}
}).change(function() {
self.data('empty', self.val() == '');
});
if (self.val() == '' || self.val() == self.attr(p)) {
self.val(self.attr(p)).addClass(p);
}
});
$('form:has([placeholder])').bind('submit', function() {
$(this).find('[placeholder]').each(function() {
if ($(this).data('empty')) {
$(this).val('');
}
});
});
}
/**
* jQuery.ScrollTo - Easy element scrolling using jQuery.
* Copyright (c) 2007-2009 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
* Dual licensed under MIT and GPL.
* Date: 3/9/2009
* @author Ariel Flesler
* @version 1.4.1
*
* http://flesler.blogspot.com/2007/10/jqueryscrollto.html
*/
;
(function($) {
var m = $.scrollTo = function(b, h, f) {
$(window).scrollTo(b, h, f)
};
m.defaults = {
axis: 'xy',
duration: parseFloat($.fn.jquery) >= 1.3 ? 0 : 1
};
m.window = function(b) {
return $(window).scrollable()
};
$.fn.scrollable = function() {
return this.map(function() {
var b = this,
h = !b.nodeName || $.inArray(b.nodeName.toLowerCase(), ['iframe', '#document', 'html', 'body']) != -1;
if (!h) return b;
var f = (b.contentWindow || b).document || b.ownerDocument || b;
return $.browser.safari || f.compatMode == 'BackCompat' ? f.body : f.documentElement
})
};
$.fn.scrollTo = function(l, j, a) {
if (typeof j == 'object') {
a = j;
j = 0
}
if (typeof a == 'function') a = {
onAfter: a
};
if (l == 'max') l = 9e9;
a = $.extend({}, m.defaults, a);
j = j || a.speed || a.duration;
a.queue = a.queue && a.axis.length > 1;
if (a.queue) j /= 2;
a.offset = n(a.offset);
a.over = n(a.over);
return this.scrollable().each(function() {
var k = this,
o = $(k),
d = l,
p, g = {},
q = o.is('html,body');
switch (typeof d) {
case 'number':
case 'string':
if (/^([+-]=)?\d+(\.\d+)?(px)?$/.test(d)) {
d = n(d);
break
}
d = $(d, this);
case 'object':
if (d.is || d.style) p = (d = $(d)).offset()
}
$.each(a.axis.split(''), function(b, h) {
var f = h == 'x' ? 'Left' : 'Top',
i = f.toLowerCase(),
c = 'scroll' + f,
r = k[c],
s = h == 'x' ? 'Width' : 'Height';
if (p) {
g[c] = p[i] + (q ? 0 : r - o.offset()[i]);
if (a.margin) {
g[c] -= parseInt(d.css('margin' + f)) || 0;
g[c] -= parseInt(d.css('border' + f + 'Width')) || 0
}
g[c] += a.offset[i] || 0;
if (a.over[i]) g[c] += d[s.toLowerCase()]() * a.over[i]
} else g[c] = d[i];
if (/^\d+$/.test(g[c])) g[c] = g[c] <= 0 ? 0 : Math.min(g[c], u(s));
if (!b && a.queue) {
if (r != g[c]) t(a.onAfterFirst);
delete g[c]
}
});
t(a.onAfter);
function t(b) {
o.animate(g, j, a.easing, b &&
function() {
b.call(this, l, a)
})
};
function u(b) {
var h = 'scroll' + b;
if (!q) return k[h];
var f = 'client' + b,
i = k.ownerDocument.documentElement,
c = k.ownerDocument.body;
return Math.max(i[h], c[h]) - Math.min(i[f], c[f])
}
}).end()
};
function n(b) {
return typeof b == 'object' ? b : {
top: b,
left: b
}
}
})(jQuery);
$.fn.setCursorPosition = function(pos) {
this.each(function(index, elem) {
if (elem.setSelectionRange) {
elem.setSelectionRange(pos, pos);
} else if (elem.createTextRange) {
var range = elem.createTextRange();
range.collapse(true);
range.moveEnd('character', pos);
range.moveStart('character', pos);
range.select();
}
});
return this;
};
function getTimeString() {
var currentTime = new Date()
var hours = currentTime.getHours()
var minutes = currentTime.getMinutes()
var suffix = "AM";
if (hours >= 12) {
suffix = "PM";
hours = hours - 12;
}
if (hours == 0) {
hours = 12;
}
if (minutes < 10) minutes = "0" + minutes
return hours + ":" + minutes + " " + suffix;
};
<!-- Our Web Chat JS, at bottom for faster loading -->
function webChat(elem, textElem, submitBtn) {
this.polling = false;
this.pollSeconds = 10;
this.chatRoot = $(elem);
this.dlg = $('<dialog></dialog>');
// Add the dialog element.
this.chatRoot.append(this.dlg);
this.chatTextBox = $(textElem);
this.submitBtn = $(submitBtn);
var self = this;
this.submitBtn.click(function() {
self.submitMessage();
});
this.chatTextBox.keypress(function(e) {
// Submit on enter;
if (e.keyCode == 13) {
self.submitMessage();
self.chatTextBox.setCursorPosition(0);
e.preventDefault();
}
});
};
webChat.prototype.submitMessage = function() {
this.sendMessage($(this.chatTextBox).val());
$(this.chatTextBox).val('');
};
webChat.prototype.addReply = function(message) {
var sender = 'Expert'; // TODO: show this at some point?
var dt = $('<dt class="chatTitle reply">' + sender + '</dt>');
var dd = $('<dd class="chatMsg reply"><p>' + message + '</p><span>' + getTimeString() + '</span><div class="arrow"></div><div class="arrow arrowOver"></div></dd>');
this.dlg.append(dt);
this.dlg.append(dd);
$(dd).fadeIn();
$.scrollTo($('.page').height(), 400);
};
webChat.prototype.sendMessage = function(message) {
// TODO: sanitize input?
var sender = 'Me';
var dt = $('<dt class="chatTitle">' + sender + '</dt>');
var dd = $('<dd class="chatMsg"><p>' + message + '</p><span>' + getTimeString() + '</span><div class="arrow"></div><div class="arrow arrowOver"></div></dd>');
this.dlg.append(dt);
this.dlg.append(dd);
$(dd).fadeIn();
$.scrollTo($('.page').height(), 400);
};
// A simple chat bot for adding replies.
function chatBot(webChatObj, messages) {
if (messages == undefined) {
messages = [
"What's up dude?",
"For realz?",
"She said what?",
"Can I get an Amen?",
"Oh no he didn't",
"u r so funny",
];
}
this.wc = webChatObj;
this.messages = messages;
};
chatBot.prototype.start = function(secs) {
if (secs == undefined) {
secs = 10;
}
this.currMsgIdx = 0;
this.started = true;
var self = this;
this.intervalId = setInterval(function() {
self.wc.addReply(self.messages[self.currMsgIdx % self.messages.length]);
self.currMsgIdx++;
}, secs * 1000);
}
chatBot.prototype.stop = function() {
if (this.intervalId != undefined) {
clearInterval(this.intervalId);
}
this.started = false;
}
// Get our web chat log inserted into the DOM.
var chat = new webChat($('#chatLog'), '.chatText', '#submitBtn');
// Start our chatty bot.
var bot = new chatBot(chat);
bot.start();
function toggleBot() {
if (bot.started) {
bot.stop();
} else {
bot.start();
}
}
<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8" />
<title>Web Chat</title>
</head>
<body>
<div class="page">
<section id="main">
<div id="chatLog"></div>
</section>
<header style="position: fixed; left: 10px; top: 0px;">
<hgroup>
<h1>Chattin' it up</h1>
</hgroup>
</header>
<footer style="position: fixed; left: 10px; bottom: 0;">
<a class="botToggle" href="#" onclick="toggleBot()">Toggle Bot On/Off</a>
<textarea class="chatText" placeholder="Type a Message" autofocus></textarea><br />
<input id="submitBtn" type="submit" value="Send" />
</footer>
<div id="typingIndicator" style="display: none;">Typing a Message</div>
</div>
</body>
</html>
/**
* HTML5 ✰ Boilerplate
*
* style.css contains a reset, font normalization and some base styles.
*
* Credit is left where credit is due.
* Much inspiration was taken from these projects:
* - yui.yahooapis.com/2.8.1/build/base/base.css
* - camendesign.com/design/
* - praegnanz.de/weblog/htmlcssjs-kickstart
*/
/**
* html5doctor.com Reset Stylesheet (Eric Meyer's Reset Reloaded + HTML5 baseline)
* v1.6.1 2010-09-17 | Authors: Eric Meyer & Richard Clark
* html5doctor.com/html-5-reset-stylesheet/
*/
html, body, div, span, object, iframe,
h1, h2, h3, h4, h5, h6, p, blockquote, pre,
abbr, address, cite, code, del, dfn, em, img, ins, kbd, q, samp,
small, strong, sub, sup, var, b, i, dl, dt, dd, ol, ul, li,
fieldset, form, label, legend,
table, caption, tbody, tfoot, thead, tr, th, td,
article, aside, canvas, details, figcaption, figure,
footer, header, hgroup, menu, nav, section, summary,
time, mark, audio, video {
margin: 0;
padding: 0;
border: 0;
font-size: 100%;
font: inherit;
vertical-align: baseline;
}
article, aside, details, figcaption, figure,
footer, header, hgroup, menu, nav, section {
display: block;
}
blockquote, q { quotes: none; }
blockquote:before, blockquote:after,
q:before, q:after { content: ''; content: none; }
ins { background-color: #ff9; color: #000; text-decoration: none; }
mark { background-color: #ff9; color: #000; font-style: italic; font-weight: bold; }
del { text-decoration: line-through; }
abbr[title], dfn[title] { border-bottom: 1px dotted; cursor: help; }
table { border-collapse: collapse; border-spacing: 0; }
hr { display: block; height: 1px; border: 0; border-top: 1px solid #ccc; margin: 1em 0; padding: 0; }
input, select { vertical-align: middle; }
/**
* Font normalization inspired by YUI Library's fonts.css: developer.yahoo.com/yui/
*/
body { font:13px/1.231 sans-serif; *font-size:small; } /* Hack retained to preserve specificity. */
select, input, textarea, button { font:99% sans-serif; }
/* Normalize monospace sizing:
en.wikipedia.org/wiki/MediaWiki_talk:Common.css/Archive_11#Teletype_style_fix_for_Chrome */
pre, code, kbd, samp { font-family: monospace, sans-serif; }
/**
* Minimal base styles.
*/
body, select, input, textarea {
/* #444 looks better than black: twitter.com/H_FJ/statuses/11800719859 */
color: #444;
/* Set your base font here, to apply evenly. */
font-family: Arial, Helvetica, sans-serif;
}
/* Headers (h1, h2, etc) have no default font-size or margin. Define those yourself. */
h1, h2, h3, h4, h5, h6 { font-weight: bold; }
/* Always force a scrollbar in non-IE:
html { overflow-y: scroll; }
*/
/* Accessible focus treatment: people.opera.com/patrickl/experiments/keyboard/test */
a:hover, a:active { outline: none; }
a, a:active, a:visited { color: #607890; }
a:hover { color: #036; }
ul, ol { margin-left: 2em; }
ol { list-style-type: decimal; }
/* Remove margins for navigation lists. */
nav ul, nav li { margin: 0; list-style:none; list-style-image: none; }
small { font-size: 85%; }
strong, th { font-weight: bold; }
td { vertical-align: top; }
/* Set sub, sup without affecting line-height: gist.github.com/413930 */
sub, sup { font-size: 75%; line-height: 0; position: relative; }
sup { top: -0.5em; }
sub { bottom: -0.25em; }
pre {
/* www.pathf.com/blogs/2008/05/formatting-quoted-code-in-blog-posts-css21-white-space-pre-wrap/ */
white-space: pre; white-space: pre-wrap; white-space: pre-line; word-wrap: break-word;
padding: 15px;
}
textarea { overflow: auto; } /* www.sitepoint.com/blogs/2010/08/20/ie-remove-textarea-scrollbars/ */
.ie6 legend, .ie7 legend { margin-left: -7px; } /* thnx ivannikolic! */
/* Align checkboxes, radios, text inputs with their label by: Thierry Koblentz tjkdesign.com/ez-css/css/base.css */
input[type="radio"] { vertical-align: text-bottom; }
input[type="checkbox"] { vertical-align: bottom; }
.ie7 input[type="checkbox"] { vertical-align: baseline; }
.ie6 input { vertical-align: text-bottom; }
/* Hand cursor on clickable input elements. */
label, input[type="button"], input[type="submit"], input[type="image"], button { cursor: pointer; }
/* Webkit browsers add a 2px margin outside the chrome of form elements. */
button, input, select, textarea { margin: 0; }
/* Colors for form validity. */
input:valid, textarea:valid { }
input:invalid, textarea:invalid {
border-radius: 1px; -moz-box-shadow: 0px 0px 5px red; -webkit-box-shadow: 0px 0px 5px red; box-shadow: 0px 0px 5px red;
}
.no-boxshadow input:invalid, .no-boxshadow textarea:invalid { background-color: #f0dddd; }
/* These selection declarations have to be separate.
No text-shadow: twitter.com/miketaylr/status/12228805301
Also: hot pink. */
::-moz-selection{ background: #F2D64C; color:#fff; text-shadow: none; }
::selection { background:#F2D64C; color:#fff; text-shadow: none; }
/* j.mp/webkit-tap-highlight-color */
a:link { -webkit-tap-highlight-color: #F2D64C; }
/* Make buttons play nice in IE:
www.viget.com/inspire/styling-the-button-element-in-internet-explorer/ */
button { width: auto; overflow: visible; }
/* Bicubic resizing for non-native sized IMG:
code.flickr.com/blog/2008/11/12/on-ui-quality-the-little-things-client-side-image-resizing/ */
.ie7 img { -ms-interpolation-mode: bicubic; }
/**
* Primary styles.
*
* Author: Jacob Gable
*/
.page { margin: 10px; }
header h1
{
font-size: 1.5em;
}
dt { display: none; height:1px;}
dd
{
display: none;
background-color: #3399FF;
border-radius: 7px;
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
margin: 0px 20px 20px 0px;
padding: 5px 10px;
color: White;
position: relative;
}
dd p { margin-bottom: 5px; }
dd span { color: Black; font-weight: bold; }
dd.reply { margin: 0 0 20px 20px; }
dd .arrow
{
border-color: #3399FF transparent transparent transparent;
border-style: solid;
border-width: 10px 10px 10px 20px;
width:0;
height:0;
position: absolute;
bottom: -20px;
right: 20px;
}
dd .arrowOver
{
border-color: White transparent transparent transparent;
border-width: 10px 22px 10px 10px;
bottom: -20px;
right: 6px;
}
dd.reply { margin: 0 0 20px 20px; }
dd.reply .arrow
{
border-color: #3399FF transparent transparent transparent;
border-style: solid;
border-width: 10px 20px 10px 10px;
width:0;
height:0;
position: absolute;
bottom: -20px;
left: 20px ! important;
}
dd.reply .arrowOver
{
border-color: White transparent transparent transparent;
border-width: 10px 10px 10px 22px;
bottom: -20px;
left: 6px ! important;
}
#typingIndicator
{
background-color: white;
/* background-image: url('loady.gif'); */
background-position: left center;
background-repeat: no-repeat;
width: 100px;
height: 20px;
color: #686868;
font-size: .8em;
padding: 5px 0 0 25px;
position: fixed;
right: 15px;
top: 10px;
border-radius: 7px;
-moz-border-radius: 7px;
-webkit-border-radius: 7px;
}
#chatLog { padding: 10px; margin: 30px 0 90px 0; }
.chatText
{
width: 100%;
background-color: #BDBEBD;
border: 0px Solid Black;
line-height: 1.2em;
font-size: 1.2em;
height:auto;
height: 3em;
white-space: pre;
}
.placeholder{color:#8A8A8A}/* Placeholder text */
header { width: 100%; background-color: white; height: 35px; }
header hgroup { margin-top: 10px; }
footer { background-color: white; }
footer input[type=submit]
{
background-color: #EDEDED;
border: 1px Solid #AAAAAA;
width: 100%;
margin: 10px 0;
min-height: 2em;
}
footer a.botToggle { float: right; margin-bottom: 5px; }
/**
* Non-semantic helper classes: please define your styles before this section.
*/
/* For image replacement. */
.ir { display: block; text-indent: -999em; overflow: hidden; background-repeat: no-repeat; text-align: left; direction: ltr; }
/* Hide for both screenreaders and browsers:
css-discuss.incutio.com/wiki/Screenreader_Visibility */
.hidden { display: none; visibility: hidden; }
/* Hide only visually, but have it available for screenreaders: by Jon Neal.
www.webaim.org/techniques/css/invisiblecontent/ & j.mp/visuallyhidden */
.visuallyhidden { border: 0; clip: rect(0 0 0 0); height: 1px; margin: -1px; overflow: hidden; padding: 0; position: absolute; width: 1px; }
/* Hide visually and from screenreaders, but maintain layout. */
.invisible { visibility: hidden; }
/* The Magnificent Clearfix: Updated to prevent margin-collapsing on child elements.
j.mp/bestclearfix */
.clearfix:before, .clearfix:after { content: "\0020"; display: block; height: 0; visibility: hidden; }
.clearfix:after { clear: both; }
/* Fix clearfix: blueprintcss.lighthouseapp.com/projects/15318/tickets/5-extra-margin-padding-bottom-of-page */
.clearfix { zoom: 1; }