Quote of the Day Web Part, Reprised – Part 2
This is the second part of a two part series on how to create a Quote of the Day web part whose quotes are drawn from a SharePoint list. The first article created the foundation for accessing the list. In this section, randomizing the quotes is considered.
Quote of the day
One approach you might’ve thought of is to use cookies to store the quote of the day. Each time the user comes to the page, JavaScript would check whether it’s the first time that this user is visiting the page or not (cookie available or not).
If it’s the first time, it would pick a random quote using the ‘random’ function we have just added to jQuery and then store the choice in the cookie on the user’s computer. On all subsequent visits it would retrieve the quote stored in the cookie instead of retrieving another one. By setting the cookie expiration time to one day you would ensure that another quote will be chosen if the user comes back tomorrow.
The downside of that approach is using cookies. They have a rather bad name because they are often misused to track user’s activity on the Internet. That’s why many users turn them off. Furthermore the approach described above could pick a different quote of the day for each user. As it would use the ‘random’ function there is no guarantee that all users would see the same quote.
While consistency wasn’t a part of our requirements list, it is definitely something you should keep in mind while working with/extending the Web Part.
There is another way though: why not make a large number out of the current date and modulo divide it by the number of quotes? The power of the modulo division is that it returns the remainder of the division (eg. 10%3=1): perfect if you want to retrieve a number from a particular range. So let’s change the ‘random’ function a little using the modulo division concept:
randomByDay: function() {
var now = new Date();
return $(this[now.getFullDate() % this.length]);
}
If you would save the above change, you would get a JavaScript error. Retrieving a large number of out the current date involves a couple of extra lines of code. Writing it inside the ‘randomByDay’ function would make the code unnecessarily complex. Instead I chose to extend the JavaScript Date object:
Date.prototype.getFullDate = function() {
var dateAsString = "";
dateAsString += this.getFullYear();
var month = this.getMonth() + 1;
if (month < 10) {
dateAsString += 0;
}
dateAsString += month;
var day = this.getDate();
if (day < 10) {
dateAsString += 0;
}
dateAsString += day;
return parseInt(dateAsString);
}
Let’s see our code so far:
<script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.2.6/jquery.min.js"></script>
<script type="text/javascript">
jQuery.fn.extend({
randomByDay: function() {
var now = new Date();
return $(this[now.getFullDate() % this.length]);
}
});
</script>
<script type="text/javascript">
Date.prototype.getFullDate = function() {
var dateAsString = "";
dateAsString += this.getFullYear();
var month = this.getMonth() + 1;
if (month < 10) {
dateAsString += 0;
}
dateAsString += month;
var day = this.getDate();
if (day < 10) {
dateAsString += 0;
}
dateAsString += day;
return parseInt(dateAsString);
}
</script>
<script type="text/javascript">
var Imtech = Imtech || {};
Imtech.QuoteOfTheDay = function(listName) {
var selector = "table[class=ms-listviewtable][summary='" + listName + "'] > tbody > tr";
var quote = { text: null, author: null, obj: null };
var renderQuote = function() {
quote.obj.parents("table:first").parents("td:first").html('<blockquote><p>' + quote.text + '</p><p class="author">' + quote.author + '</p></blockquote>')
}
this.init = function() {
var quotes = $(selector).not(":first");
quote.obj = quotes.randomByDay();
quote.text = $("td:first", quote.obj).text();
quote.author = $("td:last", quote.obj).text();
renderQuote();
}
}
</script>
<script type="text/javascript">
var quoteOfTheDay;
$(function() {
quoteOfTheDay = new Imtech.QuoteOfTheDay("Quotes");
quoteOfTheDay.init();
});
</script>
And the results:

For the clarity I’ve put all the different JavaScript pieces in separate script blocks. Please note that if you would like to reuse the solution across multiple pages, you could move the code of all these script blocks except the last one and save it to an external .js file. Such change would improve the page load as the separate JavaScript file would be cached on the user’s computer and all they would have to download is the small piece of JavaScript which initializes the Web Part.
That’s all. We’ve got our Web Part working.
Extra: Let’s prettify it
While we’re done with our requirements, the output isn’t end user ready if you’d ask me. We could however easily prettify it using a little piece of CSS:
blockquote p { font: italic bold 1.2em/1.2 "Times New Roman" , serif; }
blockquote p.author {
font: normal 0.8em/1.2 sans-serif;
color: #666;
text-align: right;
}

