--- /dev/null
+{% load i18n %}
+<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN"
+ "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
+<html xmlns="http://www.w3.org/1999/xhtml">
+ <head>
+ <meta http-equiv="Content-type" content="text/html; charset=utf-8" />
+ <title>{% trans "Redakcja" %} :: {{ book.title }}</title>
+ <link rel="stylesheet" type="text/css" href="/media/static/css/book.css" />
+ <script type="text/javascript" src="http://ajax.googleapis.com/ajax/libs/jquery/1.7.1/jquery.min.js"></script>
+ <script type="text/javascript" src="/media/static/js/book_text/jquery.eventdelegation.js"></script>
+ <script type="text/javascript" src="/media/static/js/book_text/jquery.scrollto.js"></script>
+ <script type="text/javascript" src="/media/static/js/book_text/jquery.highlightfade.js"></script>
+ <script type="text/javascript" src="/media/static/js/book_text/book.js"></script>
+
+ </head>
+ <body>
+ <div id="menu">
+ <ul>
+ <li><a class="menu" href="#toc">{% trans "Table of contents" %}</a></li>
+{# <li><a class="menu" href="#themes">{% trans "Themes" %}</a></li>#}
+ <li><a class="menu" href="#nota_red">{% trans "Edit. note" %}</a></li>
+{# <li><a class="menu" href="#info">{% trans "Infobox" %}</a></li>#}
+{# <li><a href="{{ book.get_absolute_url }}">{% trans "Book's page" %}</a></li> #}
+{# <li><a class="menu" href="#download">{% trans "Download" %}</a></li>#}
+ </ul>
+ </div>
+ <div id="header">
+ <a href="/"><img src="/media/static/img/logo-220.png" alt="Wolne Lektury" /></a>
+ </div>
+ {{ html|safe }}
+ </body>
+</html>
from django.db.models import Count, Q
from django import http
from django.http import Http404, HttpResponse, HttpResponseForbidden
-from django.shortcuts import get_object_or_404, render
+from django.shortcuts import get_object_or_404, render, render_to_response
from django.utils.encoding import iri_to_uri
from django.utils.http import urlquote_plus
from django.utils.translation import ugettext_lazy as _
from django.views.decorators.http import require_POST
from django.views.generic.simple import direct_to_template
+from django.template import RequestContext
from apiclient import NotAuthorizedError
from catalogue import forms
return HttpResponseForbidden("Not authorized.")
doc = book.wldocument(parse_dublincore=False)
- html = doc.as_html(flags=['full-page'])
+ html = doc.as_html()
+
html = html.get_string() if html is not None else ''
- response = http.HttpResponse(html, content_type='text/html', mimetype='text/html')
- return response
+ # response = http.HttpResponse(html, content_type='text/html', mimetype='text/html')
+ # return response
+ # book_themes = {}
+ # for fragment in book.fragments.all().iterator():
+ # for theme in fragment.tags.filter(category='theme').iterator():
+ # book_themes.setdefault(theme, []).append(fragment)
+
+ # book_themes = book_themes.items()
+ # book_themes.sort(key=lambda s: s[0].sort_key)
+ return render_to_response('catalogue/book_text.html', locals(),
+ context_instance=RequestContext(request))
@never_cache
--- /dev/null
+body {
+ font-size: 16px;
+ font: Georgia, "Times New Roman", serif;
+ line-height: 1.5em;
+ margin: 0;
+}
+
+a {
+ color: blue;
+ text-decoration: none;
+}
+
+#book-text {
+ margin: 3em;
+ max-width: 36em;
+}
+
+/* ================================== */
+/* = Header with logo and menu = */
+/* ================================== */
+#header {
+ margin: 3.4em 0 0 1.4em;
+}
+
+img {
+ border: none;
+}
+
+#logo {
+ font-size: 1.5em;
+}
+#logo a {
+ color: black;
+}
+
+#menu {
+ position: fixed;
+ left: 0em;
+ top: 0em;
+ width: 100%;
+ height: 1.5em;
+ background: #333;
+ color: #FFF;
+ opacity: 0.9;
+ z-index: 99;
+}
+
+#menu ul {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+#menu li a {
+ display: block;
+ float: left;
+ height: 1.5em;
+ margin-left: 0.5em;
+ text-align: center;
+ color: #FFF;
+ padding: 0 1em;
+}
+#menu li a.menu {
+ padding-right: 1.5em;
+}
+
+#menu li a.menu:hover, #menu li a.menu:active {
+ color: #000;
+ background: #FFF url(/media/static/img/arrow-down.png) no-repeat center right;
+}
+
+#menu li a.menu.selected {
+ color: #000;
+ background: #FFF url(/media/static/img/arrow-up.png) no-repeat center right;
+}
+#menu a.menu-link {
+ display: block;
+ float: left;
+ height: 1.5em;
+ margin-left: 0.5em;
+ text-align: center;
+ color: #FFF;
+}
+#menu span {
+ color: #888;
+ font-style: italic;
+ font-size: .75em;
+ margin-right: 0.5em;
+}
+
+
+#toc, #themes, #nota_red, #info {
+ position: fixed;
+ left: 0em;
+ top: 1.5em;
+ width: 37em;
+ padding: 1.5em;
+ background: #FFF;
+ border-bottom: 0.25em solid #DDD;
+ border-right: 0.25em solid #DDD;
+ display: none;
+ height: 16em;
+ overflow-x: hidden;
+ overflow-y: auto;
+ opacity: 0.9;
+ z-index: 99;
+}
+#download {
+ position: fixed;
+ left: 0em;
+ top: 1.5em;
+ width: 37em;
+ padding: 1.5em;
+ background: #FFF;
+ border-bottom: 0.25em solid #DDD;
+ border-right: 0.25em solid #DDD;
+ display: none;
+ height: 10em;
+ overflow-x: hidden;
+ overflow-y: auto;
+ opacity: 0.9;
+ z-index: 99;
+}
+
+#toc ol, #themes ol {
+ list-style: none;
+ padding: 0;
+ margin: 0;
+}
+
+#toc ol li {
+ font-weight: bold;
+}
+
+#toc ol ol {
+ padding: 0 0 1.5em 1.5em;
+ margin: 0;
+}
+
+#toc ol ol li {
+ font-weight: normal;
+}
+
+#toc h2 {
+ display: none;
+}
+
+#toc .anchor {
+ float: none;
+ margin: 0;
+ color: blue;
+ font-size: 16px;
+ position: inherit;
+}
+
+#info p {
+ text-align: justify;
+ margin: 1.5em 0 0;
+}
+
+/* =================================================== */
+/* = Common elements: headings, paragraphs and lines = */
+/* =================================================== */
+h1 {
+ font-size: 3em;
+ margin: 1.5em 0;
+ text-align: center;
+ line-height: 1.5em;
+ font-weight: bold;
+}
+
+h2 {
+ font-size: 2em;
+ margin: 1.5em 0 0;
+ font-weight: bold;
+ line-height: 1.5em;
+}
+
+h3 {
+ font-size: 1.5em;
+ margin: 1.5em 0 0;
+ font-weight: normal;
+ line-height: 1.5em;
+}
+
+h4 {
+ font-size: 1em;
+ margin: 1.5em 0 0;
+ line-height: 1.5em;
+}
+
+p {
+ margin: 0;
+}
+
+/* ======================== */
+/* = Footnotes and themes = */
+/* ======================== */
+.theme-begin {
+ border-left: 0.1em solid #DDDDDD;
+ color: #777;
+ padding: 0 0.5em;
+ width: 7.5em;
+
+ font-style: normal;
+ font-weight: normal;
+ font-variant: normal;
+ letter-spacing: 0;
+ text-transform: none;
+ text-decoration: none;
+
+ font-size: 16px;
+ float: right;
+ margin-right: -9.5em;
+ margin-bottom: 0.5em;
+ clear: both;
+ left: 40em;
+ line-height: 1.5em;
+ text-align: left;
+}
+
+.annotation {
+ font-style: normal;
+ font-weight: normal;
+ font-size: 12px;
+ padding-left: 2px;
+ position: relative;
+ top: -4px;
+}
+
+#footnotes {
+ margin-top: 3em;
+}
+
+#footnotes .annotation {
+ display: block;
+ float: left;
+ width: 2.5em;
+ clear: both;
+}
+
+#footnotes div {
+ margin: 1.5em 0 0 0;
+}
+
+#footnotes p, #footnotes ul {
+ margin-left: 2.5em;
+ font-size: 0.875em;
+}
+
+#footnotes .permalink {
+ font-size: .75em;
+}
+
+blockquote {
+ font-size: 0.875em;
+}
+
+/* ============= */
+/* = Numbering = */
+/* ============= */
+.verse, .paragraph {
+ position:relative;
+}
+.anchor {
+ position: absolute;
+ margin: -0.25em -0.5em;
+ left: -3em;
+ color: #777;
+ font-size: 12px;
+ width: 2em;
+ text-align: center;
+ padding: 0.25em 0.5em;
+ line-height: 1.5em;
+}
+
+.anchor:hover, #book-text .anchor:active {
+ color: #FFF;
+ background-color: #CCC;
+}
+
+/* =================== */
+/* = Custom elements = */
+/* =================== */
+span.author {
+ font-size: 0.5em;
+ display: block;
+ line-height: 1.5em;
+ margin-bottom: 0.25em;
+}
+
+span.collection {
+ font-size: 0.375em;
+ display: block;
+ line-height: 1.5em;
+ margin-bottom: -0.25em;
+}
+
+span.subtitle {
+ font-size: 0.5em;
+ display: block;
+ line-height: 1.5em;
+ margin-top: -0.25em;
+}
+
+span.translator {
+ font-size: 0.375em;
+ display: block;
+ line-height: 1.5em;
+ margin-top: 0.25em;
+}
+
+div.didaskalia {
+ font-style: italic;
+ margin: 0.5em 0 0 1.5em;
+}
+
+div.kwestia {
+ margin: 0.5em 0 0;
+}
+
+div.stanza {
+ margin: 1.5em 0 0;
+}
+
+div.kwestia div.stanza {
+ margin: 0;
+}
+
+p.paragraph {
+ text-align: justify;
+ margin: 1.5em 0 0;
+}
+
+p.motto {
+ text-align: justify;
+ font-style: italic;
+ margin: 1.5em 0 0;
+}
+
+p.motto_podpis {
+ font-size: 0.875em;
+ text-align: right;
+}
+
+div.fragment {
+ border-bottom: 0.1em solid #999;
+ padding-bottom: 1.5em;
+}
+
+div.note p, div.dedication p, div.note p.paragraph, div.dedication p.paragraph {
+ text-align: right;
+ font-style: italic;
+}
+
+hr.spacer {
+ height: 3em;
+ visibility: hidden;
+}
+
+hr.spacer-line {
+ margin: 1.5em 0;
+ border: none;
+ border-bottom: 0.1em solid #000;
+}
+
+p.spacer-asterisk {
+ padding: 0;
+ margin: 1.5em 0;
+ text-align: center;
+}
+
+div.person-list ol {
+ list-style: none;
+ padding: 0 0 0 1.5em;
+}
+
+p.place-and-time {
+ font-style: italic;
+}
+
+em.math, em.foreign-word, em.book-title, em.didaskalia {
+ font-style: italic;
+}
+
+em.author-emphasis {
+ letter-spacing: 0.1em;
+}
+
+em.person {
+ font-style: normal;
+ font-variant: small-caps;
+}
+
+.verse:after {
+ content: "\feff";
+}
+
+
+/* =================================== */
+/* = Hide some elements for printing = */
+/* =================================== */
+
+@media print {
+ #menu {display: none;}
+}
--- /dev/null
+$(function() {
+ function scrollToAnchor(anchor) {
+ if (anchor) {
+ var anchor_name = anchor.slice(1);
+ var element = $('a[name="' + anchor_name + '"]');
+ if (element.length > 0) {
+ $.scrollTo(element, 500, {offset: {top: -50, left: 0}});
+ foot_elem = $('#footnotes a[name="' + anchor_name + '"]');
+ if (foot_elem.length > 0) {
+ $(element).parent().highlightFade('yellow');
+ }
+ window.location.hash = anchor;
+ }
+ }
+ }
+
+ $.highlightFade.defaults.speed = 3000;
+ $('#toc').hide();
+ if ($('#toc li').length == 0) {
+ $('#menu li a[href="#toc"]').remove();
+ }
+ if ($('#nota_red').length == 0) {
+ $('#menu li a[href="#nota_red"]').remove();
+ }
+
+ // On page load, scroll to anchor
+ scrollToAnchor(window.location.hash)
+
+ $('#toc, #themes, #book-text').delegate('click', 'a', function(event) {
+ event.preventDefault();
+ $('#menu li a.selected').click();
+ scrollToAnchor($(this).attr('href'));
+ });
+
+ $('#menu li a.menu').toggle(function() {
+ $('#menu li a.selected').click();
+ $(this).addClass('selected');
+ $($(this).attr('href')).slideDown('fast');
+ }, function() {
+ $(this).removeClass('selected');
+ $($(this).attr('href')).slideUp('fast');
+ });
+
+
+ if (window.getSelection) {
+ $('.theme-begin').click(function() {
+ var selection = window.getSelection();
+ selection.removeAllRanges();
+ var range = document.createRange();
+
+ var e = $(".theme-end[fid='" + $(this).attr('fid') + "']")[0];
+
+ if (e) {
+ range.setStartAfter(this);
+ range.setEndBefore(e);
+ selection.addRange(range);
+ }
+ });
+ }
+
+});
--- /dev/null
+/*
+ * jQuery Event Delegation Plugin - jquery.eventdelegation.js
+ * Fast flexible event handling
+ *
+ * January 2008 - Randy Morey (http://dev.distilldesign.com/)
+ */
+
+(function ($) {
+ /* setup list of allowed events for event delegation
+ * only events that bubble are appropriate
+ */
+ var allowed = {};
+ $.each([
+ 'click',
+ 'dblclick',
+ 'mousedown',
+ 'mouseup',
+ 'mousemove',
+ 'mouseover',
+ 'mouseout',
+ 'keydown',
+ 'keypress',
+ 'keyup'
+ ], function(i, eventName) {
+ allowed[eventName] = true;
+ });
+
+ $.fn.extend({
+ delegate: function (event, selector, f) {
+ return $(this).each(function () {
+ if (allowed[event])
+ $(this).bind(event, function (e) {
+ var el = $(e.target),
+ result = false;
+
+ while (!$(el).is('body')) {
+ if ($(el).is(selector)) {
+ result = f.apply($(el)[0], [e]);
+ if (result === false)
+ e.preventDefault();
+ return;
+ }
+
+ el = $(el).parent();
+ }
+ });
+ });
+ },
+ undelegate: function (event) {
+ return $(this).each(function () {
+ $(this).unbind(event);
+ });
+ }
+ });
+})(jQuery);
\ No newline at end of file
--- /dev/null
+/**
+ * jQuery Plugin highlightFade (jquery.offput.ca/highlightFade)
+ * (c) 2006 Blair Mitchelmore (offput.ca) blair@offput.ca
+ */
+/**
+ * This is version 0.7 of my highlightFade plugin. It follows the yellow fade technique of Web 2.0 fame
+ * but expands it to allow any starting colour and allows you to specify the end colour as well.
+ *
+ * For the moment, I'm done with this plug-in. Unless I come upon a really cool feature it should have
+ * this plug-in will only receive updates to ensure future compatibility with jQuery.
+ *
+ * As of now (Aug. 16, 2006) the plugin has been written with the 1.0.1 release of jQuery (rev 249) which
+ * is available from http://jquery.com/src/jquery-1.0.1.js
+ *
+ * A note regarding rgb() syntax: I noticed that most browsers implement rgb syntax as either an integer
+ * (0-255) or percentage (0-100%) value for each field, that is, rgb(i/p,i/p,i/p); however, the W3C
+ * standard clearly defines it as "either three integer values or three percentage values" [http://www.w3.org/TR/CSS21/syndata.html]
+ * which I choose to follow despite the error redundancy of the typical behaviour browsers employ.
+ *
+ * Changelog:
+ *
+ * 0.7:
+ * - Added the awesome custom attribute support written by George Adamson (slightly modified)
+ * - Removed bgColor plugin dependency seeing as attr is customizable now...
+ * 0.6:
+ * - Abstracted getBGColor into its own plugin with optional test and data retrieval functions
+ * - Converted all $ references to jQuery references as John's code seems to be shifting away
+ * from that and I don't want to have to update this for a long time.
+ * 0.5:
+ * - Added simple argument syntax for only specifying start colour of event
+ * - Removed old style argument syntax
+ * - Added 'interval', 'final, and 'end' properties
+ * - Renamed 'color' property to 'start'
+ * - Added second argument to $.highlightFade.getBGColor to bypass the e.highlighting check
+ * 0.4:
+ * - Added rgb(%,%,%) color syntax
+ * 0.3:
+ * - Fixed bug when event was called while parent was also running event corrupting the
+ * the background colour of the child
+ * 0.2:
+ * - Fixed bug where an unspecified onComplete function made the page throw continuous errors
+ * - Fixed bug where multiple events on the same element would speed each subsequent event
+ * 0.1:
+ * - Initial Release
+ *
+ * @author Blair Mitchelmore (blair@offput.ca)
+ * @version 0.5
+ */
+jQuery.fn.highlightFade = function(settings) {
+ var o = (settings && settings.constructor == String) ? {start: settings} : settings || {};
+ var d = jQuery.highlightFade.defaults;
+ var i = o['interval'] || d['interval'];
+ var a = o['attr'] || d['attr'];
+ var ts = {
+ 'linear': function(s,e,t,c) { return parseInt(s+(c/t)*(e-s)); },
+ 'sinusoidal': function(s,e,t,c) { return parseInt(s+Math.sin(((c/t)*90)*(Math.PI/180))*(e-s)); },
+ 'exponential': function(s,e,t,c) { return parseInt(s+(Math.pow(c/t,2))*(e-s)); }
+ };
+ var t = (o['iterator'] && o['iterator'].constructor == Function) ? o['iterator'] : ts[o['iterator']] || ts[d['iterator']] || ts['linear'];
+ if (d['iterator'] && d['iterator'].constructor == Function) t = d['iterator'];
+ return this.each(function() {
+ if (!this.highlighting) this.highlighting = {};
+ var e = (this.highlighting[a]) ? this.highlighting[a].end : jQuery.highlightFade.getBaseValue(this,a) || [255,255,255];
+ var c = jQuery.highlightFade.getRGB(o['start'] || o['colour'] || o['color'] || d['start'] || [255,255,128]);
+ var s = jQuery.speed(o['speed'] || d['speed']);
+ var r = o['final'] || (this.highlighting[a] && this.highlighting[a].orig) ? this.highlighting[a].orig : jQuery.curCSS(this,a);
+ if (o['end'] || d['end']) r = jQuery.highlightFade.asRGBString(e = jQuery.highlightFade.getRGB(o['end'] || d['end']));
+ if (typeof o['final'] != 'undefined') r = o['final'];
+ if (this.highlighting[a] && this.highlighting[a].timer) window.clearInterval(this.highlighting[a].timer);
+ this.highlighting[a] = { steps: ((s.duration) / i), interval: i, currentStep: 0, start: c, end: e, orig: r, attr: a };
+ jQuery.highlightFade(this,a,o['complete'],t);
+ });
+};
+
+jQuery.highlightFade = function(e,a,o,t) {
+ e.highlighting[a].timer = window.setInterval(function() {
+ var newR = t(e.highlighting[a].start[0],e.highlighting[a].end[0],e.highlighting[a].steps,e.highlighting[a].currentStep);
+ var newG = t(e.highlighting[a].start[1],e.highlighting[a].end[1],e.highlighting[a].steps,e.highlighting[a].currentStep);
+ var newB = t(e.highlighting[a].start[2],e.highlighting[a].end[2],e.highlighting[a].steps,e.highlighting[a].currentStep);
+ jQuery(e).css(a,jQuery.highlightFade.asRGBString([newR,newG,newB]));
+ if (e.highlighting[a].currentStep++ >= e.highlighting[a].steps) {
+ jQuery(e).css(a,e.highlighting[a].orig || '');
+ window.clearInterval(e.highlighting[a].timer);
+ e.highlighting[a] = null;
+ if (o && o.constructor == Function) o.call(e);
+ }
+ },e.highlighting[a].interval);
+};
+
+jQuery.highlightFade.defaults = {
+ start: [255,255,128],
+ interval: 50,
+ speed: 400,
+ attr: 'backgroundColor'
+};
+
+jQuery.highlightFade.getRGB = function(c,d) {
+ var result;
+ if (c && c.constructor == Array && c.length == 3) return c;
+ if (result = /rgb\(\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*,\s*([0-9]{1,3})\s*\)/.exec(c))
+ return [parseInt(result[1]),parseInt(result[2]),parseInt(result[3])];
+ else if (result = /rgb\(\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*,\s*([0-9]+(?:\.[0-9]+)?)\%\s*\)/.exec(c))
+ return [parseFloat(result[1])*2.55,parseFloat(result[2])*2.55,parseFloat(result[3])*2.55];
+ else if (result = /#([a-fA-F0-9]{2})([a-fA-F0-9]{2})([a-fA-F0-9]{2})/.exec(c))
+ return [parseInt("0x" + result[1]),parseInt("0x" + result[2]),parseInt("0x" + result[3])];
+ else if (result = /#([a-fA-F0-9])([a-fA-F0-9])([a-fA-F0-9])/.exec(c))
+ return [parseInt("0x"+ result[1] + result[1]),parseInt("0x" + result[2] + result[2]),parseInt("0x" + result[3] + result[3])];
+ else
+ return jQuery.highlightFade.checkColorName(c) || d || null;
+};
+
+jQuery.highlightFade.asRGBString = function(a) {
+ return "rgb(" + a.join(",") + ")";
+};
+
+jQuery.highlightFade.getBaseValue = function(e,a,b) {
+ var s, t;
+ b = b || false;
+ t = a = a || jQuery.highlightFade.defaults['attr'];
+ do {
+ s = jQuery(e).css(t || 'backgroundColor');
+ if ((s != '' && s != 'transparent') || (e.tagName.toLowerCase() == "body") || (!b && e.highlighting && e.highlighting[a] && e.highlighting[a].end)) break;
+ t = false;
+ } while (e = e.parentNode);
+ if (!b && e.highlighting && e.highlighting[a] && e.highlighting[a].end) s = e.highlighting[a].end;
+ if (s == undefined || s == '' || s == 'transparent') s = [255,255,255];
+ return jQuery.highlightFade.getRGB(s);
+};
+
+jQuery.highlightFade.checkColorName = function(c) {
+ if (!c) return null;
+ switch(c.replace(/^\s*|\s*$/g,'').toLowerCase()) {
+ case 'aqua': return [0,255,255];
+ case 'black': return [0,0,0];
+ case 'blue': return [0,0,255];
+ case 'fuchsia': return [255,0,255];
+ case 'gray': return [128,128,128];
+ case 'green': return [0,128,0];
+ case 'lime': return [0,255,0];
+ case 'maroon': return [128,0,0];
+ case 'navy': return [0,0,128];
+ case 'olive': return [128,128,0];
+ case 'purple': return [128,0,128];
+ case 'red': return [255,0,0];
+ case 'silver': return [192,192,192];
+ case 'teal': return [0,128,128];
+ case 'white': return [255,255,255];
+ case 'yellow': return [255,255,0];
+ }
+};
--- /dev/null
+/**
+ * jQuery.ScrollTo
+ * Copyright (c) 2007-2008 Ariel Flesler - aflesler(at)gmail(dot)com | http://flesler.blogspot.com
+ * Dual licensed under MIT and GPL.
+ * Date: 9/11/2008
+ *
+ * @projectDescription Easy element scrolling using jQuery.
+ * http://flesler.blogspot.com/2007/10/jqueryscrollto.html
+ * Tested with jQuery 1.2.6. On FF 2/3, IE 6/7, Opera 9.2/5 and Safari 3. on Windows.
+ *
+ * @author Ariel Flesler
+ * @version 1.4
+ *
+ * @id jQuery.scrollTo
+ * @id jQuery.fn.scrollTo
+ * @param {String, Number, DOMElement, jQuery, Object} target Where to scroll the matched elements.
+ * The different options for target are:
+ * - A number position (will be applied to all axes).
+ * - A string position ('44', '100px', '+=90', etc ) will be applied to all axes
+ * - A jQuery/DOM element ( logically, child of the element to scroll )
+ * - A string selector, that will be relative to the element to scroll ( 'li:eq(2)', etc )
+ * - A hash { top:x, left:y }, x and y can be any kind of number/string like above.
+ * @param {Number} duration The OVERALL length of the animation, this argument can be the settings object instead.
+ * @param {Object,Function} settings Optional set of settings or the onAfter callback.
+ * @option {String} axis Which axis must be scrolled, use 'x', 'y', 'xy' or 'yx'.
+ * @option {Number} duration The OVERALL length of the animation.
+ * @option {String} easing The easing method for the animation.
+ * @option {Boolean} margin If true, the margin of the target element will be deducted from the final position.
+ * @option {Object, Number} offset Add/deduct from the end position. One number for both axes or { top:x, left:y }.
+ * @option {Object, Number} over Add/deduct the height/width multiplied by 'over', can be { top:x, left:y } when using both axes.
+ * @option {Boolean} queue If true, and both axis are given, the 2nd axis will only be animated after the first one ends.
+ * @option {Function} onAfter Function to be called after the scrolling ends.
+ * @option {Function} onAfterFirst If queuing is activated, this function will be called after the first scrolling ends.
+ * @return {jQuery} Returns the same jQuery object, for chaining.
+ *
+ * @desc Scroll to a fixed position
+ * @example $('div').scrollTo( 340 );
+ *
+ * @desc Scroll relatively to the actual position
+ * @example $('div').scrollTo( '+=340px', { axis:'y' } );
+ *
+ * @dec Scroll using a selector (relative to the scrolled element)
+ * @example $('div').scrollTo( 'p.paragraph:eq(2)', 500, { easing:'swing', queue:true, axis:'xy' } );
+ *
+ * @ Scroll to a DOM element (same for jQuery object)
+ * @example var second_child = document.getElementById('container').firstChild.nextSibling;
+ * $('#container').scrollTo( second_child, { duration:500, axis:'x', onAfter:function(){
+ * alert('scrolled!!');
+ * }});
+ *
+ * @desc Scroll on both axes, to different values
+ * @example $('div').scrollTo( { top: 300, left:'+=200' }, { axis:'xy', offset:-20 } );
+ */
+;(function( $ ){
+
+ var $scrollTo = $.scrollTo = function( target, duration, settings ){
+ $(window).scrollTo( target, duration, settings );
+ };
+
+ $scrollTo.defaults = {
+ axis:'y',
+ duration:1
+ };
+
+ // Returns the element that needs to be animated to scroll the window.
+ // Kept for backwards compatibility (specially for localScroll & serialScroll)
+ $scrollTo.window = function( scope ){
+ return $(window).scrollable();
+ };
+
+ // Hack, hack, hack... stay away!
+ // Returns the real elements to scroll (supports window/iframes, documents and regular nodes)
+ $.fn.scrollable = function(){
+ return this.map(function(){
+ // Just store it, we might need it
+ var win = this.parentWindow || this.defaultView,
+ // If it's a document, get its iframe or the window if it's THE document
+ elem = this.nodeName == '#document' ? win.frameElement || win : this,
+ // Get the corresponding document
+ doc = elem.contentDocument || (elem.contentWindow || elem).document,
+ isWin = elem.setInterval;
+
+ return elem.nodeName == 'IFRAME' || isWin && $.browser.safari ? doc.body
+ : isWin ? doc.documentElement
+ : this;
+ });
+ };
+
+ $.fn.scrollTo = function( target, duration, settings ){
+ if( typeof duration == 'object' ){
+ settings = duration;
+ duration = 0;
+ }
+ if( typeof settings == 'function' )
+ settings = { onAfter:settings };
+
+ settings = $.extend( {}, $scrollTo.defaults, settings );
+ // Speed is still recognized for backwards compatibility
+ duration = duration || settings.speed || settings.duration;
+ // Make sure the settings are given right
+ settings.queue = settings.queue && settings.axis.length > 1;
+
+ if( settings.queue )
+ // Let's keep the overall duration
+ duration /= 2;
+ settings.offset = both( settings.offset );
+ settings.over = both( settings.over );
+
+ return this.scrollable().each(function(){
+ var elem = this,
+ $elem = $(elem),
+ targ = target, toff, attr = {},
+ win = $elem.is('html,body');
+
+ switch( typeof targ ){
+ // A number will pass the regex
+ case 'number':
+ case 'string':
+ if( /^([+-]=)?\d+(px)?$/.test(targ) ){
+ targ = both( targ );
+ // We are done
+ break;
+ }
+ // Relative selector, no break!
+ targ = $(targ,this);
+ case 'object':
+ // DOMElement / jQuery
+ if( targ.is || targ.style )
+ // Get the real position of the target
+ toff = (targ = $(targ)).offset();
+ }
+ $.each( settings.axis.split(''), function( i, axis ){
+ var Pos = axis == 'x' ? 'Left' : 'Top',
+ pos = Pos.toLowerCase(),
+ key = 'scroll' + Pos,
+ old = elem[key],
+ Dim = axis == 'x' ? 'Width' : 'Height',
+ dim = Dim.toLowerCase();
+
+ if( toff ){// jQuery / DOMElement
+ attr[key] = toff[pos] + ( win ? 0 : old - $elem.offset()[pos] );
+
+ // If it's a dom element, reduce the margin
+ if( settings.margin ){
+ attr[key] -= parseInt(targ.css('margin'+Pos)) || 0;
+ attr[key] -= parseInt(targ.css('border'+Pos+'Width')) || 0;
+ }
+
+ attr[key] += settings.offset[pos] || 0;
+
+ if( settings.over[pos] )
+ // Scroll to a fraction of its width/height
+ attr[key] += targ[dim]() * settings.over[pos];
+ }else
+ attr[key] = targ[pos];
+
+ // Number or 'number'
+ if( /^\d+$/.test(attr[key]) )
+ // Check the limits
+ attr[key] = attr[key] <= 0 ? 0 : Math.min( attr[key], max(Dim) );
+
+ // Queueing axes
+ if( !i && settings.queue ){
+ // Don't waste time animating, if there's no need.
+ if( old != attr[key] )
+ // Intermediate animation
+ animate( settings.onAfterFirst );
+ // Don't animate this axis again in the next iteration.
+ delete attr[key];
+ }
+ });
+ animate( settings.onAfter );
+
+ function animate( callback ){
+ $elem.animate( attr, duration, settings.easing, callback && function(){
+ callback.call(this, target, settings);
+ });
+ };
+ function max( Dim ){
+ var attr ='scroll'+Dim,
+ doc = elem.ownerDocument;
+
+ return win
+ ? Math.max( doc.documentElement[attr], doc.body[attr] )
+ : elem[attr];
+ };
+ }).end();
+ };
+
+ function both( val ){
+ return typeof val == 'object' ? val : { top:val, left:val };
+ };
+
+})( jQuery );
\ No newline at end of file