merge from trunk

This commit is contained in:
Charles Haley 2010-10-16 13:38:42 +01:00
commit dc5875d402
28 changed files with 854 additions and 172 deletions

View File

@ -176,6 +176,10 @@ h2.library_name {
overflow: hidden; overflow: hidden;
} }
#search_box .ui-button {
padding: 0.25em;
}
/* }}} */ /* }}} */
/* Top level {{{ */ /* Top level {{{ */
@ -259,4 +263,162 @@ h2.library_name {
/* }}} */ /* }}} */
/* Booklist {{{ */
#booklist .page {
display: none;
}
#booklist .load_data { display: none }
.loading img {
vertical-align: middle;
}
#booklist .summary {
margin-bottom: 2ex;
border-bottom: solid 1px black;
}
#booklist div.left {
float: left;
height: 190px;
width: 100px;
vertical-align: middle;
text-align: center;
margin-left: 1em;
margin-right: 2em;
}
#booklist div.left img {
display: block;
margin-bottom: 1ex;
margin-left: auto;
margin-right: auto;
}
#booklist div.right {
height: 190px;
overflow: auto;
margin-left: 1em;
margin-right: 1em;
}
#booklist div.right .stars {
float:right;
margin-right: 1em;
}
#booklist div.right .stars .rating_container {
display: block;
}
#booklist div.right .stars .series {
display: block;
}
#booklist .title {
font-size: larger;
}
#booklist a {
text-decoration: none;
color: blue;
}
#booklist a:hover {
color: red;
}
#booklist .left .ui-button-text {
font-size: medium;
color: black;
padding-left: 0.25em;
padding-right: 0.25em;
padding-top: 0.25em;
padding-bottom: 0.25em;
}
#booklist .listnav {
display: table;
width: 100%;
}
#booklist .listnav a {
color: blue;
text-decoration: none;
}
#booklist .listnav a:hover {
color: red;
}
#booklist .topnav {
border-bottom: solid black 1px;
margin-bottom: 1ex;
}
#booklist .navleft {
display: table-cell;
text-align: left;
}
#booklist .navleft a {
margin-right: 1em;
}
#booklist .navmiddle {
display: table-cell;
text-align: center;
}
#booklist .navright {
display: table-cell;
text-align: right;
}
#booklist .navright a {
margin-left: 1em;
}
/* }}} */
/* Details {{{ */
.details .left {
float: left;
max-width: 50%;
margin-right: 2em;
overflow: auto;
}
.details .right {
overflow: auto;
}
.details .formats {
margin-bottom: 2ex;
}
#book_details_dialog .details a {
color: blue;
text-decoration: none;
}
#book_details_dialog .details a:hover {
color: red;
}
.details .field {
margin-bottom: 0.5em;
}
.details .comment {
margin-left: 1em;
overflow: auto;
max-height: 50%;
}
/* }}} */

View File

@ -76,8 +76,8 @@
</select> </select>
</div> </div>
<div id="search_box"> <div id="search_box">
<form name="search_form" action="/browse/search" method="get"> <form name="search_form" action="/browse/search" method="get" accept-charset="UTF-8">
<input value="" type="text" title="Search" <input value="{initial_search}" type="text" title="Search" name="query"
class="search_input" />&nbsp; class="search_input" />&nbsp;
<input type="submit" value="Search" title="Search" alt="Search" /> <input type="submit" value="Search" title="Search" alt="Search" />
</form> </form>
@ -94,5 +94,6 @@
</div> </div>
</div> </div>
</div> </div>
<div id="book_details_dialog"></div>
</body> </body>
</html> </html>

View File