Looks way better, doesn’t it?
Summary
Using jQuery you can build some great functionality on top of SharePoint. The best part is that it can be achieved without deploying of even a single line of server-side code.
In the example above we’ve stepped through the process of creating a Web Part on top of a List View. We’ve seen how jQuery can retrieve data out of a standard SharePoint List. Additionally we’ve learned how we can extend both jQuery and JavaScript with custom functions and use CSS to change the way the text is being displayed.
Other ideas? Leave a suggestion in the comments and I’ll see what I can do.
Waldek Mastykarz
Innovation Matters
Waldek Mastykarz is a Dutch SharePoint MVP specialized in Web Content Management solutions in Microsoft Office SharePoint Server 2007, web standards and accessibility.
- Quote of the Day Web Part, Reprised - Part 1
- Quote of the Day Web Part, Reprised - Part 2





Great Post! How do you add a CSS snippet to the page without touching the template or core.css? I’d love to know that trick too.
Waldek,
Nice upgrade! One question, where does the CSS code snippet go?
Thanks!
This is is great article but my knowledge about putting css into javascript is not enough. Could You explain where can I put css lines?
What you could do is to add the CSS block just under/above the JavaScript in the same Content Editor Web Part:
Hi,
This is great, but it relies on someone remembering to add quotes to a list, is there a way of tapping into an unlimited [internet] source of quotes?
Thanks.
Theoretically it would be possible to retrieve the quotes from the Internet. Unfortunately that would result in a cross-domain request (by default you’re not allowed to make a call to another domain due to security issues).
Another possibility would be to display the quotes based on the RSS Viewer web part which would retrieve the quotes from an RSS somewhere on the Internet.
Hi. Cool but I can’t get the CSS to work. Any help?
Could you provide any more details on what you’ve already tried and what you’re stuck on?
Thank You for help – this is a good Idea for Intranet sites! I implement this and works fine!
Well I can get it to work fine apart from slotting in the CSS code. Anyone have the Webpart code with the CSS working?
Waldek,
I tried your solution (comment 5)and tried it in several places in the code. It did not work. Any other ideas?
Thanks!
Dave
As far as I can tell it should work. The CSS piece for prettyfying was originally included just above the JavaScript in the same CEWP. Are you sure that the code is being properly output and that there is no other CSS on your page which could override the ones from the Web Part?
Code as follows… CSS at the bottom not working.
jQuery.fn.extend({ randomByDay: function() { var now = new Date(); return $(this[now.getFullDate() % this.length]); } }); Date.prototype.getFullDate = function() { var dateAsString = ""; dateAsString += this.getFullYear(); var month = this.getMonth() + 1; if (month < 10) { dateAsString += 0; } dateAsString += month; var day = this.getDate(); if (day < 10) { dateAsString += 0; } dateAsString += day; return parseInt(dateAsString); } var Imtech = Imtech || {}; Imtech.QuoteOfTheDay = function(listName) { var selector = "table[class=ms-listviewtable][summary='" + listName + "'] > tbody > tr"; var quote = { text: null, author: null, obj: null }; var renderQuote = function() { quote.obj.parents("table:first").parents("td:first").html(' ') } this.init = function() { var quotes = $(selector).not(":first"); quote.obj = quotes.randomByDay(); quote.text = $("td:first", quote.obj).text(); quote.author = $("td:last", quote.obj).text(); renderQuote(); } } var quoteOfTheDay; $(function() { quoteOfTheDay = new Imtech.QuoteOfTheDay("Quotes"); quoteOfTheDay.init(); }); blockquote p { font: italic bold 1.2em/1.2 "Times New Roman" , serif; } blockquote p.author { font: normal 0.8em/1.2 sans-serif; color: #666; text-align: right; }That didn’t come out right :/
Tony – How’s that… a little better? — Mark
Did you change the code or just place it in that format.
When I pasted it, it removed all the “”" blocks.
The simple solution would be to paste the code from above with the CSS included properly then at least I’m on the same page ;)
These block headers…. Seems you can’t just type in
script type=”text/javascript.
Sorry for ruining these comments but I see no way to preview or amend.
From Tony (cut and paste by Mark)
I’m trying to get the css into it. As suggested, I’ve tried putting it into a block of its own at the top , bottom and in between the above;)
blockquote p { font: italic bold 1.2em/1.2 "Times New Roman" , serif; }blockquote p.author {font: normal 0.8em/1.2 sans-serif;color: #666;text-align: right;}With no success.
Tony
I concur with Tony. The original script works well, but I can not get the css portion to work. I enlisted the aid of a knowledgeable coworker and he said the css will work if it is placed in the master page. This is not something we want users to do. Plus it defeats the cut and paste approach EUSP supports.
I hope we can get this working because we could adapt this code for other uses.
Dave
Hi guys,
I just took a look at the page which I used to write this article. My CEWP contains (in the following order):
- style: CSS style
- script: reference to jQuery @ Google
- script: jQuery extend randomByDay
- script: Date extend (getFullDate function)
- script: Imtech.QuoteOfTheDay
- script: initiation
It’s all in one CEWP and is being properly displayed. Can you confirm that there is no other CSS included which could override the definitions inside CEWP?
Waldek – If you’ll email me your updated web part with the CSS included, I’ll post a link for people to download and then they can just adjust the web part. Thanks. — Mark
Waldek has sent me an updated web part with the CSS embedded at the top of the source. Try it out and please get back to us here to let us know it is working properly for you. — Thanks. Mark and Waldek
http://www.endusersharepoint.com/blog/wp-content/uploads/2009/01/EndUserSharePoint-RandomQuotesWebPart.zip
Works for me!
Thanks guys.
Cool! Great to hear that :)
since the quotes are now in an SP list, is there a way to include a hyperlink in the quote? (seeing as its now changed to a field in the list)
How about the ability to scroll through the quotes or at least get a new one every refresh?
@Tony: See the end of Part 1
@Teena: If the quote is a Rich HTML field, it shouldn’t be a problem
I think where I went wrong on adding the CSS at first was in copying the text from Waldek in post #5 above:
When I changed the quote marks (as shown below), the web part worked as expected:
I’m still trying to get this to work with hyperlinks.
My list has one column for a quote and another column for a URL.
The quote displays twice on the webpage – one above the other within the same webpart.
The link does not display or associate with the quote. help please!
I am still having trouble getting this working with hyperlinks. I would like the quote to display as a link.
My list has 2 columns, one for Quote and one for URL.
The Quote displays on the webpage twice, one above the other within the webpart. Neither is the URL or hyperlinked.
Otherwise a very good tool. Any help appreciated!
It seems like your JavaScript refers twice to the same column. It would be easier for us to help if you posted the snippet that does the job (but not the whole thing, please).
var renderQuote = function() {
quote.obj.parents(”table:first”).parents(”td:first”).html(’
‘)
}
produces the repeated quote
var renderQuote = function() {
quote.obj.parents(”table:first”).parents(”td:first”).html(’
Craig, have you modified the JavaScript in any way or are you using the standard Web Part provided by Mark?
Not modified at all. I think I’m using the same code as comment 19.
I’ve managed to download the revised Quote of the Day webpart, but when I try to import the webpart into my site, I’m prompted to enter credentials for endusersharepoint.securespsites.com.
What am I doing wrong?
Thanks so much!
Oh, never mind. When I imported the new webpart that Mark posted in comment #23, it worked fine.
Thanks so much, Waldek – love it!
Hi, whatever I do I cannot get the “Author” column to display. “Quote” is fine. Am I missing something?
This does work on WSS doesn’t it?
MattH: It should work on WSS. Have you changed anything about the List View your using comparing to the one described in this article?
You were right, my view wasn’t configured to show both fields.. i’ve now got a random film quote one on our social page and daily “deep and meaningful” quote on our front page. :)
Thanks a lot!
to make the link clickable change:
quote.text = $(”td:first”, quote.obj).text();
to
quote.text = $(”td:first”, quote.obj).html();
Hi, I created a list and a put a list view web part onto my home page and then downloaded the web part posted in comment #23 and uploaded as described. The list view does not change at all – it is still showing all quotes and even has a ‘Add new Item’ at the end. Do you have any ideas on what I am doing wrong
Do you have a content editor webpart on the page? make sure it’s there and that in the source editor you have the correct code.
Yes I do have the content editor webpart on the page – I uploaded the one on comment #23 and then dragged and dropped into the page. It doesn’t appear to link to the list view in any way. I have even called my list view webpart ‘quotes’ so that I didn’t have to edit the code in any way
Thank you so much for your help. I have the web part up and running and it is great. It has given me more confidence to try other ideas on your site. With luck I may even get to a workshop though the time difference maybe an issue. Again many thanks
Thanks much for this! I’m playing around with it and see huge potential for this in various parts of our new intranet site. One observation, the text of the quote seems to be pushed up to the very top of the web part. Is there some way to control the amount of whitespace between the top of the webpart and the beginning of the quote?
Hi all:
I don’t know why, but I can’t see the code in the body of the article itself.
Mark is kind enough to have a ZIP file of the code in the comments, but I would never have gotten this from the article itself.
For what it’s worth: there’s only blank space visible between this section:
————————————-
Let’s see our code so far:
And the results:
————————
George – Should be good to go, now. — Mark
I love you site and the information provide. I seem to miss a step. I down load the zip file.
Created the qoutes web part, added the random qoute web part., changed the url to point to the min.js on my site. I have moved the random quote web part above and below the quote web part.
What did I miss in the instructions. Can help me. thanks