@ -89,11 +89,14 @@ function render_error(msg) {
} }
// Category feed {{{ // Category feed {{{
function category_clicked() {
var href = $(this).find("span.href").html();
window.location = href;
}
function category() { function category() {
$(".category .category-item").click(function() { $(".category .category-item").click(category_clicked);
var href = $(this).find("span.href").html();
window.location = href;
});
$(".category a.navlink").button(); $(".category a.navlink").button();
@ -111,10 +114,12 @@ function category() {
if (href) { if (href) {
$.ajax({ $.ajax({
url:href, url:href,
data:{'sort':cookie(sort_cookie_name)},
success: function(data) { success: function(data) {
this.children(".loaded").html(data); this.children(".loaded").html(data);
this.children(".loaded").show(); this.children(".loaded").show();
this.children(".loading").hide(); this.children(".loading").hide();
this.find('.category-item').click(category_clicked);
}, },
context: ui.newContent, context: ui.newContent,
dataType: "json", dataType: "json",
@ -132,4 +137,99 @@ function category() {
} }
// }}} // }}}
// Booklist {{{
function first_page() {
load_page($("#booklist #page0"));
}
function last_page() {
load_page($("#booklist .page").last());
}
function next_page() {
var elem = $("#booklist .page:visible").next('.page');
if (elem.length > 0) load_page(elem);
else first_page();
}
function previous_page() {
var elem = $("#booklist .page:visible").prev('.page');
if (elem.length > 0) load_page(elem);
else last_page();
}
function load_page(elem) {
if (elem.is(":visible")) return;
var ld = elem.find('.load_data');
var ids = ld.attr('title');
var href = ld.find(".url").attr('title');
elem.children(".loaded").hide();
$.ajax({
url: href,
context: elem,
dataType: "json",
type: 'POST',
timeout: 600000, //milliseconds (10 minutes)
data: {'ids': ids},
error: function(xhr, stat, err) {
this.children(".loaded").html(render_error(stat));
this.children(".loaded").show();
this.children(".loading").hide();
},
success: function(data) {
this.children(".loaded").html(data);
this.find(".left a.read").button();
this.children(".loading").hide();
this.parent().find('.navmiddle .start').html(this.find('.load_data .start').attr('title'));
this.parent().find('.navmiddle .end').html(this.find('.load_data .end').attr('title'));
this.children(".loaded").fadeIn(1000);
}
});
$("#booklist .page:visible").hide();
elem.children(".loaded").hide();
elem.children(".loading").show();
elem.show();
}
function booklist(hide_sort) {
if (hide_sort) $("#content > .sort_select").hide();
var test = $("#booklist #page0").html();
if (!test) {
$("#booklist").html(render_error("No books found"));
return;
}
$("#book_details_dialog").dialog({
autoOpen: false,
modal: true,
show: 'slide'
});
first_page();
}
function show_details(a_dom) {
var book = $(a_dom).closest('div.summary');
var bd = $('#book_details_dialog');
bd.html('<span class="loading"><img src="/static/loading.gif" alt="Loading" />Loading, please wait&hellip;</span>');
bd.dialog('option', 'width', $(window).width() - 100);
bd.dialog('option', 'height', $(window).height() - 100);
bd.dialog('option', 'title', book.find('.title').text());
$.ajax({
url: book.find('.details-href').attr('title'),
context: bd,
dataType: "json",
timeout: 600000, //milliseconds (10 minutes)
error: function(xhr, stat, err) {
this.html(render_error(stat));
},
success: function(data) {
this.html(data);
}
});
bd.dialog('open');
}
// }}}

View File

@ -0,0 +1,10 @@
<div id="details_{id}" class="details">
<div class="left">
<img alt="Cover of {title}" src="/get/cover/{id}" />
</div>
<div class="right">
<div class="field formats">{formats}</div>
{fields}
{comments}
</div>
</div>

View File

@ -0,0 +1,19 @@
<div id="summary_{id}" class="summary">
<div class="left">
<img alt="Cover of {title}" src="/get/thumb_90_120/{id}" />
<a href="{href}" class="read" title="{read_tooltip}">{read_string}</a>
</div>
<div class="right">
<div class="stars">
<span class="rating_container">{stars}</span>
<span class="series">{series}</span>
<a href="#" onclick="show_details(this); return false;" title="{details_tt}">{details}</a>
</div>
<div class="title"><strong>{title}</strong></div>
<div class="authors">{authors}</div>
<div class="comments">{comments}</div>
<div class="tags">{tags}</div>
<div class="formats">{other_formats}</div>
</div>
<div class="details-href" title="{details_href}" style="display:none"></div>
</div>

View File

@ -15,7 +15,7 @@
</div> </div>
<div id="search_box"> <div id="search_box">
<form name="search_form" onsubmit="search();return false;" action="./" method="get"> <form name="search_form" onsubmit="search();return false;" action="./" method="get" accept-charset="UTF-8">
<input value="" id="s" type="text" /> <input value="" id="s" type="text" />
<input type="image" src="/static/btn_search_box.png" width="27" height="24" id="go" alt="Search" title="Search" /> <input type="image" src="/static/btn_search_box.png" width="27" height="24" id="go" alt="Search" title="Search" />
</form> </form>

Binary file not shown.

Before

Width:  |  Height:  |  Size: 157 B

After

Width:  |  Height:  |  Size: 123 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 125 B

After

Width:  |  Height:  |  Size: 161 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 141 B

After

Width:  |  Height:  |  Size: 113 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.2 KiB

After

Width:  |  Height:  |  Size: 4.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 4.3 KiB

After

Width:  |  Height:  |  Size: 5.2 KiB

View File

@ -50,13 +50,13 @@
* *
* http://docs.jquery.com/UI/Theming/API * http://docs.jquery.com/UI/Theming/API
* *
* To view and modify this theme, visit http://jqueryui.com/themeroller/?ffDefault=Verdana,Arial,sans-serif&fwDefault=normal&fsDefault=1em&cornerRadius=6px&bgColorHeader=cb842e&bgTextureHeader=02_glass.png&bgImgOpacityHeader=25&borderColorHeader=d49768&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=f4f0ec&bgTextureContent=05_inset_soft.png&bgImgOpacityContent=100&borderColorContent=e0cfc2&fcContent=1e1b1d&iconColorContent=c47a23&bgColorDefault=ede4d4&bgTextureDefault=02_glass.png&bgImgOpacityDefault=70&borderColorDefault=cdc3b7&fcDefault=3f3731&iconColorDefault=f08000&bgColorHover=f5f0e5&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=f5ad66&fcHover=a46313&iconColorHover=f08000&bgColorActive=f4f0ec&bgTextureActive=04_highlight_hard.png&bgImgOpacityActive=100&borderColorActive=e0cfc2&fcActive=b85700&iconColorActive=f35f07&bgColorHighlight=f5f5b5&bgTextureHighlight=04_highlight_hard.png&bgImgOpacityHighlight=75&borderColorHighlight=d9bb73&fcHighlight=060200&iconColorHighlight=cb672b&bgColorError=fee4bd&bgTextureError=04_highlight_hard.png&bgImgOpacityError=65&borderColorError=f8893f&fcError=592003&iconColorError=ff7519&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=75&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=75&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px * To view and modify this theme, visit http://jqueryui.com/themeroller/?tr=ffDefault=Helvetica,Arial,sans-serif&fwDefault=normal&fsDefault=1.1em&cornerRadius=6px&bgColorHeader=cb842e&bgTextureHeader=02_glass.png&bgImgOpacityHeader=25&borderColorHeader=d49768&fcHeader=ffffff&iconColorHeader=ffffff&bgColorContent=f4f0ec&bgTextureContent=05_inset_soft.png&bgImgOpacityContent=100&borderColorContent=e0cfc2&fcContent=1e1b1d&iconColorContent=c47a23&bgColorDefault=ede4d4&bgTextureDefault=02_glass.png&bgImgOpacityDefault=70&borderColorDefault=cdc3b7&fcDefault=3f3731&iconColorDefault=f08000&bgColorHover=f5f0e5&bgTextureHover=02_glass.png&bgImgOpacityHover=100&borderColorHover=f5ad66&fcHover=a46313&iconColorHover=f08000&bgColorActive=f4f0ec&bgTextureActive=04_highlight_hard.png&bgImgOpacityActive=100&borderColorActive=e0cfc2&fcActive=b85700&iconColorActive=f35f07&bgColorHighlight=f5f5b5&bgTextureHighlight=04_highlight_hard.png&bgImgOpacityHighlight=75&borderColorHighlight=d9bb73&fcHighlight=060200&iconColorHighlight=cb672b&bgColorError=fee4bd&bgTextureError=04_highlight_hard.png&bgImgOpacityError=65&borderColorError=f8893f&fcError=592003&iconColorError=ff7519&bgColorOverlay=aaaaaa&bgTextureOverlay=01_flat.png&bgImgOpacityOverlay=75&opacityOverlay=30&bgColorShadow=aaaaaa&bgTextureShadow=01_flat.png&bgImgOpacityShadow=75&opacityShadow=30&thicknessShadow=8px&offsetTopShadow=-8px&offsetLeftShadow=-8px&cornerRadiusShadow=8px
*/ */
/* Component containers /* Component containers
----------------------------------*/ ----------------------------------*/
.ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1em; } .ui-widget { font-family: Verdana,Arial,sans-serif; font-size: 1.1em; }
.ui-widget .ui-widget { font-size: 1em; } .ui-widget .ui-widget { font-size: 1em; }
.ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; } .ui-widget input, .ui-widget select, .ui-widget textarea, .ui-widget button { font-family: Verdana,Arial,sans-serif; font-size: 1em; }
.ui-widget-content { border: 1px solid #e0cfc2; background: #f4f0ec url(images/ui-bg_inset-soft_100_f4f0ec_1x100.png) 50% bottom repeat-x; color: #1e1b1d; } .ui-widget-content { border: 1px solid #e0cfc2; background: #f4f0ec url(images/ui-bg_inset-soft_100_f4f0ec_1x100.png) 50% bottom repeat-x; color: #1e1b1d; }
@ -293,6 +293,25 @@
/* Overlays */ /* Overlays */
.ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_75_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); } .ui-widget-overlay { background: #aaaaaa url(images/ui-bg_flat_75_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); }
.ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_75_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/* .ui-widget-shadow { margin: -8px 0 0 -8px; padding: 8px; background: #aaaaaa url(images/ui-bg_flat_75_aaaaaa_40x100.png) 50% 50% repeat-x; opacity: .30;filter:Alpha(Opacity=30); -moz-border-radius: 8px; -webkit-border-radius: 8px; border-radius: 8px; }/*
* jQuery UI Resizable @VERSION
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Resizable#theming
*/
.ui-resizable { position: relative;}
.ui-resizable-handle { position: absolute;font-size: 0.1px;z-index: 99999; display: block;}
.ui-resizable-disabled .ui-resizable-handle, .ui-resizable-autohide .ui-resizable-handle { display: none; }
.ui-resizable-n { cursor: n-resize; height: 7px; width: 100%; top: -5px; left: 0; }
.ui-resizable-s { cursor: s-resize; height: 7px; width: 100%; bottom: -5px; left: 0; }
.ui-resizable-e { cursor: e-resize; width: 7px; right: -5px; top: 0; height: 100%; }
.ui-resizable-w { cursor: w-resize; width: 7px; left: -5px; top: 0; height: 100%; }
.ui-resizable-se { cursor: se-resize; width: 12px; height: 12px; right: 1px; bottom: 1px; }
.ui-resizable-sw { cursor: sw-resize; width: 9px; height: 9px; left: -5px; bottom: -5px; }
.ui-resizable-nw { cursor: nw-resize; width: 9px; height: 9px; left: -5px; top: -5px; }
.ui-resizable-ne { cursor: ne-resize; width: 9px; height: 9px; right: -5px; top: -5px;}/*
* jQuery UI Accordion @VERSION * jQuery UI Accordion @VERSION
* *
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about) * Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
@ -348,3 +367,24 @@ input.ui-button { padding: .4em 1em; }
/* workarounds */ /* workarounds */
button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */ button.ui-button::-moz-focus-inner { border: 0; padding: 0; } /* reset extra padding in Firefox */
/*
* jQuery UI Dialog @VERSION
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Dialog#theming
*/
.ui-dialog { position: absolute; padding: .2em; width: 300px; overflow: hidden; }
.ui-dialog .ui-dialog-titlebar { padding: .5em 1em .3em; position: relative; }
.ui-dialog .ui-dialog-title { float: left; margin: .1em 16px .2em 0; }
.ui-dialog .ui-dialog-titlebar-close { position: absolute; right: .3em; top: 50%; width: 19px; margin: -10px 0 0 0; padding: 1px; height: 18px; }
.ui-dialog .ui-dialog-titlebar-close span { display: block; margin: 1px; }
.ui-dialog .ui-dialog-titlebar-close:hover, .ui-dialog .ui-dialog-titlebar-close:focus { padding: 0; }
.ui-dialog .ui-dialog-content { position: relative; border: 0; padding: .5em 1em; background: none; overflow: auto; zoom: 1; }
.ui-dialog .ui-dialog-buttonpane { text-align: left; border-width: 1px 0 0 0; background-image: none; margin: .5em 0 0 0; padding: .3em 1em .5em .4em; }
.ui-dialog .ui-dialog-buttonpane .ui-dialog-buttonset { float: right; }
.ui-dialog .ui-dialog-buttonpane button { margin: .5em .4em .5em 0; cursor: pointer; }
.ui-dialog .ui-resizable-se { width: 14px; height: 14px; right: 3px; bottom: 3px; }
.ui-draggable .ui-dialog-titlebar { cursor: move; }

View File

@ -63,6 +63,53 @@ a.pageX),Math.abs(this._mouseDownEvent.pageY-a.pageY))>=this.options.distance},_
b.left=d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0]; b.left=d>0?b.left-d:Math.max(b.left-a.collisionPosition.left,b.left)},top:function(b,a){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();b.top=d>0?b.top-d:Math.max(b.top-a.collisionPosition.top,b.top)}},flip:{left:function(b,a){if(a.at[0]!=="center"){var d=c(window);d=a.collisionPosition.left+a.collisionWidth-d.width()-d.scrollLeft();var g=a.my[0]==="left"?-a.elemWidth:a.my[0]==="right"?a.elemWidth:0,e=a.at[0]==="left"?a.targetWidth:-a.targetWidth,h=-2*a.offset[0];
b.left+=a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d= b.left+=a.collisionPosition.left<0?g+e+h:d>0?g+e+h:0}},top:function(b,a){if(a.at[1]!=="center"){var d=c(window);d=a.collisionPosition.top+a.collisionHeight-d.height()-d.scrollTop();var g=a.my[1]==="top"?-a.elemHeight:a.my[1]==="bottom"?a.elemHeight:0,e=a.at[1]==="top"?a.targetHeight:-a.targetHeight,h=-2*a.offset[1];b.top+=a.collisionPosition.top<0?g+e+h:d>0?g+e+h:0}}}};if(!c.offset.setOffset){c.offset.setOffset=function(b,a){if(/static/.test(c.curCSS(b,"position")))b.style.position="relative";var d=
c(b),g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery); c(b),g=d.offset(),e=parseInt(c.curCSS(b,"top",true),10)||0,h=parseInt(c.curCSS(b,"left",true),10)||0;g={top:a.top-g.top+e,left:a.left-g.left+h};"using"in a?a.using.call(b,g):d.css(g)};c.fn.offset=function(b){var a=this[0];if(!a||!a.ownerDocument)return null;if(b)return this.each(function(){c.offset.setOffset(this,b)});return u.call(this)}}})(jQuery);
;/*
* jQuery UI Resizable 1.8.5
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Resizables
*
* Depends:
* jquery.ui.core.js
* jquery.ui.mouse.js
* jquery.ui.widget.js
*/
(function(e){e.widget("ui.resizable",e.ui.mouse,{widgetEventPrefix:"resize",options:{alsoResize:false,animate:false,animateDuration:"slow",animateEasing:"swing",aspectRatio:false,autoHide:false,containment:false,ghost:false,grid:false,handles:"e,s,se",helper:false,maxHeight:null,maxWidth:null,minHeight:10,minWidth:10,zIndex:1E3},_create:function(){var b=this,a=this.options;this.element.addClass("ui-resizable");e.extend(this,{_aspectRatio:!!a.aspectRatio,aspectRatio:a.aspectRatio,originalElement:this.element,
_proportionallyResizeElements:[],_helper:a.helper||a.ghost||a.animate?a.helper||"ui-resizable-helper":null});if(this.element[0].nodeName.match(/canvas|textarea|input|select|button|img/i)){/relative/.test(this.element.css("position"))&&e.browser.opera&&this.element.css({position:"relative",top:"auto",left:"auto"});this.element.wrap(e('<div class="ui-wrapper" style="overflow: hidden;"></div>').css({position:this.element.css("position"),width:this.element.outerWidth(),height:this.element.outerHeight(),
top:this.element.css("top"),left:this.element.css("left")}));this.element=this.element.parent().data("resizable",this.element.data("resizable"));this.elementIsWrapper=true;this.element.css({marginLeft:this.originalElement.css("marginLeft"),marginTop:this.originalElement.css("marginTop"),marginRight:this.originalElement.css("marginRight"),marginBottom:this.originalElement.css("marginBottom")});this.originalElement.css({marginLeft:0,marginTop:0,marginRight:0,marginBottom:0});this.originalResizeStyle=
this.originalElement.css("resize");this.originalElement.css("resize","none");this._proportionallyResizeElements.push(this.originalElement.css({position:"static",zoom:1,display:"block"}));this.originalElement.css({margin:this.originalElement.css("margin")});this._proportionallyResize()}this.handles=a.handles||(!e(".ui-resizable-handle",this.element).length?"e,s,se":{n:".ui-resizable-n",e:".ui-resizable-e",s:".ui-resizable-s",w:".ui-resizable-w",se:".ui-resizable-se",sw:".ui-resizable-sw",ne:".ui-resizable-ne",
nw:".ui-resizable-nw"});if(this.handles.constructor==String){if(this.handles=="all")this.handles="n,e,s,w,se,sw,ne,nw";var c=this.handles.split(",");this.handles={};for(var d=0;d<c.length;d++){var f=e.trim(c[d]),g=e('<div class="ui-resizable-handle '+("ui-resizable-"+f)+'"></div>');/sw|se|ne|nw/.test(f)&&g.css({zIndex:++a.zIndex});"se"==f&&g.addClass("ui-icon ui-icon-gripsmall-diagonal-se");this.handles[f]=".ui-resizable-"+f;this.element.append(g)}}this._renderAxis=function(h){h=h||this.element;for(var i in this.handles){if(this.handles[i].constructor==
String)this.handles[i]=e(this.handles[i],this.element).show();if(this.elementIsWrapper&&this.originalElement[0].nodeName.match(/textarea|input|select|button/i)){var j=e(this.handles[i],this.element),k=0;k=/sw|ne|nw|se|n|s/.test(i)?j.outerHeight():j.outerWidth();j=["padding",/ne|nw|n/.test(i)?"Top":/se|sw|s/.test(i)?"Bottom":/^e$/.test(i)?"Right":"Left"].join("");h.css(j,k);this._proportionallyResize()}e(this.handles[i])}};this._renderAxis(this.element);this._handles=e(".ui-resizable-handle",this.element).disableSelection();
this._handles.mouseover(function(){if(!b.resizing){if(this.className)var h=this.className.match(/ui-resizable-(se|sw|ne|nw|n|e|s|w)/i);b.axis=h&&h[1]?h[1]:"se"}});if(a.autoHide){this._handles.hide();e(this.element).addClass("ui-resizable-autohide").hover(function(){e(this).removeClass("ui-resizable-autohide");b._handles.show()},function(){if(!b.resizing){e(this).addClass("ui-resizable-autohide");b._handles.hide()}})}this._mouseInit()},destroy:function(){this._mouseDestroy();var b=function(c){e(c).removeClass("ui-resizable ui-resizable-disabled ui-resizable-resizing").removeData("resizable").unbind(".resizable").find(".ui-resizable-handle").remove()};
if(this.elementIsWrapper){b(this.element);var a=this.element;a.after(this.originalElement.css({position:a.css("position"),width:a.outerWidth(),height:a.outerHeight(),top:a.css("top"),left:a.css("left")})).remove()}this.originalElement.css("resize",this.originalResizeStyle);b(this.originalElement);return this},_mouseCapture:function(b){var a=false;for(var c in this.handles)if(e(this.handles[c])[0]==b.target)a=true;return!this.options.disabled&&a},_mouseStart:function(b){var a=this.options,c=this.element.position(),
d=this.element;this.resizing=true;this.documentScroll={top:e(document).scrollTop(),left:e(document).scrollLeft()};if(d.is(".ui-draggable")||/absolute/.test(d.css("position")))d.css({position:"absolute",top:c.top,left:c.left});e.browser.opera&&/relative/.test(d.css("position"))&&d.css({position:"relative",top:"auto",left:"auto"});this._renderProxy();c=m(this.helper.css("left"));var f=m(this.helper.css("top"));if(a.containment){c+=e(a.containment).scrollLeft()||0;f+=e(a.containment).scrollTop()||0}this.offset=
this.helper.offset();this.position={left:c,top:f};this.size=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalSize=this._helper?{width:d.outerWidth(),height:d.outerHeight()}:{width:d.width(),height:d.height()};this.originalPosition={left:c,top:f};this.sizeDiff={width:d.outerWidth()-d.width(),height:d.outerHeight()-d.height()};this.originalMousePosition={left:b.pageX,top:b.pageY};this.aspectRatio=typeof a.aspectRatio=="number"?a.aspectRatio:
this.originalSize.width/this.originalSize.height||1;a=e(".ui-resizable-"+this.axis).css("cursor");e("body").css("cursor",a=="auto"?this.axis+"-resize":a);d.addClass("ui-resizable-resizing");this._propagate("start",b);return true},_mouseDrag:function(b){var a=this.helper,c=this.originalMousePosition,d=this._change[this.axis];if(!d)return false;c=d.apply(this,[b,b.pageX-c.left||0,b.pageY-c.top||0]);if(this._aspectRatio||b.shiftKey)c=this._updateRatio(c,b);c=this._respectSize(c,b);this._propagate("resize",
b);a.css({top:this.position.top+"px",left:this.position.left+"px",width:this.size.width+"px",height:this.size.height+"px"});!this._helper&&this._proportionallyResizeElements.length&&this._proportionallyResize();this._updateCache(c);this._trigger("resize",b,this.ui());return false},_mouseStop:function(b){this.resizing=false;var a=this.options,c=this;if(this._helper){var d=this._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName);d=f&&e.ui.hasScroll(d[0],"left")?0:c.sizeDiff.height;
f={width:c.size.width-(f?0:c.sizeDiff.width),height:c.size.height-d};d=parseInt(c.element.css("left"),10)+(c.position.left-c.originalPosition.left)||null;var g=parseInt(c.element.css("top"),10)+(c.position.top-c.originalPosition.top)||null;a.animate||this.element.css(e.extend(f,{top:g,left:d}));c.helper.height(c.size.height);c.helper.width(c.size.width);this._helper&&!a.animate&&this._proportionallyResize()}e("body").css("cursor","auto");this.element.removeClass("ui-resizable-resizing");this._propagate("stop",
b);this._helper&&this.helper.remove();return false},_updateCache:function(b){this.offset=this.helper.offset();if(l(b.left))this.position.left=b.left;if(l(b.top))this.position.top=b.top;if(l(b.height))this.size.height=b.height;if(l(b.width))this.size.width=b.width},_updateRatio:function(b){var a=this.position,c=this.size,d=this.axis;if(b.height)b.width=c.height*this.aspectRatio;else if(b.width)b.height=c.width/this.aspectRatio;if(d=="sw"){b.left=a.left+(c.width-b.width);b.top=null}if(d=="nw"){b.top=
a.top+(c.height-b.height);b.left=a.left+(c.width-b.width)}return b},_respectSize:function(b){var a=this.options,c=this.axis,d=l(b.width)&&a.maxWidth&&a.maxWidth<b.width,f=l(b.height)&&a.maxHeight&&a.maxHeight<b.height,g=l(b.width)&&a.minWidth&&a.minWidth>b.width,h=l(b.height)&&a.minHeight&&a.minHeight>b.height;if(g)b.width=a.minWidth;if(h)b.height=a.minHeight;if(d)b.width=a.maxWidth;if(f)b.height=a.maxHeight;var i=this.originalPosition.left+this.originalSize.width,j=this.position.top+this.size.height,
k=/sw|nw|w/.test(c);c=/nw|ne|n/.test(c);if(g&&k)b.left=i-a.minWidth;if(d&&k)b.left=i-a.maxWidth;if(h&&c)b.top=j-a.minHeight;if(f&&c)b.top=j-a.maxHeight;if((a=!b.width&&!b.height)&&!b.left&&b.top)b.top=null;else if(a&&!b.top&&b.left)b.left=null;return b},_proportionallyResize:function(){if(this._proportionallyResizeElements.length)for(var b=this.helper||this.element,a=0;a<this._proportionallyResizeElements.length;a++){var c=this._proportionallyResizeElements[a];if(!this.borderDif){var d=[c.css("borderTopWidth"),
c.css("borderRightWidth"),c.css("borderBottomWidth"),c.css("borderLeftWidth")],f=[c.css("paddingTop"),c.css("paddingRight"),c.css("paddingBottom"),c.css("paddingLeft")];this.borderDif=e.map(d,function(g,h){g=parseInt(g,10)||0;h=parseInt(f[h],10)||0;return g+h})}e.browser.msie&&(e(b).is(":hidden")||e(b).parents(":hidden").length)||c.css({height:b.height()-this.borderDif[0]-this.borderDif[2]||0,width:b.width()-this.borderDif[1]-this.borderDif[3]||0})}},_renderProxy:function(){var b=this.options;this.elementOffset=
this.element.offset();if(this._helper){this.helper=this.helper||e('<div style="overflow:hidden;"></div>');var a=e.browser.msie&&e.browser.version<7,c=a?1:0;a=a?2:-1;this.helper.addClass(this._helper).css({width:this.element.outerWidth()+a,height:this.element.outerHeight()+a,position:"absolute",left:this.elementOffset.left-c+"px",top:this.elementOffset.top-c+"px",zIndex:++b.zIndex});this.helper.appendTo("body").disableSelection()}else this.helper=this.element},_change:{e:function(b,a){return{width:this.originalSize.width+
a}},w:function(b,a){return{left:this.originalPosition.left+a,width:this.originalSize.width-a}},n:function(b,a,c){return{top:this.originalPosition.top+c,height:this.originalSize.height-c}},s:function(b,a,c){return{height:this.originalSize.height+c}},se:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.e.apply(this,[b,a,c]))},sw:function(b,a,c){return e.extend(this._change.s.apply(this,arguments),this._change.w.apply(this,[b,a,c]))},ne:function(b,a,c){return e.extend(this._change.n.apply(this,
arguments),this._change.e.apply(this,[b,a,c]))},nw:function(b,a,c){return e.extend(this._change.n.apply(this,arguments),this._change.w.apply(this,[b,a,c]))}},_propagate:function(b,a){e.ui.plugin.call(this,b,[a,this.ui()]);b!="resize"&&this._trigger(b,a,this.ui())},plugins:{},ui:function(){return{originalElement:this.originalElement,element:this.element,helper:this.helper,position:this.position,size:this.size,originalSize:this.originalSize,originalPosition:this.originalPosition}}});e.extend(e.ui.resizable,
{version:"1.8.5"});e.ui.plugin.add("resizable","alsoResize",{start:function(){var b=e(this).data("resizable").options,a=function(c){e(c).each(function(){var d=e(this);d.data("resizable-alsoresize",{width:parseInt(d.width(),10),height:parseInt(d.height(),10),left:parseInt(d.css("left"),10),top:parseInt(d.css("top"),10),position:d.css("position")})})};if(typeof b.alsoResize=="object"&&!b.alsoResize.parentNode)if(b.alsoResize.length){b.alsoResize=b.alsoResize[0];a(b.alsoResize)}else e.each(b.alsoResize,
function(c){a(c)});else a(b.alsoResize)},resize:function(b,a){var c=e(this).data("resizable");b=c.options;var d=c.originalSize,f=c.originalPosition,g={height:c.size.height-d.height||0,width:c.size.width-d.width||0,top:c.position.top-f.top||0,left:c.position.left-f.left||0},h=function(i,j){e(i).each(function(){var k=e(this),q=e(this).data("resizable-alsoresize"),p={},r=j&&j.length?j:k.parents(a.originalElement[0]).length?["width","height"]:["width","height","top","left"];e.each(r,function(n,o){if((n=
(q[o]||0)+(g[o]||0))&&n>=0)p[o]=n||null});if(e.browser.opera&&/relative/.test(k.css("position"))){c._revertToRelativePosition=true;k.css({position:"absolute",top:"auto",left:"auto"})}k.css(p)})};typeof b.alsoResize=="object"&&!b.alsoResize.nodeType?e.each(b.alsoResize,function(i,j){h(i,j)}):h(b.alsoResize)},stop:function(){var b=e(this).data("resizable"),a=b.options,c=function(d){e(d).each(function(){var f=e(this);f.css({position:f.data("resizable-alsoresize").position})})};if(b._revertToRelativePosition){b._revertToRelativePosition=
false;typeof a.alsoResize=="object"&&!a.alsoResize.nodeType?e.each(a.alsoResize,function(d){c(d)}):c(a.alsoResize)}e(this).removeData("resizable-alsoresize")}});e.ui.plugin.add("resizable","animate",{stop:function(b){var a=e(this).data("resizable"),c=a.options,d=a._proportionallyResizeElements,f=d.length&&/textarea/i.test(d[0].nodeName),g=f&&e.ui.hasScroll(d[0],"left")?0:a.sizeDiff.height;f={width:a.size.width-(f?0:a.sizeDiff.width),height:a.size.height-g};g=parseInt(a.element.css("left"),10)+(a.position.left-
a.originalPosition.left)||null;var h=parseInt(a.element.css("top"),10)+(a.position.top-a.originalPosition.top)||null;a.element.animate(e.extend(f,h&&g?{top:h,left:g}:{}),{duration:c.animateDuration,easing:c.animateEasing,step:function(){var i={width:parseInt(a.element.css("width"),10),height:parseInt(a.element.css("height"),10),top:parseInt(a.element.css("top"),10),left:parseInt(a.element.css("left"),10)};d&&d.length&&e(d[0]).css({width:i.width,height:i.height});a._updateCache(i);a._propagate("resize",
b)}})}});e.ui.plugin.add("resizable","containment",{start:function(){var b=e(this).data("resizable"),a=b.element,c=b.options.containment;if(a=c instanceof e?c.get(0):/parent/.test(c)?a.parent().get(0):c){b.containerElement=e(a);if(/document/.test(c)||c==document){b.containerOffset={left:0,top:0};b.containerPosition={left:0,top:0};b.parentData={element:e(document),left:0,top:0,width:e(document).width(),height:e(document).height()||document.body.parentNode.scrollHeight}}else{var d=e(a),f=[];e(["Top",
"Right","Left","Bottom"]).each(function(i,j){f[i]=m(d.css("padding"+j))});b.containerOffset=d.offset();b.containerPosition=d.position();b.containerSize={height:d.innerHeight()-f[3],width:d.innerWidth()-f[1]};c=b.containerOffset;var g=b.containerSize.height,h=b.containerSize.width;h=e.ui.hasScroll(a,"left")?a.scrollWidth:h;g=e.ui.hasScroll(a)?a.scrollHeight:g;b.parentData={element:a,left:c.left,top:c.top,width:h,height:g}}}},resize:function(b){var a=e(this).data("resizable"),c=a.options,d=a.containerOffset,
f=a.position;b=a._aspectRatio||b.shiftKey;var g={top:0,left:0},h=a.containerElement;if(h[0]!=document&&/static/.test(h.css("position")))g=d;if(f.left<(a._helper?d.left:0)){a.size.width+=a._helper?a.position.left-d.left:a.position.left-g.left;if(b)a.size.height=a.size.width/c.aspectRatio;a.position.left=c.helper?d.left:0}if(f.top<(a._helper?d.top:0)){a.size.height+=a._helper?a.position.top-d.top:a.position.top;if(b)a.size.width=a.size.height*c.aspectRatio;a.position.top=a._helper?d.top:0}a.offset.left=
a.parentData.left+a.position.left;a.offset.top=a.parentData.top+a.position.top;c=Math.abs((a._helper?a.offset.left-g.left:a.offset.left-g.left)+a.sizeDiff.width);d=Math.abs((a._helper?a.offset.top-g.top:a.offset.top-d.top)+a.sizeDiff.height);f=a.containerElement.get(0)==a.element.parent().get(0);g=/relative|absolute/.test(a.containerElement.css("position"));if(f&&g)c-=a.parentData.left;if(c+a.size.width>=a.parentData.width){a.size.width=a.parentData.width-c;if(b)a.size.height=a.size.width/a.aspectRatio}if(d+
a.size.height>=a.parentData.height){a.size.height=a.parentData.height-d;if(b)a.size.width=a.size.height*a.aspectRatio}},stop:function(){var b=e(this).data("resizable"),a=b.options,c=b.containerOffset,d=b.containerPosition,f=b.containerElement,g=e(b.helper),h=g.offset(),i=g.outerWidth()-b.sizeDiff.width;g=g.outerHeight()-b.sizeDiff.height;b._helper&&!a.animate&&/relative/.test(f.css("position"))&&e(this).css({left:h.left-d.left-c.left,width:i,height:g});b._helper&&!a.animate&&/static/.test(f.css("position"))&&
e(this).css({left:h.left-d.left-c.left,width:i,height:g})}});e.ui.plugin.add("resizable","ghost",{start:function(){var b=e(this).data("resizable"),a=b.options,c=b.size;b.ghost=b.originalElement.clone();b.ghost.css({opacity:0.25,display:"block",position:"relative",height:c.height,width:c.width,margin:0,left:0,top:0}).addClass("ui-resizable-ghost").addClass(typeof a.ghost=="string"?a.ghost:"");b.ghost.appendTo(b.helper)},resize:function(){var b=e(this).data("resizable");b.ghost&&b.ghost.css({position:"relative",
height:b.size.height,width:b.size.width})},stop:function(){var b=e(this).data("resizable");b.ghost&&b.helper&&b.helper.get(0).removeChild(b.ghost.get(0))}});e.ui.plugin.add("resizable","grid",{resize:function(){var b=e(this).data("resizable"),a=b.options,c=b.size,d=b.originalSize,f=b.originalPosition,g=b.axis;a.grid=typeof a.grid=="number"?[a.grid,a.grid]:a.grid;var h=Math.round((c.width-d.width)/(a.grid[0]||1))*(a.grid[0]||1);a=Math.round((c.height-d.height)/(a.grid[1]||1))*(a.grid[1]||1);if(/^(se|s|e)$/.test(g)){b.size.width=
d.width+h;b.size.height=d.height+a}else if(/^(ne)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}else{if(/^(sw)$/.test(g)){b.size.width=d.width+h;b.size.height=d.height+a}else{b.size.width=d.width+h;b.size.height=d.height+a;b.position.top=f.top-a}b.position.left=f.left-h}}});var m=function(b){return parseInt(b,10)||0},l=function(b){return!isNaN(parseInt(b,10))}})(jQuery);
;/* ;/*
* jQuery UI Accordion 1.8.5 * jQuery UI Accordion 1.8.5
* *
@ -118,6 +165,45 @@ true):a(this).button("widget").removeClass("ui-state-active").attr("aria-pressed
c=a("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary;if(d.primary||d.secondary){b.addClass("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary"));d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>");d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>");if(!this.options.text){b.addClass(e?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary"); c=a("<span></span>").addClass("ui-button-text").html(this.options.label).appendTo(b.empty()).text(),d=this.options.icons,e=d.primary&&d.secondary;if(d.primary||d.secondary){b.addClass("ui-button-text-icon"+(e?"s":d.primary?"-primary":"-secondary"));d.primary&&b.prepend("<span class='ui-button-icon-primary ui-icon "+d.primary+"'></span>");d.secondary&&b.append("<span class='ui-button-icon-secondary ui-icon "+d.secondary+"'></span>");if(!this.options.text){b.addClass(e?"ui-button-icons-only":"ui-button-icon-only").removeClass("ui-button-text-icons ui-button-text-icon-primary ui-button-text-icon-secondary");
this.hasTitle||b.attr("title",c)}}else b.addClass("ui-button-text-only")}}});a.widget("ui.buttonset",{_create:function(){this.element.addClass("ui-buttonset");this._init()},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(":button, :submit, :reset, :checkbox, :radio, a, :data(button)").filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":visible").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end().end()}, this.hasTitle||b.attr("title",c)}}else b.addClass("ui-button-text-only")}}});a.widget("ui.buttonset",{_create:function(){this.element.addClass("ui-buttonset");this._init()},_init:function(){this.refresh()},_setOption:function(b,c){b==="disabled"&&this.buttons.button("option",b,c);a.Widget.prototype._setOption.apply(this,arguments)},refresh:function(){this.buttons=this.element.find(":button, :submit, :reset, :checkbox, :radio, a, :data(button)").filter(":ui-button").button("refresh").end().not(":ui-button").button().end().map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-all ui-corner-left ui-corner-right").filter(":visible").filter(":first").addClass("ui-corner-left").end().filter(":last").addClass("ui-corner-right").end().end().end()},
destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery); destroy:function(){this.element.removeClass("ui-buttonset");this.buttons.map(function(){return a(this).button("widget")[0]}).removeClass("ui-corner-left ui-corner-right").end().button("destroy");a.Widget.prototype.destroy.call(this)}})})(jQuery);
;/*
* jQuery UI Dialog 1.8.5
*
* Copyright 2010, AUTHORS.txt (http://jqueryui.com/about)
* Dual licensed under the MIT or GPL Version 2 licenses.
* http://jquery.org/license
*
* http://docs.jquery.com/UI/Dialog
*
* Depends:
* jquery.ui.core.js
* jquery.ui.widget.js
* jquery.ui.button.js
* jquery.ui.draggable.js
* jquery.ui.mouse.js
* jquery.ui.position.js
* jquery.ui.resizable.js
*/
(function(c,j){c.widget("ui.dialog",{options:{autoOpen:true,buttons:{},closeOnEscape:true,closeText:"close",dialogClass:"",draggable:true,hide:null,height:"auto",maxHeight:false,maxWidth:false,minHeight:150,minWidth:150,modal:false,position:{my:"center",at:"center",of:window,collision:"fit",using:function(a){var b=c(this).css(a).offset().top;b<0&&c(this).css("top",a.top-b)}},resizable:true,show:null,stack:true,title:"",width:300,zIndex:1E3},_create:function(){this.originalTitle=this.element.attr("title");
if(typeof this.originalTitle!=="string")this.originalTitle="";this.options.title=this.options.title||this.originalTitle;var a=this,b=a.options,d=b.title||"&#160;",f=c.ui.dialog.getTitleId(a.element),g=(a.uiDialog=c("<div></div>")).appendTo(document.body).hide().addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b.dialogClass).css({zIndex:b.zIndex}).attr("tabIndex",-1).css("outline",0).keydown(function(i){if(b.closeOnEscape&&i.keyCode&&i.keyCode===c.ui.keyCode.ESCAPE){a.close(i);i.preventDefault()}}).attr({role:"dialog",
"aria-labelledby":f}).mousedown(function(i){a.moveToTop(false,i)});a.element.show().removeAttr("title").addClass("ui-dialog-content ui-widget-content").appendTo(g);var e=(a.uiDialogTitlebar=c("<div></div>")).addClass("ui-dialog-titlebar ui-widget-header ui-corner-all ui-helper-clearfix").prependTo(g),h=c('<a href="#"></a>').addClass("ui-dialog-titlebar-close ui-corner-all").attr("role","button").hover(function(){h.addClass("ui-state-hover")},function(){h.removeClass("ui-state-hover")}).focus(function(){h.addClass("ui-state-focus")}).blur(function(){h.removeClass("ui-state-focus")}).click(function(i){a.close(i);
return false}).appendTo(e);(a.uiDialogTitlebarCloseText=c("<span></span>")).addClass("ui-icon ui-icon-closethick").text(b.closeText).appendTo(h);c("<span></span>").addClass("ui-dialog-title").attr("id",f).html(d).prependTo(e);if(c.isFunction(b.beforeclose)&&!c.isFunction(b.beforeClose))b.beforeClose=b.beforeclose;e.find("*").add(e).disableSelection();b.draggable&&c.fn.draggable&&a._makeDraggable();b.resizable&&c.fn.resizable&&a._makeResizable();a._createButtons(b.buttons);a._isOpen=false;c.fn.bgiframe&&
g.bgiframe()},_init:function(){this.options.autoOpen&&this.open()},destroy:function(){var a=this;a.overlay&&a.overlay.destroy();a.uiDialog.hide();a.element.unbind(".dialog").removeData("dialog").removeClass("ui-dialog-content ui-widget-content").hide().appendTo("body");a.uiDialog.remove();a.originalTitle&&a.element.attr("title",a.originalTitle);return a},widget:function(){return this.uiDialog},close:function(a){var b=this,d;if(false!==b._trigger("beforeClose",a)){b.overlay&&b.overlay.destroy();b.uiDialog.unbind("keypress.ui-dialog");
b._isOpen=false;if(b.options.hide)b.uiDialog.hide(b.options.hide,function(){b._trigger("close",a)});else{b.uiDialog.hide();b._trigger("close",a)}c.ui.dialog.overlay.resize();if(b.options.modal){d=0;c(".ui-dialog").each(function(){if(this!==b.uiDialog[0])d=Math.max(d,c(this).css("z-index"))});c.ui.dialog.maxZ=d}return b}},isOpen:function(){return this._isOpen},moveToTop:function(a,b){var d=this,f=d.options;if(f.modal&&!a||!f.stack&&!f.modal)return d._trigger("focus",b);if(f.zIndex>c.ui.dialog.maxZ)c.ui.dialog.maxZ=
f.zIndex;if(d.overlay){c.ui.dialog.maxZ+=1;d.overlay.$el.css("z-index",c.ui.dialog.overlay.maxZ=c.ui.dialog.maxZ)}a={scrollTop:d.element.attr("scrollTop"),scrollLeft:d.element.attr("scrollLeft")};c.ui.dialog.maxZ+=1;d.uiDialog.css("z-index",c.ui.dialog.maxZ);d.element.attr(a);d._trigger("focus",b);return d},open:function(){if(!this._isOpen){var a=this,b=a.options,d=a.uiDialog;a.overlay=b.modal?new c.ui.dialog.overlay(a):null;d.next().length&&d.appendTo("body");a._size();a._position(b.position);d.show(b.show);
a.moveToTop(true);b.modal&&d.bind("keypress.ui-dialog",function(f){if(f.keyCode===c.ui.keyCode.TAB){var g=c(":tabbable",this),e=g.filter(":first");g=g.filter(":last");if(f.target===g[0]&&!f.shiftKey){e.focus(1);return false}else if(f.target===e[0]&&f.shiftKey){g.focus(1);return false}}});c(a.element.find(":tabbable").get().concat(d.find(".ui-dialog-buttonpane :tabbable").get().concat(d.get()))).eq(0).focus();a._isOpen=true;a._trigger("open");return a}},_createButtons:function(a){var b=this,d=false,
f=c("<div></div>").addClass("ui-dialog-buttonpane ui-widget-content ui-helper-clearfix"),g=c("<div></div>").addClass("ui-dialog-buttonset").appendTo(f);b.uiDialog.find(".ui-dialog-buttonpane").remove();typeof a==="object"&&a!==null&&c.each(a,function(){return!(d=true)});if(d){c.each(a,function(e,h){h=c.isFunction(h)?{click:h,text:e}:h;e=c("<button></button>",h).unbind("click").click(function(){h.click.apply(b.element[0],arguments)}).appendTo(g);c.fn.button&&e.button()});f.appendTo(b.uiDialog)}},_makeDraggable:function(){function a(e){return{position:e.position,
offset:e.offset}}var b=this,d=b.options,f=c(document),g;b.uiDialog.draggable({cancel:".ui-dialog-content, .ui-dialog-titlebar-close",handle:".ui-dialog-titlebar",containment:"document",start:function(e,h){g=d.height==="auto"?"auto":c(this).height();c(this).height(c(this).height()).addClass("ui-dialog-dragging");b._trigger("dragStart",e,a(h))},drag:function(e,h){b._trigger("drag",e,a(h))},stop:function(e,h){d.position=[h.position.left-f.scrollLeft(),h.position.top-f.scrollTop()];c(this).removeClass("ui-dialog-dragging").height(g);
b._trigger("dragStop",e,a(h));c.ui.dialog.overlay.resize()}})},_makeResizable:function(a){function b(e){return{originalPosition:e.originalPosition,originalSize:e.originalSize,position:e.position,size:e.size}}a=a===j?this.options.resizable:a;var d=this,f=d.options,g=d.uiDialog.css("position");a=typeof a==="string"?a:"n,e,s,w,se,sw,ne,nw";d.uiDialog.resizable({cancel:".ui-dialog-content",containment:"document",alsoResize:d.element,maxWidth:f.maxWidth,maxHeight:f.maxHeight,minWidth:f.minWidth,minHeight:d._minHeight(),
handles:a,start:function(e,h){c(this).addClass("ui-dialog-resizing");d._trigger("resizeStart",e,b(h))},resize:function(e,h){d._trigger("resize",e,b(h))},stop:function(e,h){c(this).removeClass("ui-dialog-resizing");f.height=c(this).height();f.width=c(this).width();d._trigger("resizeStop",e,b(h));c.ui.dialog.overlay.resize()}}).css("position",g).find(".ui-resizable-se").addClass("ui-icon ui-icon-grip-diagonal-se")},_minHeight:function(){var a=this.options;return a.height==="auto"?a.minHeight:Math.min(a.minHeight,
a.height)},_position:function(a){var b=[],d=[0,0],f;if(a){if(typeof a==="string"||typeof a==="object"&&"0"in a){b=a.split?a.split(" "):[a[0],a[1]];if(b.length===1)b[1]=b[0];c.each(["left","top"],function(g,e){if(+b[g]===b[g]){d[g]=b[g];b[g]=e}});a={my:b.join(" "),at:b.join(" "),offset:d.join(" ")}}a=c.extend({},c.ui.dialog.prototype.options.position,a)}else a=c.ui.dialog.prototype.options.position;(f=this.uiDialog.is(":visible"))||this.uiDialog.show();this.uiDialog.css({top:0,left:0}).position(a);
f||this.uiDialog.hide()},_setOption:function(a,b){var d=this,f=d.uiDialog,g=f.is(":data(resizable)"),e=false;switch(a){case "beforeclose":a="beforeClose";break;case "buttons":d._createButtons(b);e=true;break;case "closeText":d.uiDialogTitlebarCloseText.text(""+b);break;case "dialogClass":f.removeClass(d.options.dialogClass).addClass("ui-dialog ui-widget ui-widget-content ui-corner-all "+b);break;case "disabled":b?f.addClass("ui-dialog-disabled"):f.removeClass("ui-dialog-disabled");break;case "draggable":b?
d._makeDraggable():f.draggable("destroy");break;case "height":e=true;break;case "maxHeight":g&&f.resizable("option","maxHeight",b);e=true;break;case "maxWidth":g&&f.resizable("option","maxWidth",b);e=true;break;case "minHeight":g&&f.resizable("option","minHeight",b);e=true;break;case "minWidth":g&&f.resizable("option","minWidth",b);e=true;break;case "position":d._position(b);break;case "resizable":g&&!b&&f.resizable("destroy");g&&typeof b==="string"&&f.resizable("option","handles",b);!g&&b!==false&&
d._makeResizable(b);break;case "title":c(".ui-dialog-title",d.uiDialogTitlebar).html(""+(b||"&#160;"));break;case "width":e=true;break}c.Widget.prototype._setOption.apply(d,arguments);e&&d._size()},_size:function(){var a=this.options,b;this.element.css({width:"auto",minHeight:0,height:0});if(a.minWidth>a.width)a.width=a.minWidth;b=this.uiDialog.css({height:"auto",width:a.width}).height();this.element.css(a.height==="auto"?{minHeight:Math.max(a.minHeight-b,0),height:c.support.minHeight?"auto":Math.max(a.minHeight-
b,0)}:{minHeight:0,height:Math.max(a.height-b,0)}).show();this.uiDialog.is(":data(resizable)")&&this.uiDialog.resizable("option","minHeight",this._minHeight())}});c.extend(c.ui.dialog,{version:"1.8.5",uuid:0,maxZ:0,getTitleId:function(a){a=a.attr("id");if(!a){this.uuid+=1;a=this.uuid}return"ui-dialog-title-"+a},overlay:function(a){this.$el=c.ui.dialog.overlay.create(a)}});c.extend(c.ui.dialog.overlay,{instances:[],oldInstances:[],maxZ:0,events:c.map("focus,mousedown,mouseup,keydown,keypress,click".split(","),
function(a){return a+".dialog-overlay"}).join(" "),create:function(a){if(this.instances.length===0){setTimeout(function(){c.ui.dialog.overlay.instances.length&&c(document).bind(c.ui.dialog.overlay.events,function(d){if(c(d.target).zIndex()<c.ui.dialog.overlay.maxZ)return false})},1);c(document).bind("keydown.dialog-overlay",function(d){if(a.options.closeOnEscape&&d.keyCode&&d.keyCode===c.ui.keyCode.ESCAPE){a.close(d);d.preventDefault()}});c(window).bind("resize.dialog-overlay",c.ui.dialog.overlay.resize)}var b=
(this.oldInstances.pop()||c("<div></div>").addClass("ui-widget-overlay")).appendTo(document.body).css({width:this.width(),height:this.height()});c.fn.bgiframe&&b.bgiframe();this.instances.push(b);return b},destroy:function(a){this.oldInstances.push(this.instances.splice(c.inArray(a,this.instances),1)[0]);this.instances.length===0&&c([document,window]).unbind(".dialog-overlay");a.remove();var b=0;c.each(this.instances,function(){b=Math.max(b,this.css("z-index"))});this.maxZ=b},height:function(){var a,
b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollHeight,document.body.scrollHeight);b=Math.max(document.documentElement.offsetHeight,document.body.offsetHeight);return a<b?c(window).height()+"px":a+"px"}else return c(document).height()+"px"},width:function(){var a,b;if(c.browser.msie&&c.browser.version<7){a=Math.max(document.documentElement.scrollWidth,document.body.scrollWidth);b=Math.max(document.documentElement.offsetWidth,document.body.offsetWidth);return a<
b?c(window).width()+"px":a+"px"}else return c(document).width()+"px"},resize:function(){var a=c([]);c.each(c.ui.dialog.overlay.instances,function(){a=a.add(this)});a.css({width:0,height:0}).css({width:c.ui.dialog.overlay.width(),height:c.ui.dialog.overlay.height()})}});c.extend(c.ui.dialog.overlay.prototype,{destroy:function(){c.ui.dialog.overlay.destroy(this.$el)}})})(jQuery);
;/* ;/*
* jQuery UI Effects 1.8.5 * jQuery UI Effects 1.8.5
* *

Binary file not shown.

After

Width:  |  Height:  |  Size: 684 B

View File

@ -26,31 +26,12 @@ class GlobeAndMail(BasicNewsRecipe):
#credit {margin-top:0px;} #credit {margin-top:0px;}
.tag {font-size: 22pt;}''' .tag {font-size: 22pt;}'''
description = 'Canada\'s national newspaper' description = 'Canada\'s national newspaper'
remove_tags_before = dict(id="article-top") keep_only_tags = [dict(name='article')]
remove_tags = [ remove_tags = [dict(name='aside'),
{'id':['util', 'article-tabs', 'comments', 'article-relations', dict(name='footer'),
'gallery-controls', 'video', 'galleryLoading','deck','header', dict(name='div', attrs={'class':(lambda x: isinstance(x, (str,unicode)) and 'articlecommentcountholder' in x.split(' '))}),
'toolsBottom'] }, dict(name='ul', attrs={'class':(lambda x: isinstance(x, (str,unicode)) and 'articletoolbar' in x.split(' '))}),
{'class':['credit','inline-img-caption','tab-pointer'] }, ]
dict(name='div', attrs={'id':['lead-photo', 'most-popular-story']}),
dict(name='div', attrs={'class':'right'}),
dict(name='div', attrs={'id':'footer'}),
dict(name='div', attrs={'id':'beta-msg'}),
dict(name='img', attrs={'class':'headshot'}),
dict(name='div', attrs={'class':'brand'}),
dict(name='div', attrs={'id':'nav-wrap'}),
dict(name='div', attrs={'id':'featureTopics'}),
dict(name='div', attrs={'id':'videoNav'}),
dict(name='div', attrs={'id':'blog-header'}),
dict(name='div', attrs={'id':'right-rail'}),
dict(name='div', attrs={'id':'group-footer-container'}),
dict(name=['iframe', 'style'])
]
remove_attributes = ['style']
remove_tags_after = [{'id':['article-content']},
{'class':['pull','inline-img'] },
dict(name='img', attrs={'class':'inline-media-embed'}),
]
feeds = [ feeds = [
(u'Latest headlines', u'http://www.theglobeandmail.com/?service=rss'), (u'Latest headlines', u'http://www.theglobeandmail.com/?service=rss'),
(u'Top stories', u'http://www.theglobeandmail.com/?service=rss&feed=topstories'), (u'Top stories', u'http://www.theglobeandmail.com/?service=rss&feed=topstories'),

View File

@ -0,0 +1,37 @@
__license__ = 'GPL v3'
__copyright__ = '2010, Darko Miletic <darko.miletic at gmail.com>'
'''
orsai.bitacoras.com
'''
from calibre.web.feeds.news import BasicNewsRecipe
class Orsai(BasicNewsRecipe):
title = 'Orsai'
__author__ = 'Darko Miletic'
language = 'es'
oldest_article = 35
max_articles_per_feed = 100
encoding = 'utf-8'
no_stylesheets = True
use_embedded_content = False
publication_type = 'blog'
masthead_url = 'http://orsai.bitacoras.com/wp-content/themes/orsai/images/logo_orsai.png'
conversion_options = {
'comment' : 'Blog literario de Hernán Casciari'
, 'tags' : 'blog, Argentina, España, literatura, Casciari'
, 'publisher': 'Editorial Orsai S.L.'
, 'language' : 'es'
}
keep_only_tags=[dict(attrs={'class':['entry-title','entry-meta','entry-content','commentlist']})]
remove_tags=[dict(name='img',attrs={'class':'avatar avatar-40 photo'})]
feeds = [(u'Articulos', u'http://orsai.bitacoras.com/feed')]
def preprocess_html(self, soup):
for item in soup.findAll(style=True):
del item['style']
return self.adeify_images(soup)

View File

@ -11,6 +11,7 @@ __docformat__ = 'restructuredtext en'
on 10/10/10 to include function to grab print version of articles on 10/10/10 to include function to grab print version of articles
''' '''
from datetime import date
from calibre.web.feeds.news import BasicNewsRecipe from calibre.web.feeds.news import BasicNewsRecipe
''' '''
added by Tony Stegall added by Tony Stegall
@ -27,7 +28,6 @@ class AdvancedUserRecipe1249039563(BasicNewsRecipe):
no_stylesheets = True no_stylesheets = True
language = 'nl' language = 'nl'
extra_css = ''' extra_css = '''
body{font-family:Arial,Helvetica,sans-serif; font-size:small;} body{font-family:Arial,Helvetica,sans-serif; font-size:small;}
h1{font-size:large;} h1{font-size:large;}
@ -43,14 +43,16 @@ class AdvancedUserRecipe1249039563(BasicNewsRecipe):
def get_obfuscated_article(self, url): def get_obfuscated_article(self, url):
br = self.get_browser() br = self.get_browser()
print 'THE CURRENT URL IS: ', url
br.open(url) br.open(url)
year = date.today().year
try: try:
response = br.follow_link(url_regex='.*?(2010)(\\/)(article)(\\/)(print)(\\/)', nr = 0) response = br.follow_link(url_regex='.*?(%d)(\\/)(article)(\\/)(print)(\\/)'%year, nr = 0)
html = response.read() html = response.read()
except: except:
response = br.open(url) response = br.open(url)
html = response.read() html = response.read()
self.temp_files.append(PersistentTemporaryFile('_fa.html')) self.temp_files.append(PersistentTemporaryFile('_fa.html'))
self.temp_files[-1].write(html) self.temp_files[-1].write(html)
@ -59,19 +61,22 @@ class AdvancedUserRecipe1249039563(BasicNewsRecipe):
############################################################################################################### ###############################################################################################################
feeds = [ '''
(u'Laatste Nieuws', u'http://volkskrant.nl/rss/laatstenieuws.rss'), Change Log:
(u'Binnenlands nieuws', u'http://volkskrant.nl/rss/nederland.rss'), Date: 10/15/2010
(u'Buitenlands nieuws', u'http://volkskrant.nl/rss/internationaal.rss'), Feeds updated by Martin Tarenskeen
(u'Economisch nieuws', u'http://volkskrant.nl/rss/economie.rss'), '''
(u'Sportnieuws', u'http://volkskrant.nl/rss/sport.rss'),
(u'Kunstnieuws', u'http://volkskrant.nl/rss/kunst.rss'), feeds = [
(u'Laatste Nieuws', u'http://www.volkskrant.nl/rss/laatstenieuws.rss'),
(u'Binnenland', u'http://www.volkskrant.nl/rss/nederland.rss'),
(u'Buitenland', u'http://www.volkskrant.nl/rss/internationaal.rss'),
(u'Economie', u'http://www.volkskrant.nl/rss/economie.rss'),
(u'Sport', u'http://www.volkskrant.nl/rss/sport.rss'),
(u'Cultuur', u'http://www.volkskrant.nl/rss/kunst.rss'),
(u'Gezondheid & Wetenschap', u'http://www.volkskrant.nl/rss/wetenschap.rss'),
(u'Internet & Media', u'http://www.volkskrant.nl/rss/media.rss') ]
#both of these rss feeds link back to the main volksrant.nl url a.k.a Broken
#If someone happens to know the correct paths then they can put them in here
#(u'Wetenschapsnieuws', u'http://feeds.feedburner.com/DeVolkskrantWetenschap'),
#(u'Technologienieuws', u'http://feeds.feedburner.com/vkmedia')
]
''' '''
example for formating example for formating

View File

@ -25,7 +25,7 @@ from calibre.ebooks.metadata.covers import download_cover
from calibre.ebooks.metadata.meta import get_metadata from calibre.ebooks.metadata.meta import get_metadata
from calibre.ebooks.metadata import MetaInformation from calibre.ebooks.metadata import MetaInformation
from calibre.utils.config import prefs, tweaks from calibre.utils.config import prefs, tweaks
from calibre.utils.date import qt_to_dt, local_tz, utcfromtimestamp, utc_tz from calibre.utils.date import qt_to_dt, local_tz, utcfromtimestamp
from calibre.customize.ui import run_plugins_on_import, get_isbndb_key from calibre.customize.ui import run_plugins_on_import, get_isbndb_key
from calibre.gui2.preferences.social import SocialMetadata from calibre.gui2.preferences.social import SocialMetadata
from calibre.gui2.custom_column_widgets import populate_metadata_page from calibre.gui2.custom_column_widgets import populate_metadata_page

View File

@ -42,6 +42,8 @@ def comments_to_html(comments):
Deprecated HTML returns as HTML via BeautifulSoup() Deprecated HTML returns as HTML via BeautifulSoup()
''' '''
if not comments:
return u'<p></p>'
if not isinstance(comments, unicode): if not isinstance(comments, unicode):
comments = comments.decode(preferred_encoding, 'replace') comments = comments.decode(preferred_encoding, 'replace')

View File

@ -161,7 +161,7 @@ class FieldMetadata(dict):
'datatype':'text', 'datatype':'text',
'is_multiple':None, 'is_multiple':None,
'kind':'field', 'kind':'field',
'name':None, 'name':_('Comments'),
'search_terms':['comments', 'comment'], 'search_terms':['comments', 'comment'],
'is_custom':False, 'is_category':False}), 'is_custom':False, 'is_category':False}),
('cover', {'table':None, ('cover', {'table':None,

View File

@ -7,71 +7,78 @@ __docformat__ = 'restructuredtext en'
import operator, os, json import operator, os, json
from urllib import quote from urllib import quote
from binascii import hexlify from binascii import hexlify, unhexlify
import cherrypy import cherrypy
from calibre.constants import filesystem_encoding from calibre.constants import filesystem_encoding
from calibre import isbytestring, force_unicode, prepare_string_for_xml as xml from calibre import isbytestring, force_unicode, prepare_string_for_xml as xml
from calibre.utils.ordered_dict import OrderedDict from calibre.utils.ordered_dict import OrderedDict
from calibre.utils.filenames import ascii_filename
from calibre.utils.config import prefs
from calibre.library.comments import comments_to_html
def paginate(offsets, content, base_url, up_url=None): # {{{ def render_book_list(ids, suffix=''): # {{{
'Create markup for pagination' pages = []
num = len(ids)
if '?' not in base_url: pos = 0
base_url += '?' delta = 25
while ids:
if base_url[-1] != '?': page = list(ids[:delta])
base_url += '&' pages.append((page, pos))
ids = ids[delta:]
def navlink(decoration, name, cls, offset): pos += len(page)
label = xml(name) page_template = u'''\
if cls in ('next', 'last'): <div class="page" id="page{0}">
label += '&nbsp;' + decoration <div class="load_data" title="{1}">
else: <span class="url" title="/browse/booklist_page"></span>
label = decoration + '&nbsp;' + label <span class="start" title="{start}"></span>
return (u'<a class="{cls}" href="{base_url}&amp;offset={offset}" title={name}>' <span class="end" title="{end}"></span>
u'{label}</a>').format(cls=cls, decoration=decoration, </div>
name=xml(name, True), offset=offset, <div class="loading"><img src="/static/loading.gif" /> {2}</div>
base_url=xml(base_url, True), label=label) <div class="loaded"></div>
left = ''
if offsets.offset > 0 and offsets.previous_offset > 0:
left += navlink(u'\u219e', _('First'), 'first', 0)
if offsets.offset > 0:
left += ' ' + navlink('&larr;', _('Previous'), 'previous',
offsets.previous_offset)
middle = ''
if up_url:
middle = '<a href="{0}" title="{1}">[{1} &uarr;]</a>'.format(xml(up_url, True),
xml(_('Up')))
right = ''
if offsets.next_offset > -1:
right += navlink('&rarr', _('Next'), 'next', offsets.next_offset)
if offsets.last_offset > offsets.next_offset and offsets.last_offset > 0:
right += ' ' + navlink(u'\u21A0', _('Last'), 'last', offsets.last_offset)
navbar = u'''
<table class="navbar">
<tr>
<td class="left">{left}</td>
<td class="middle">{middle}</td>
<td class="right">{right}</td>
</tr>
<table>
'''.format(left=left, right=right, middle=middle)
templ = u'''
<div class="page">
{navbar}
<div class="page-contents">
{content}
</div> </div>
{navbar} '''
rpages = []
for i, x in enumerate(pages):
pg, pos = x
ld = xml(json.dumps(pg), True)
rpages.append(page_template.format(i, ld,
xml(_('Loading, please wait')) + '&hellip;',
start=pos+1, end=pos+len(pg)))
rpages = u'\n\n'.join(rpages)
templ = u'''\
<h3>{0} {suffix}</h3>
<div id="booklist">
<div class="listnav topnav">
{navbar}
</div>
{pages}
<div class="listnav bottomnav">
{navbar}
</div>
</div>
'''
navbar = u'''\
<div class="navleft">
<a href="#" onclick="first_page(); return false;">{first}</a>
<a href="#" onclick="previous_page(); return false;">{previous}</a>
</div> </div>
''' <div class="navmiddle">
return templ.format(navbar=navbar, content=content) <span class="start">0</span> to <span class="end">0</span> of {num}
</div>
<div class="navright">
<a href="#" onclick="next_page(); return false;">{next}</a>
<a href="#" onclick="last_page(); return false;">{last}</a>
</div>
'''.format(first=_('First'), last=_('Last'), previous=_('Previous'),
next=_('Next'), num=num)
return templ.format(_('Browsing %d books')%num, suffix=suffix,
pages=rpages, navbar=navbar)
# }}} # }}}
def utf8(x): # {{{ def utf8(x): # {{{
@ -80,11 +87,13 @@ def utf8(x): # {{{
return x return x
# }}} # }}}
def render_rating(rating, container='span'): # {{{ def render_rating(rating, container='span', prefix=None): # {{{
if rating < 0.1: if rating < 0.1:
return '', '' return '', ''
added = 0 added = 0
rstring = xml(_('Average rating: %.1f stars')% (rating if rating else 0.0), if prefix is None:
prefix = _('Average rating')
rstring = xml(_('%s: %.1f stars')% (prefix, rating if rating else 0.0),
True) True)
ans = ['<%s class="rating">' % (container)] ans = ['<%s class="rating">' % (container)]
for i in range(5): for i in range(5):
@ -120,7 +129,7 @@ def get_category_items(category, items, db, datatype): # {{{
id_ = xml(str(id_)) id_ = xml(str(id_))
desc = '' desc = ''
if i.count > 0: if i.count > 0:
desc += '[' + _('%d items')%i.count + ']' desc += '[' + _('%d books')%i.count + ']'
href = '/browse/matches/%s/%s'%(category, id_) href = '/browse/matches/%s/%s'%(category, id_)
return templ.format(xml(name), rating, return templ.format(xml(name), rating,
xml(desc), xml(quote(href)), rstring) xml(desc), xml(quote(href)), rstring)
@ -142,11 +151,12 @@ class Endpoint(object): # {{{
def __call__(eself, func): def __call__(eself, func):
def do(self, *args, **kwargs): def do(self, *args, **kwargs):
sort_val = None if 'json' not in eself.mimetype:
cookie = cherrypy.request.cookie sort_val = None
if cookie.has_key(eself.sort_cookie_name): cookie = cherrypy.request.cookie
sort_val = cookie[eself.sort_cookie_name].value if cookie.has_key(eself.sort_cookie_name):
kwargs[eself.sort_kwarg] = sort_val sort_val = cookie[eself.sort_cookie_name].value
kwargs[eself.sort_kwarg] = sort_val
ans = func(self, *args, **kwargs) ans = func(self, *args, **kwargs)
cherrypy.response.headers['Content-Type'] = eself.mimetype cherrypy.response.headers['Content-Type'] = eself.mimetype
@ -171,12 +181,19 @@ class BrowseServer(object):
connect('browse_category_group', connect('browse_category_group',
base_href+'/category_group/{category}/{group}', base_href+'/category_group/{category}/{group}',
self.browse_category_group) self.browse_category_group)
connect('browse_list', base_href+'/list/{query}', self.browse_list) connect('browse_matches',
connect('browse_search', base_href+'/search/{query}', base_href+'/matches/{category}/{cid}',
self.browse_matches)
connect('browse_booklist_page',
base_href+'/booklist_page',
self.browse_booklist_page)
connect('browse_search', base_href+'/search',
self.browse_search) self.browse_search)
connect('browse_book', base_href+'/book/{uuid}', self.browse_book) connect('browse_details', base_href+'/details/{id}',
self.browse_details)
def browse_template(self, sort, category=True): # Templates {{{
def browse_template(self, sort, category=True, initial_search=''):
def generate(): def generate():
scn = 'calibre_browse_server_sort_' scn = 'calibre_browse_server_sort_'
@ -202,7 +219,7 @@ class BrowseServer(object):
opts = ['<option %svalue="%s">%s</option>' % ( opts = ['<option %svalue="%s">%s</option>' % (
'selected="selected" ' if k==sort else '', 'selected="selected" ' if k==sort else '',
xml(k), xml(n), ) for k, n in xml(k), xml(n), ) for k, n in
sorted(sort_opts, key=operator.itemgetter(1))] sorted(sort_opts, key=operator.itemgetter(1)) if k and n]
ans = ans.replace('{sort_select_options}', ('\n'+' '*20).join(opts)) ans = ans.replace('{sort_select_options}', ('\n'+' '*20).join(opts))
lp = self.db.library_path lp = self.db.library_path
if isbytestring(lp): if isbytestring(lp):
@ -211,6 +228,7 @@ class BrowseServer(object):
ans = ans.encode('utf-8') ans = ans.encode('utf-8')
ans = ans.replace('{library_name}', xml(os.path.basename(lp))) ans = ans.replace('{library_name}', xml(os.path.basename(lp)))
ans = ans.replace('{library_path}', xml(lp, True)) ans = ans.replace('{library_path}', xml(lp, True))
ans = ans.replace('{initial_search}', initial_search)
return ans return ans
if self.opts.develop: if self.opts.develop:
@ -219,6 +237,23 @@ class BrowseServer(object):
self.__browse_template__ = generate() self.__browse_template__ = generate()
return self.__browse_template__ return self.__browse_template__
@property
def browse_summary_template(self):
if not hasattr(self, '__browse_summary_template__') or \
self.opts.develop:
self.__browse_summary_template__ = \
P('content_server/browse/summary.html', data=True).decode('utf-8')
return self.__browse_summary_template__
@property
def browse_details_template(self):
if not hasattr(self, '__browse_details_template__') or \
self.opts.develop:
self.__browse_details_template__ = \
P('content_server/browse/details.html', data=True).decode('utf-8')
return self.__browse_details_template__
# }}}
# Catalogs {{{ # Catalogs {{{
def browse_toplevel(self): def browse_toplevel(self):
@ -267,12 +302,12 @@ class BrowseServer(object):
def browse_category(self, category, sort): def browse_category(self, category, sort):
categories = self.categories_cache() categories = self.categories_cache()
if category not in categories:
raise cherrypy.HTTPError(404, 'category not found')
category_meta = self.db.field_metadata category_meta = self.db.field_metadata
category_name = category_meta[category]['name'] category_name = category_meta[category]['name']
datatype = category_meta[category]['datatype'] datatype = category_meta[category]['datatype']
if category not in categories:
raise cherrypy.HTTPError(404, 'category not found')
items = categories[category] items = categories[category]
sort = self.browse_sort_categories(items, sort) sort = self.browse_sort_categories(items, sort)
@ -325,17 +360,18 @@ class BrowseServer(object):
script=script, main=main) script=script, main=main)
@Endpoint(mimetype='application/json; charset=utf-8') @Endpoint(mimetype='application/json; charset=utf-8')
def browse_category_group(self, category=None, group=None, def browse_category_group(self, category=None, group=None, sort=None):
category_sort=None): if sort == 'null':
sort = category_sort sort = None
if sort not in ('rating', 'name', 'popularity'): if sort not in ('rating', 'name', 'popularity'):
sort = 'name' sort = 'name'
categories = self.categories_cache() categories = self.categories_cache()
if category not in categories:
raise cherrypy.HTTPError(404, 'category not found')
category_meta = self.db.field_metadata category_meta = self.db.field_metadata
datatype = category_meta[category]['datatype'] datatype = category_meta[category]['datatype']
if category not in categories:
raise cherrypy.HTTPError(404, 'category not found')
if not group: if not group:
raise cherrypy.HTTPError(404, 'invalid group') raise cherrypy.HTTPError(404, 'invalid group')
@ -354,12 +390,13 @@ class BrowseServer(object):
return json.dumps(entries, ensure_ascii=False) return json.dumps(entries, ensure_ascii=False)
@Endpoint() @Endpoint()
def browse_catalog(self, category=None, category_sort=None): def browse_catalog(self, category=None, category_sort=None):
'Entry point for top-level, categories and sub-categories' 'Entry point for top-level, categories and sub-categories'
if category == None: if category == None:
ans = self.browse_toplevel() ans = self.browse_toplevel()
elif category == 'newest':
raise cherrypy.InternalRedirect('/browse/matches/newest/dummy')
else: else:
ans = self.browse_category(category, category_sort) ans = self.browse_category(category, category_sort)
@ -368,18 +405,197 @@ class BrowseServer(object):
# }}} # }}}
# Book Lists {{{ # Book Lists {{{
def browse_list(self, query=None, offset=0, sort=None):
raise NotImplementedError() def browse_sort_book_list(self, items, sort):
fm = self.db.field_metadata
keys = frozenset(fm.sortable_field_keys())
if sort not in keys:
sort = 'title'
self.sort(items, 'title', True)
if sort != 'title':
ascending = fm[sort]['datatype'] not in ('rating', 'datetime')
self.sort(items, sort, ascending)
return sort
@Endpoint(sort_type='list')
def browse_matches(self, category=None, cid=None, list_sort=None):
if not cid:
raise cherrypy.HTTPError(404, 'invalid category id: %r'%cid)
categories = self.categories_cache()
if category not in categories and category != 'newest':
raise cherrypy.HTTPError(404, 'category not found')
try:
category_name = self.db.field_metadata[category]['name']
except:
if category != 'newest':
raise
category_name = _('Newest')
hide_sort = 'false'
if category == 'search':
which = unhexlify(cid)
try:
ids = self.search_cache('search:"%s"'%which)
except:
raise cherrypy.HTTPError(404, 'Search: %r not understood'%which)
elif category == 'newest':
ids = list(self.db.data.iterallids())
hide_sort = 'true'
else:
ids = self.db.get_books_for_category(category, cid)
items = [self.db.data._data[x] for x in ids]
if category == 'newest':
list_sort = 'timestamp'
sort = self.browse_sort_book_list(items, list_sort)
ids = [x[0] for x in items]
html = render_book_list(ids, suffix=_('in') + ' ' + category_name)
return self.browse_template(sort, category=False).format(
title=_('Books in') + " " +category_name,
script='booklist(%s);'%hide_sort, main=html)
def browse_get_book_args(self, mi, id_):
fmts = self.db.formats(id_, index_is_id=True)
if not fmts:
fmts = ''
fmts = [x.lower() for x in fmts.split(',') if x]
pf = prefs['output_format'].lower()
fmt = pf if pf in fmts else fmts[0]
args = {'id':id_, 'mi':mi,
}
for key in mi.all_field_keys():
val = mi.format_field(key)[1]
if not val:
val = ''
args[key] = xml(val, True)
fname = ascii_filename(args['title']) + ' - ' + ascii_filename(args['authors'])
return args, fmt, fmts, fname
@Endpoint(mimetype='application/json; charset=utf-8')
def browse_booklist_page(self, ids=None, sort=None):
if sort == 'null':
sort = None
if ids is None:
ids = json.dumps('[]')
try:
ids = json.loads(ids)
except:
raise cherrypy.HTTPError(404, 'invalid ids')
summs = []
for id_ in ids:
try:
id_ = int(id_)
mi = self.db.get_metadata(id_, index_is_id=True)
except:
continue
args, fmt, fmts, fname = self.browse_get_book_args(mi, id_)
args['other_formats'] = ''
other_fmts = [x for x in fmts if x.lower() != fmt.lower()]
if other_fmts:
ofmts = [u'<a href="/get/{0}/{1}_{2}.{0}" title="{3}">{3}</a>'\
.format(fmt, fname, id_, fmt.upper()) for fmt in
other_fmts]
ofmts = ', '.join(ofmts)
args['other_formats'] = u'<strong>%s: </strong>' % \
_('Other formats') + ofmts
args['details_href'] = '/browse/details/'+str(id_)
args['read_tooltip'] = \
_('Read %s in the %s format')%(args['title'], fmt.upper())
args['href'] = '/get/%s/%s_%d.%s'%(
fmt, fname, id_, fmt)
args['comments'] = comments_to_html(mi.comments)
args['stars'] = ''
if mi.rating:
args['stars'] = render_rating(mi.rating/2.0, prefix=_('Rating'))[0]
if args['tags']:
args['tags'] = u'<strong>%s: </strong>'%xml(_('Tags')) + \
args['tags']
if args['series']:
args['series'] = args['series']
args['read_string'] = xml(_('Read'), True)
args['details'] = xml(_('Details'), True)
args['details_tt'] = xml(_('Show book details'), True)
summs.append(self.browse_summary_template.format(**args))
return json.dumps('\n'.join(summs), ensure_ascii=False)
@Endpoint(mimetype='application/json; charset=utf-8')
def browse_details(self, id=None):
try:
id_ = int(id)
except:
raise cherrypy.HTTPError(404, 'invalid id: %r'%id)
try:
mi = self.db.get_metadata(id_, index_is_id=True)
except:
ans = _('This book has been deleted')
else:
args, fmt, fmts, fname = self.browse_get_book_args(mi, id_)
args['formats'] = ''
if fmts:
ofmts = [u'<a href="/get/{0}/{1}_{2}.{0}" title="{3}">{3}</a>'\
.format(fmt, fname, id_, fmt.upper()) for fmt in
fmts]
ofmts = ', '.join(ofmts)
args['formats'] = ofmts
fields, comments = [], []
for field, m in list(mi.get_all_standard_metadata(False).items()) + \
list(mi.get_all_user_metadata(False).items()):
if m['datatype'] == 'comments' or field == 'comments':
comments.append((m['name'], comments_to_html(mi.get(field,
''))))
continue
if field in ('title', 'formats') or not args.get(field, False) \
or not m['name']:
continue
if m['datatype'] == 'rating':
r = u'<strong>%s: </strong>'%xml(m['name']) + \
render_rating(mi.rating/2.0, prefix=m['name'])[0]
else:
r = u'<strong>%s: </strong>'%xml(m['name']) + \
args[field]
fields.append((m['name'], r))
fields.sort(key=lambda x: x[0].lower())
fields = [u'<div class="field">{0}</div>'.format(f[1]) for f in
fields]
fields = u'<div class="fields">%s</div>'%('\n\n'.join(fields))
comments.sort(key=lambda x: x[0].lower())
comments = [(u'<div class="field"><strong>%s: </strong>'
u'<div class="comment">%s</div></div>') % (xml(c[0]),
c[1]) for c in comments]
comments = u'<div class="comments">%s</div>'%('\n\n'.join(comments))
ans = self.browse_details_template.format(id=id_,
title=xml(mi.title, True), fields=fields,
formats=args['formats'], comments=comments)
return json.dumps(ans, ensure_ascii=False)
# }}} # }}}
# Search {{{ # Search {{{
def browse_search(self, query=None, offset=0, sort=None): @Endpoint(sort_type='list')
raise NotImplementedError() def browse_search(self, query='', list_sort=None):
# }}} if isbytestring(query):
query = query.decode('UTF-8')
ids = self.db.search_getting_ids(query.strip(), self.search_restriction)
items = [self.db.data._data[x] for x in ids]
sort = self.browse_sort_book_list(items, list_sort)
ids = [x[0] for x in items]
html = render_book_list(ids, suffix=_('in search')+': '+query)
return self.browse_template(sort, category=False, initial_search=query).format(
title=_('Matching books'),
script='booklist();', main=html)
# Book {{{
def browse_book(self, uuid=None):
raise NotImplementedError()
# }}} # }}}

View File

@ -5,18 +5,15 @@ __license__ = 'GPL v3'
__copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>' __copyright__ = '2010, Kovid Goyal <kovid@kovidgoyal.net>'
__docformat__ = 'restructuredtext en' __docformat__ = 'restructuredtext en'
import re, os, cStringIO import re, os
import cherrypy import cherrypy
try:
from PIL import Image as PILImage
PILImage
except ImportError:
import Image as PILImage
from calibre import fit_image, guess_type from calibre import fit_image, guess_type
from calibre.utils.date import fromtimestamp from calibre.utils.date import fromtimestamp
from calibre.library.caches import SortKeyGenerator from calibre.library.caches import SortKeyGenerator
from calibre.utils.magick.draw import save_cover_data_to, Image, \
thumbnail as generate_thumbnail
class CSSortKeyGenerator(SortKeyGenerator): class CSSortKeyGenerator(SortKeyGenerator):
@ -77,8 +74,13 @@ class ContentServer(object):
id = int(match.group()) id = int(match.group())
if not self.db.has_id(id): if not self.db.has_id(id):
raise cherrypy.HTTPError(400, 'id:%d does not exist in database'%id) raise cherrypy.HTTPError(400, 'id:%d does not exist in database'%id)
if what == 'thumb': if what == 'thumb' or what.startswith('thumb_'):
return self.get_cover(id, thumbnail=True) try:
width, height = map(int, what.split('_')[1:])
except:
width, height = 60, 80
return self.get_cover(id, thumbnail=True, thumb_width=width,
thumb_height=height)
if what == 'cover': if what == 'cover':
return self.get_cover(id) return self.get_cover(id)
return self.get_format(id, what) return self.get_format(id, what)
@ -128,37 +130,39 @@ class ContentServer(object):
return self.static('index.html') return self.static('index.html')
# Actually get content from the database {{{ # Actually get content from the database {{{
def get_cover(self, id, thumbnail=False): def get_cover(self, id, thumbnail=False, thumb_width=60, thumb_height=80):
cover = self.db.cover(id, index_is_id=True, as_file=False)
if cover is None:
cover = self.default_cover
cherrypy.response.headers['Content-Type'] = 'image/jpeg'
cherrypy.response.timeout = 3600
path = getattr(cover, 'name', False)
updated = fromtimestamp(os.stat(path).st_mtime) if path and \
os.access(path, os.R_OK) else self.build_time
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
try: try:
f = cStringIO.StringIO(cover) cherrypy.response.headers['Content-Type'] = 'image/jpeg'
try: cherrypy.response.timeout = 3600
im = PILImage.open(f) cover = self.db.cover(id, index_is_id=True, as_file=True)
except IOError: if cover is None:
raise cherrypy.HTTPError(404, 'No valid cover found') cover = self.default_cover
width, height = im.size updated = self.build_time
else:
with cover as f:
updated = fromtimestamp(os.stat(f.name).st_mtime)
cover = f.read()
cherrypy.response.headers['Last-Modified'] = self.last_modified(updated)
if thumbnail:
return generate_thumbnail(cover,
width=thumb_width, height=thumb_height)[-1]
img = Image()
img.load(cover)
width, height = img.size
scaled, width, height = fit_image(width, height, scaled, width, height = fit_image(width, height,
60 if thumbnail else self.max_cover_width, thumb_width if thumbnail else self.max_cover_width,
80 if thumbnail else self.max_cover_height) thumb_height if thumbnail else self.max_cover_height)
if not scaled: if not scaled:
return cover return cover
im = im.resize((int(width), int(height)), PILImage.ANTIALIAS) return save_cover_data_to(img, 'img.jpg', return_data=True,
of = cStringIO.StringIO() resize_to=(width, height))
im.convert('RGB').save(of, 'JPEG')
return of.getvalue()
except Exception, err: except Exception, err:
import traceback import traceback
cherrypy.log.error('Failed to generate cover:') cherrypy.log.error('Failed to generate cover:')
cherrypy.log.error(traceback.print_exc()) cherrypy.log.error(traceback.print_exc())
raise cherrypy.HTTPError(404, 'Failed to generate cover: %s'%err) raise cherrypy.HTTPError(404, 'Failed to generate cover: %r'%err)
def get_format(self, id, format): def get_format(self, id, format):
format = format.upper() format = format.upper()

View File

@ -17,7 +17,7 @@ from calibre.library.server import custom_fields_to_display
from calibre.library.server.utils import strftime, format_tag_string from calibre.library.server.utils import strftime, format_tag_string
from calibre.ebooks.metadata import fmt_sidx from calibre.ebooks.metadata import fmt_sidx
from calibre.constants import __appname__ from calibre.constants import __appname__
from calibre import human_readable from calibre import human_readable, isbytestring
from calibre.utils.date import utcfromtimestamp from calibre.utils.date import utcfromtimestamp
from calibre.utils.filenames import ascii_filename from calibre.utils.filenames import ascii_filename
@ -29,6 +29,8 @@ def CLASS(*args, **kwargs): # class is a reserved word in Python
def build_search_box(num, search, sort, order): # {{{ def build_search_box(num, search, sort, order): # {{{
div = DIV(id='search_box') div = DIV(id='search_box')
form = FORM('Show ', method='get', action='mobile') form = FORM('Show ', method='get', action='mobile')
form.set('accept-charset', 'UTF-8')
div.append(form) div.append(form)
num_select = SELECT(name='num') num_select = SELECT(name='num')
@ -193,6 +195,8 @@ class MobileServer(object):
raise cherrypy.HTTPError(400, 'num: %s is not an integer'%num) raise cherrypy.HTTPError(400, 'num: %s is not an integer'%num)
if not search: if not search:
search = '' search = ''
if isbytestring(search):
search = search.decode('UTF-8')
ids = self.db.search_getting_ids(search.strip(), self.search_restriction) ids = self.db.search_getting_ids(search.strip(), self.search_restriction)
FM = self.db.FIELD_MAP FM = self.db.FIELD_MAP
items = [r for r in iter(self.db) if r[FM['id']] in ids] items = [r for r in iter(self.db) if r[FM['id']] in ids]

View File

@ -49,6 +49,8 @@ class XMLServer(object):
if not search: if not search:
search = '' search = ''
if isbytestring(search):
search = search.decode('UTF-8')
ids = self.db.search_getting_ids(search.strip(), self.search_restriction) ids = self.db.search_getting_ids(search.strip(), self.search_restriction)

View File

@ -387,6 +387,12 @@ solve it, look for a corrupted font file on your system, in ~/Library/Fonts or t
check for corrupted fonts in OS X is to start the "Font Book" application, select all fonts and then in the File check for corrupted fonts in OS X is to start the "Font Book" application, select all fonts and then in the File
menu, choose "Validate fonts". menu, choose "Validate fonts".
I downloaded the installer, but it is not working?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Downloading from the internet can sometimes result in a corrupted download. If the |app| installer you downloaded is not opening, try downloading it again. If re-downloading it does not work, download it from `an alternate location <http://sourceforge.net/projects/calibre/files/>`_. If the installer still doesn't work, then something on your computer is preventing it from running. Best place to ask for more help is in the `forums <http://www.mobileread.com/forums/usercp.php>`_.
My antivirus program claims |app| is a virus/trojan? My antivirus program claims |app| is a virus/trojan?
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View File

@ -295,6 +295,9 @@ To learn more about writing advanced recipes using some of the facilities, avail
`Built-in recipes <http://bazaar.launchpad.net/~kovid/calibre/trunk/files/head:/src/calibre/web/feeds/recipes/>`_ `Built-in recipes <http://bazaar.launchpad.net/~kovid/calibre/trunk/files/head:/src/calibre/web/feeds/recipes/>`_
The source code for the built-in recipes that come with |app| The source code for the built-in recipes that come with |app|
`The calibre recipes forum <http://www.mobileread.com/forums/forumdisplay.php?f=228>`_
Lots of knowledgeable |app| recipe writers hang out here.
API documentation API documentation
-------------------- --------------------

View File

@ -25,6 +25,7 @@ def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None,
resize and the input and output image formats are the same, no changes are resize and the input and output image formats are the same, no changes are
made. made.
:param data: Image data as bytestring or Image object
:param compression_quality: The quality of the image after compression. :param compression_quality: The quality of the image after compression.
Number between 1 and 100. 1 means highest compression, 100 means no Number between 1 and 100. 1 means highest compression, 100 means no
compression (lossless). compression (lossless).
@ -33,8 +34,11 @@ def save_cover_data_to(data, path, bgcolor='#ffffff', resize_to=None,
''' '''
changed = False changed = False
img = Image() if isinstance(data, Image):
img.load(data) img = data
else:
img = Image()
img.load(data)
orig_fmt = normalize_format_name(img.format) orig_fmt = normalize_format_name(img.format)
fmt = os.path.splitext(path)[1] fmt = os.path.splitext(path)[1]
fmt = normalize_format_name(fmt[1:]) fmt = normalize_format_name(fmt[1:])